Merge remote-tracking branch 'kwolf/for-anthony' into staging
diff --git a/Makefile.target b/Makefile.target
index e280bf6..07af4d4 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -387,9 +387,11 @@
 endif # CONFIG_SOFTMMU
 
 ifndef CONFIG_LINUX_USER
+ifndef CONFIG_BSD_USER
 # libcacard needs qemu-thread support, and besides is only needed by devices
-# so not requires with linux-user targets
+# so not requires with linux-user / bsd-user targets
 obj-$(CONFIG_SMARTCARD_NSS) += $(addprefix ../libcacard/, $(libcacard-y))
+endif # CONFIG_BSD_USER
 endif # CONFIG_LINUX_USER
 
 obj-y += $(addprefix ../, $(trace-obj-y))
diff --git a/arm.ld b/arm.ld
index 12b3edb..7f13da9 100644
--- a/arm.ld
+++ b/arm.ld
@@ -71,23 +71,23 @@
   .data1   : { *(.data1) }
   .preinit_array     :
   {
-    PROVIDE_HIDDEN (__preinit_array_start = .);
+    PROVIDE (__preinit_array_start = .);
     KEEP (*(.preinit_array))
-    PROVIDE_HIDDEN (__preinit_array_end = .);
+    PROVIDE (__preinit_array_end = .);
   }
   .init_array     :
   {
-     PROVIDE_HIDDEN (__init_array_start = .);
+     PROVIDE (__init_array_start = .);
      KEEP (*(SORT(.init_array.*)))
      KEEP (*(.init_array))
-     PROVIDE_HIDDEN (__init_array_end = .);
+     PROVIDE (__init_array_end = .);
   }
   .fini_array     :
   {
-    PROVIDE_HIDDEN (__fini_array_start = .);
+    PROVIDE (__fini_array_start = .);
     KEEP (*(.fini_array))
     KEEP (*(SORT(.fini_array.*)))
-    PROVIDE_HIDDEN (__fini_array_end = .);
+    PROVIDE (__fini_array_end = .);
   }
   .ctors         :
   {
diff --git a/cutils.c b/cutils.c
index f2bcf20..c91f887 100644
--- a/cutils.c
+++ b/cutils.c
@@ -408,7 +408,7 @@
 
 int64_t strtosz_suffix(const char *nptr, char **end, const char default_suffix)
 {
-        return strtosz_suffix_unit(nptr, end, default_suffix, 1024);
+    return strtosz_suffix_unit(nptr, end, default_suffix, 1024);
 }
 
 int64_t strtosz(const char *nptr, char **end)
diff --git a/disas.c b/disas.c
index 1334b8e..611b30b 100644
--- a/disas.c
+++ b/disas.c
@@ -137,7 +137,7 @@
 
 /* Disassemble this for me please... (debugging). 'flags' has the following
    values:
-    i386 - nonzero means 16 bit code
+    i386 - 1 means 16 bit code, 2 means 64 bit code
     arm  - nonzero means thumb code
     ppc  - nonzero means little endian
     other targets - unused
diff --git a/dyngen-exec.h b/dyngen-exec.h
index cc1e4fb..8beb7f3 100644
--- a/dyngen-exec.h
+++ b/dyngen-exec.h
@@ -19,15 +19,6 @@
 #if !defined(__DYNGEN_EXEC_H__)
 #define __DYNGEN_EXEC_H__
 
-#include "qemu-common.h"
-
-#ifdef __OpenBSD__
-#include <sys/types.h>
-#endif
-
-/* XXX: This may be wrong for 64-bit ILP32 hosts.  */
-typedef void * host_reg_t;
-
 #if defined(__i386__)
 #define AREG0 "ebp"
 #elif defined(__x86_64__)
@@ -66,11 +57,6 @@
 
 register CPUState *env asm(AREG0);
 
-#define xglue(x, y) x ## y
-#define glue(x, y) xglue(x, y)
-#define stringify(s)	tostring(s)
-#define tostring(s)	#s
-
 /* The return address may point to the start of the next instruction.
    Subtracting one gets us the call instruction itself.  */
 #if defined(__s390__) && !defined(__s390x__)
diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h
index af9daf7..1eda342 100644
--- a/fsdev/file-op-9p.h
+++ b/fsdev/file-op-9p.h
@@ -78,7 +78,7 @@
     int (*open2)(FsContext *, const char *, int, FsCred *);
     void (*rewinddir)(FsContext *, DIR *);
     off_t (*telldir)(FsContext *, DIR *);
-    struct dirent *(*readdir)(FsContext *, DIR *);
+    int (*readdir_r)(FsContext *, DIR *, struct dirent *, struct dirent **);
     void (*seekdir)(FsContext *, DIR *, off_t);
     ssize_t (*preadv)(FsContext *, int, const struct iovec *, int, off_t);
     ssize_t (*pwritev)(FsContext *, int, const struct iovec *, int, off_t);
diff --git a/hppa.ld b/hppa.ld
index 9a4b22c..3555b3e 100644
--- a/hppa.ld
+++ b/hppa.ld
@@ -75,36 +75,34 @@
   .sbss2          : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
   .PARISC.unwind   : { *(.PARISC.unwind) }
   .eh_frame_hdr : { *(.eh_frame_hdr) }
-  .eh_frame       : ONLY_IF_RO { KEEP (*(.eh_frame)) }
-  .gcc_except_table   : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
   /* Adjust the address for the data segment.  We want to adjust up to
      the same address within the page on the next page up.  */
   . = ALIGN(0x10000) + (. & (0x10000 - 1));
   /* Exception handling  */
-  .eh_frame       : ONLY_IF_RW { KEEP (*(.eh_frame)) }
-  .gcc_except_table   : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
+  .eh_frame       : { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : { *(.gcc_except_table .gcc_except_table.*) }
   /* Thread Local Storage sections  */
   .tdata	  : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
   .tbss		  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
   .preinit_array     :
   {
-    PROVIDE_HIDDEN (__preinit_array_start = .);
+    PROVIDE (__preinit_array_start = .);
     KEEP (*(.preinit_array))
-    PROVIDE_HIDDEN (__preinit_array_end = .);
+    PROVIDE (__preinit_array_end = .);
   }
   .init_array     :
   {
-     PROVIDE_HIDDEN (__init_array_start = .);
+     PROVIDE (__init_array_start = .);
      KEEP (*(SORT(.init_array.*)))
      KEEP (*(.init_array))
-     PROVIDE_HIDDEN (__init_array_end = .);
+     PROVIDE (__init_array_end = .);
   }
   .fini_array     :
   {
-    PROVIDE_HIDDEN (__fini_array_start = .);
+    PROVIDE (__fini_array_start = .);
     KEEP (*(.fini_array))
     KEEP (*(SORT(.fini_array.*)))
-    PROVIDE_HIDDEN (__fini_array_end = .);
+    PROVIDE (__fini_array_end = .);
   }
   .ctors          :
   {
diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c
index 28f2ad7..3a257b9 100644
--- a/hw/9pfs/codir.c
+++ b/hw/9pfs/codir.c
@@ -17,16 +17,16 @@
 #include "qemu-coroutine.h"
 #include "virtio-9p-coth.h"
 
-int v9fs_co_readdir(V9fsState *s, V9fsFidState *fidp, struct dirent **dent)
+int v9fs_co_readdir_r(V9fsState *s, V9fsFidState *fidp, struct dirent *dent,
+                      struct dirent **result)
 {
     int err;
 
     v9fs_co_run_in_worker(
         {
             errno = 0;
-            /*FIXME!! need to switch to readdir_r */
-            *dent = s->ops->readdir(&s->ctx, fidp->fs.dir);
-            if (!*dent && errno) {
+            err = s->ops->readdir_r(&s->ctx, fidp->fs.dir, dent, result);
+            if (!*result && errno) {
                 err = -errno;
             } else {
                 err = 0;
@@ -83,3 +83,35 @@
         });
     return err;
 }
+
+int v9fs_co_opendir(V9fsState *s, V9fsFidState *fidp)
+{
+    int err;
+
+    v9fs_co_run_in_worker(
+        {
+            fidp->fs.dir = s->ops->opendir(&s->ctx, fidp->path.data);
+            if (!fidp->fs.dir) {
+                err = -errno;
+            } else {
+                err = 0;
+            }
+        });
+    return err;
+}
+
+int v9fs_co_closedir(V9fsState *s, V9fsFidState *fidp)
+{
+    int err;
+    DIR *dir;
+
+    dir = fidp->fs.dir;
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->closedir(&s->ctx, dir);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    return err;
+}
diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c
index a4c0ae7..e388146 100644
--- a/hw/9pfs/cofile.c
+++ b/hw/9pfs/cofile.c
@@ -30,3 +30,134 @@
         });
     return err;
 }
+
+int v9fs_co_fstat(V9fsState *s, int fd, struct stat *stbuf)
+{
+    int err;
+
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->fstat(&s->ctx, fd, stbuf);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    return err;
+}
+
+int v9fs_co_open(V9fsState *s, V9fsFidState *fidp, int flags)
+{
+    int err;
+
+    v9fs_co_run_in_worker(
+        {
+            fidp->fs.fd = s->ops->open(&s->ctx, fidp->path.data, flags);
+            if (fidp->fs.fd == -1) {
+                err = -errno;
+            } else {
+                err = 0;
+            }
+        });
+    return err;
+}
+
+int v9fs_co_open2(V9fsState *s, V9fsFidState *fidp, char *fullname, gid_t gid,
+                  int flags, int mode)
+{
+    int err;
+    FsCred cred;
+
+    cred_init(&cred);
+    cred.fc_mode = mode & 07777;
+    cred.fc_uid = fidp->uid;
+    cred.fc_gid = gid;
+    v9fs_co_run_in_worker(
+        {
+            fidp->fs.fd = s->ops->open2(&s->ctx, fullname, flags, &cred);
+            err = 0;
+            if (fidp->fs.fd == -1) {
+                err = -errno;
+            }
+        });
+    return err;
+}
+
+int v9fs_co_close(V9fsState *s, V9fsFidState *fidp)
+{
+    int fd;
+    int err;
+
+    fd = fidp->fs.fd;
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->close(&s->ctx, fd);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    return err;
+}
+
+int v9fs_co_fsync(V9fsState *s, V9fsFidState *fidp, int datasync)
+{
+    int fd;
+    int err;
+
+    fd = fidp->fs.fd;
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->fsync(&s->ctx, fd, datasync);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    return err;
+}
+
+int v9fs_co_link(V9fsState *s, V9fsString *oldpath, V9fsString *newpath)
+{
+    int err;
+
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->link(&s->ctx, oldpath->data, newpath->data);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    return err;
+}
+
+int v9fs_co_pwritev(V9fsState *s, V9fsFidState *fidp,
+                    struct iovec *iov, int iovcnt, int64_t offset)
+{
+    int fd;
+    int err;
+
+    fd = fidp->fs.fd;
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->pwritev(&s->ctx, fd, iov, iovcnt, offset);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    return err;
+}
+
+int v9fs_co_preadv(V9fsState *s, V9fsFidState *fidp,
+                   struct iovec *iov, int iovcnt, int64_t offset)
+{
+    int fd;
+    int err;
+
+    fd = fidp->fs.fd;
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->preadv(&s->ctx, fd, iov, iovcnt, offset);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    return err;
+}
diff --git a/hw/9pfs/cofs.c b/hw/9pfs/cofs.c
index 1f10632..a78fccb 100644
--- a/hw/9pfs/cofs.c
+++ b/hw/9pfs/cofs.c
@@ -169,3 +169,23 @@
         });
     return err;
 }
+
+int v9fs_co_symlink(V9fsState *s, V9fsFidState *fidp,
+                    const char *oldpath, const char *newpath, gid_t gid)
+{
+    int err;
+    FsCred cred;
+
+    cred_init(&cred);
+    cred.fc_uid = fidp->uid;
+    cred.fc_gid = gid;
+    cred.fc_mode = 0777;
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->symlink(&s->ctx, oldpath, newpath, &cred);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    return err;
+}
diff --git a/hw/9pfs/coxattr.c b/hw/9pfs/coxattr.c
index 2fba2c9..a289389 100644
--- a/hw/9pfs/coxattr.c
+++ b/hw/9pfs/coxattr.c
@@ -48,3 +48,37 @@
         });
     return err;
 }
+
+int v9fs_co_lsetxattr(V9fsState *s, V9fsString *path,
+                      V9fsString *xattr_name, void *value,
+                      size_t size, int flags)
+{
+    int err;
+
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->lsetxattr(&s->ctx, path->data,
+                                    xattr_name->data, value,
+                                    size, flags);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    return err;
+}
+
+int v9fs_co_lremovexattr(V9fsState *s, V9fsString *path,
+                         V9fsString *xattr_name)
+{
+    int err;
+
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->lremovexattr(&s->ctx, path->data,
+                                       xattr_name->data);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    return err;
+}
diff --git a/hw/9pfs/virtio-9p-coth.h b/hw/9pfs/virtio-9p-coth.h
index 11272d3..48defb7 100644
--- a/hw/9pfs/virtio-9p-coth.h
+++ b/hw/9pfs/virtio-9p-coth.h
@@ -57,8 +57,8 @@
 extern void co_run_in_worker_bh(void *);
 extern int v9fs_init_worker_threads(void);
 extern int v9fs_co_readlink(V9fsState *, V9fsString *, V9fsString *);
-extern int v9fs_co_readdir(V9fsState *, V9fsFidState *,
-                           struct dirent **);
+extern int v9fs_co_readdir_r(V9fsState *, V9fsFidState *,
+                           struct dirent *, struct dirent **result);
 extern off_t v9fs_co_telldir(V9fsState *, V9fsFidState *);
 extern void v9fs_co_seekdir(V9fsState *, V9fsFidState *, off_t);
 extern void v9fs_co_rewinddir(V9fsState *, V9fsFidState *);
@@ -76,4 +76,21 @@
 extern int v9fs_co_mkdir(V9fsState *, char *, mode_t, uid_t, gid_t);
 extern int v9fs_co_remove(V9fsState *, V9fsString *);
 extern int v9fs_co_rename(V9fsState *, V9fsString *, V9fsString *);
+extern int v9fs_co_fstat(V9fsState *, int, struct stat *);
+extern int v9fs_co_opendir(V9fsState *, V9fsFidState *);
+extern int v9fs_co_open(V9fsState *, V9fsFidState *, int);
+extern int v9fs_co_open2(V9fsState *, V9fsFidState *, char *, gid_t, int, int);
+extern int v9fs_co_lsetxattr(V9fsState *, V9fsString *, V9fsString *,
+                             void *, size_t, int);
+extern int v9fs_co_lremovexattr(V9fsState *, V9fsString *, V9fsString *);
+extern int v9fs_co_closedir(V9fsState *, V9fsFidState *);
+extern int v9fs_co_close(V9fsState *, V9fsFidState *);
+extern int v9fs_co_fsync(V9fsState *, V9fsFidState *, int);
+extern int v9fs_co_symlink(V9fsState *, V9fsFidState *, const char *,
+                           const char *, gid_t);
+extern int v9fs_co_link(V9fsState *, V9fsString *, V9fsString *);
+extern int v9fs_co_pwritev(V9fsState *, V9fsFidState *,
+                           struct iovec *, int, int64_t);
+extern int v9fs_co_preadv(V9fsState *, V9fsFidState *,
+                          struct iovec *, int, int64_t);
 #endif
diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c
index 77904c3..61cbf8d 100644
--- a/hw/9pfs/virtio-9p-local.c
+++ b/hw/9pfs/virtio-9p-local.c
@@ -165,9 +165,10 @@
     return telldir(dir);
 }
 
-static struct dirent *local_readdir(FsContext *ctx, DIR *dir)
+static int local_readdir_r(FsContext *ctx, DIR *dir, struct dirent *entry,
+                         struct dirent **result)
 {
-    return readdir(dir);
+    return readdir_r(dir, entry, result);
 }
 
 static void local_seekdir(FsContext *ctx, DIR *dir, off_t off)
@@ -532,7 +533,7 @@
     .opendir = local_opendir,
     .rewinddir = local_rewinddir,
     .telldir = local_telldir,
-    .readdir = local_readdir,
+    .readdir_r = local_readdir_r,
     .seekdir = local_seekdir,
     .preadv = local_preadv,
     .pwritev = local_pwritev,
diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index eb33636..ad70768 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -77,160 +77,6 @@
     credp->fc_rdev = -1;
 }
 
-static int v9fs_do_lstat(V9fsState *s, V9fsString *path, struct stat *stbuf)
-{
-    return s->ops->lstat(&s->ctx, path->data, stbuf);
-}
-
-static int v9fs_do_close(V9fsState *s, int fd)
-{
-    return s->ops->close(&s->ctx, fd);
-}
-
-static int v9fs_do_closedir(V9fsState *s, DIR *dir)
-{
-    return s->ops->closedir(&s->ctx, dir);
-}
-
-static int v9fs_do_open(V9fsState *s, V9fsString *path, int flags)
-{
-    return s->ops->open(&s->ctx, path->data, flags);
-}
-
-static DIR *v9fs_do_opendir(V9fsState *s, V9fsString *path)
-{
-    return s->ops->opendir(&s->ctx, path->data);
-}
-
-static void v9fs_do_rewinddir(V9fsState *s, DIR *dir)
-{
-    return s->ops->rewinddir(&s->ctx, dir);
-}
-
-static off_t v9fs_do_telldir(V9fsState *s, DIR *dir)
-{
-    return s->ops->telldir(&s->ctx, dir);
-}
-
-static void v9fs_do_seekdir(V9fsState *s, DIR *dir, off_t off)
-{
-    return s->ops->seekdir(&s->ctx, dir, off);
-}
-
-static int v9fs_do_preadv(V9fsState *s, int fd, const struct iovec *iov,
-                            int iovcnt, int64_t offset)
-{
-    return s->ops->preadv(&s->ctx, fd, iov, iovcnt, offset);
-}
-
-static int v9fs_do_pwritev(V9fsState *s, int fd, const struct iovec *iov,
-                       int iovcnt, int64_t offset)
-{
-    return s->ops->pwritev(&s->ctx, fd, iov, iovcnt, offset);
-}
-
-static int v9fs_do_chmod(V9fsState *s, V9fsString *path, mode_t mode)
-{
-    FsCred cred;
-    cred_init(&cred);
-    cred.fc_mode = mode;
-    return s->ops->chmod(&s->ctx, path->data, &cred);
-}
-
-static int v9fs_do_mknod(V9fsState *s, char *name,
-        mode_t mode, dev_t dev, uid_t uid, gid_t gid)
-{
-    FsCred cred;
-    cred_init(&cred);
-    cred.fc_uid = uid;
-    cred.fc_gid = gid;
-    cred.fc_mode = mode;
-    cred.fc_rdev = dev;
-    return s->ops->mknod(&s->ctx, name, &cred);
-}
-
-static int v9fs_do_fstat(V9fsState *s, int fd, struct stat *stbuf)
-{
-    return s->ops->fstat(&s->ctx, fd, stbuf);
-}
-
-static int v9fs_do_open2(V9fsState *s, char *fullname, uid_t uid, gid_t gid,
-        int flags, int mode)
-{
-    FsCred cred;
-
-    cred_init(&cred);
-    cred.fc_uid = uid;
-    cred.fc_gid = gid;
-    cred.fc_mode = mode & 07777;
-
-    return s->ops->open2(&s->ctx, fullname, flags, &cred);
-}
-
-static int v9fs_do_symlink(V9fsState *s, V9fsFidState *fidp,
-        const char *oldpath, const char *newpath, gid_t gid)
-{
-    FsCred cred;
-    cred_init(&cred);
-    cred.fc_uid = fidp->uid;
-    cred.fc_gid = gid;
-    cred.fc_mode = 0777;
-
-    return s->ops->symlink(&s->ctx, oldpath, newpath, &cred);
-}
-
-static int v9fs_do_link(V9fsState *s, V9fsString *oldpath, V9fsString *newpath)
-{
-    return s->ops->link(&s->ctx, oldpath->data, newpath->data);
-}
-
-static int v9fs_do_truncate(V9fsState *s, V9fsString *path, off_t size)
-{
-    return s->ops->truncate(&s->ctx, path->data, size);
-}
-
-static int v9fs_do_chown(V9fsState *s, V9fsString *path, uid_t uid, gid_t gid)
-{
-    FsCred cred;
-    cred_init(&cred);
-    cred.fc_uid = uid;
-    cred.fc_gid = gid;
-
-    return s->ops->chown(&s->ctx, path->data, &cred);
-}
-
-static int v9fs_do_utimensat(V9fsState *s, V9fsString *path,
-                                           const struct timespec times[2])
-{
-    return s->ops->utimensat(&s->ctx, path->data, times);
-}
-
-static int v9fs_do_fsync(V9fsState *s, int fd, int datasync)
-{
-    return s->ops->fsync(&s->ctx, fd, datasync);
-}
-
-static int v9fs_do_statfs(V9fsState *s, V9fsString *path, struct statfs *stbuf)
-{
-    return s->ops->statfs(&s->ctx, path->data, stbuf);
-}
-
-static int v9fs_do_lsetxattr(V9fsState *s, V9fsString *path,
-                             V9fsString *xattr_name,
-                             void *value, size_t size, int flags)
-{
-    return s->ops->lsetxattr(&s->ctx, path->data,
-                             xattr_name->data, value, size, flags);
-}
-
-static int v9fs_do_lremovexattr(V9fsState *s, V9fsString *path,
-                                V9fsString *xattr_name)
-{
-    return s->ops->lremovexattr(&s->ctx, path->data,
-                                xattr_name->data);
-}
-
-
 static void v9fs_string_init(V9fsString *str)
 {
     str->data = NULL;
@@ -437,12 +283,12 @@
         goto free_out;
     }
     if (fidp->fs.xattr.len) {
-        retval = v9fs_do_lsetxattr(s, &fidp->path, &fidp->fs.xattr.name,
+        retval = v9fs_co_lsetxattr(s, &fidp->path, &fidp->fs.xattr.name,
                                    fidp->fs.xattr.value,
                                    fidp->fs.xattr.len,
                                    fidp->fs.xattr.flags);
     } else {
-        retval = v9fs_do_lremovexattr(s, &fidp->path, &fidp->fs.xattr.name);
+        retval = v9fs_co_lremovexattr(s, &fidp->path, &fidp->fs.xattr.name);
     }
 free_out:
     v9fs_string_free(&fidp->fs.xattr.name);
@@ -472,15 +318,14 @@
     *fidpp = fidp->next;
 
     if (fidp->fid_type == P9_FID_FILE) {
-        v9fs_do_close(s, fidp->fs.fd);
+        retval = v9fs_co_close(s, fidp);
     } else if (fidp->fid_type == P9_FID_DIR) {
-        v9fs_do_closedir(s, fidp->fs.dir);
+        retval = v9fs_co_closedir(s, fidp);
     } else if (fidp->fid_type == P9_FID_XATTR) {
         retval = v9fs_xattr_fid_clunk(s, fidp);
     }
     v9fs_string_free(&fidp->path);
     g_free(fidp);
-
     return retval;
 }
 
@@ -531,11 +376,10 @@
     struct stat stbuf;
     int err;
 
-    err = v9fs_do_lstat(s, &fidp->path, &stbuf);
-    if (err) {
+    err = v9fs_co_lstat(s, &fidp->path, &stbuf);
+    if (err < 0) {
         return err;
     }
-
     stat_to_qid(&stbuf, qidp);
     return 0;
 }
@@ -1161,8 +1005,8 @@
     int32_t fid, afid, n_uname;
     V9fsString uname, aname;
     V9fsFidState *fidp;
-    V9fsQID qid;
     size_t offset = 7;
+    V9fsQID qid;
     ssize_t err;
 
     pdu_unmarshal(pdu, offset, "ddssd", &fid, &afid, &uname, &aname, &n_uname);
@@ -1172,19 +1016,15 @@
         err = -EINVAL;
         goto out;
     }
-
     fidp->uid = n_uname;
-
     v9fs_string_sprintf(&fidp->path, "%s", "/");
     err = fid_to_qid(s, fidp, &qid);
-    if (err) {
+    if (err < 0) {
         err = -EINVAL;
         free_fid(s, fid);
         goto out;
     }
-
     offset += pdu_marshal(pdu, offset, "Q", &qid);
-
     err = offset;
 out:
     complete_pdu(s, pdu, err);
@@ -1192,56 +1032,36 @@
     v9fs_string_free(&aname);
 }
 
-static void v9fs_stat_post_lstat(V9fsState *s, V9fsStatState *vs, int err)
-{
-    if (err == -1) {
-        err = -errno;
-        goto out;
-    }
-
-    err = stat_to_v9stat(s, &vs->fidp->path, &vs->stbuf, &vs->v9stat);
-    if (err) {
-        goto out;
-    }
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "wS", 0, &vs->v9stat);
-    err = vs->offset;
-
-out:
-    complete_pdu(s, vs->pdu, err);
-    v9fs_stat_free(&vs->v9stat);
-    g_free(vs);
-}
-
 static void v9fs_stat(void *opaque)
 {
+    int32_t fid;
+    V9fsStat v9stat;
+    ssize_t err = 0;
+    size_t offset = 7;
+    struct stat stbuf;
+    V9fsFidState *fidp;
     V9fsPDU *pdu = opaque;
     V9fsState *s = pdu->s;
-    int32_t fid;
-    V9fsStatState *vs;
-    ssize_t err = 0;
 
-    vs = g_malloc(sizeof(*vs));
-    vs->pdu = pdu;
-    vs->offset = 7;
-
-    memset(&vs->v9stat, 0, sizeof(vs->v9stat));
-
-    pdu_unmarshal(vs->pdu, vs->offset, "d", &fid);
-
-    vs->fidp = lookup_fid(s, fid);
-    if (vs->fidp == NULL) {
+    pdu_unmarshal(pdu, offset, "d", &fid);
+    fidp = lookup_fid(s, fid);
+    if (fidp == NULL) {
         err = -ENOENT;
         goto out;
     }
-
-    err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
-    v9fs_stat_post_lstat(s, vs, err);
-    return;
-
+    err = v9fs_co_lstat(s, &fidp->path, &stbuf);
+    if (err < 0) {
+        goto out;
+    }
+    err = stat_to_v9stat(s, &fidp->path, &stbuf, &v9stat);
+    if (err < 0) {
+        goto out;
+    }
+    offset += pdu_marshal(pdu, offset, "wS", 0, &v9stat);
+    err = offset;
+    v9fs_stat_free(&v9stat);
 out:
-    complete_pdu(s, vs->pdu, err);
-    v9fs_stat_free(&vs->v9stat);
-    g_free(vs);
+    complete_pdu(s, pdu, err);
 }
 
 static void v9fs_getattr(void *opaque)
@@ -1370,171 +1190,101 @@
     complete_pdu(s, pdu, err);
 }
 
-static void v9fs_walk_complete(V9fsState *s, V9fsWalkState *vs, int err)
-{
-    complete_pdu(s, vs->pdu, err);
-
-    if (vs->nwnames && vs->nwnames <= P9_MAXWELEM) {
-        for (vs->name_idx = 0; vs->name_idx < vs->nwnames; vs->name_idx++) {
-            v9fs_string_free(&vs->wnames[vs->name_idx]);
-        }
-
-        g_free(vs->wnames);
-        g_free(vs->qids);
-    }
-}
-
-static void v9fs_walk_marshal(V9fsWalkState *vs)
+static int v9fs_walk_marshal(V9fsPDU *pdu, uint16_t nwnames, V9fsQID *qids)
 {
     int i;
-    vs->offset = 7;
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "w", vs->nwnames);
-
-    for (i = 0; i < vs->nwnames; i++) {
-        vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qids[i]);
+    size_t offset = 7;
+    offset += pdu_marshal(pdu, offset, "w", nwnames);
+    for (i = 0; i < nwnames; i++) {
+        offset += pdu_marshal(pdu, offset, "Q", &qids[i]);
     }
-}
-
-static void v9fs_walk_post_newfid_lstat(V9fsState *s, V9fsWalkState *vs,
-                                                                int err)
-{
-    if (err == -1) {
-        free_fid(s, vs->newfidp->fid);
-        v9fs_string_free(&vs->path);
-        err = -ENOENT;
-        goto out;
-    }
-
-    stat_to_qid(&vs->stbuf, &vs->qids[vs->name_idx]);
-
-    vs->name_idx++;
-    if (vs->name_idx < vs->nwnames) {
-        v9fs_string_sprintf(&vs->path, "%s/%s", vs->newfidp->path.data,
-                                            vs->wnames[vs->name_idx].data);
-        v9fs_string_copy(&vs->newfidp->path, &vs->path);
-
-        err = v9fs_do_lstat(s, &vs->newfidp->path, &vs->stbuf);
-        v9fs_walk_post_newfid_lstat(s, vs, err);
-        return;
-    }
-
-    v9fs_string_free(&vs->path);
-    v9fs_walk_marshal(vs);
-    err = vs->offset;
-out:
-    v9fs_walk_complete(s, vs, err);
-}
-
-static void v9fs_walk_post_oldfid_lstat(V9fsState *s, V9fsWalkState *vs,
-        int err)
-{
-    if (err == -1) {
-        v9fs_string_free(&vs->path);
-        err = -ENOENT;
-        goto out;
-    }
-
-    stat_to_qid(&vs->stbuf, &vs->qids[vs->name_idx]);
-    vs->name_idx++;
-    if (vs->name_idx < vs->nwnames) {
-
-        v9fs_string_sprintf(&vs->path, "%s/%s",
-                vs->fidp->path.data, vs->wnames[vs->name_idx].data);
-        v9fs_string_copy(&vs->fidp->path, &vs->path);
-
-        err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
-        v9fs_walk_post_oldfid_lstat(s, vs, err);
-        return;
-    }
-
-    v9fs_string_free(&vs->path);
-    v9fs_walk_marshal(vs);
-    err = vs->offset;
-out:
-    v9fs_walk_complete(s, vs, err);
+    return offset;
 }
 
 static void v9fs_walk(void *opaque)
 {
+    int name_idx;
+    V9fsQID *qids = NULL;
+    int i, err = 0;
+    V9fsString path;
+    uint16_t nwnames;
+    struct stat stbuf;
+    size_t offset = 7;
+    int32_t fid, newfid;
+    V9fsString *wnames = NULL;
+    V9fsFidState *fidp;
+    V9fsFidState *newfidp;
     V9fsPDU *pdu = opaque;
     V9fsState *s = pdu->s;
-    int32_t fid, newfid;
-    V9fsWalkState *vs;
-    int err = 0;
-    int i;
 
-    vs = g_malloc(sizeof(*vs));
-    vs->pdu = pdu;
-    vs->wnames = NULL;
-    vs->qids = NULL;
-    vs->offset = 7;
+    offset += pdu_unmarshal(pdu, offset, "ddw", &fid,
+                            &newfid, &nwnames);
 
-    vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "ddw", &fid,
-                                            &newfid, &vs->nwnames);
-
-    if (vs->nwnames && vs->nwnames <= P9_MAXWELEM) {
-        vs->wnames = g_malloc0(sizeof(vs->wnames[0]) * vs->nwnames);
-
-        vs->qids = g_malloc0(sizeof(vs->qids[0]) * vs->nwnames);
-
-        for (i = 0; i < vs->nwnames; i++) {
-            vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "s",
-                                            &vs->wnames[i]);
+    if (nwnames && nwnames <= P9_MAXWELEM) {
+        wnames = g_malloc0(sizeof(wnames[0]) * nwnames);
+        qids   = g_malloc0(sizeof(qids[0]) * nwnames);
+        for (i = 0; i < nwnames; i++) {
+            offset += pdu_unmarshal(pdu, offset, "s", &wnames[i]);
         }
-    } else if (vs->nwnames > P9_MAXWELEM) {
+
+    } else if (nwnames > P9_MAXWELEM) {
         err = -EINVAL;
         goto out;
     }
-
-    vs->fidp = lookup_fid(s, fid);
-    if (vs->fidp == NULL) {
+    fidp = lookup_fid(s, fid);
+    if (fidp == NULL) {
         err = -ENOENT;
         goto out;
     }
-
-    /* FIXME: is this really valid? */
     if (fid == newfid) {
+        BUG_ON(fidp->fid_type != P9_FID_NONE);
+        v9fs_string_init(&path);
+        for (name_idx = 0; name_idx < nwnames; name_idx++) {
+            v9fs_string_sprintf(&path, "%s/%s",
+                                fidp->path.data, wnames[name_idx].data);
+            v9fs_string_copy(&fidp->path, &path);
 
-        BUG_ON(vs->fidp->fid_type != P9_FID_NONE);
-        v9fs_string_init(&vs->path);
-        vs->name_idx = 0;
-
-        if (vs->name_idx < vs->nwnames) {
-            v9fs_string_sprintf(&vs->path, "%s/%s",
-                vs->fidp->path.data, vs->wnames[vs->name_idx].data);
-            v9fs_string_copy(&vs->fidp->path, &vs->path);
-
-            err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
-            v9fs_walk_post_oldfid_lstat(s, vs, err);
-            return;
+            err = v9fs_co_lstat(s, &fidp->path, &stbuf);
+            if (err < 0) {
+                v9fs_string_free(&path);
+                goto out;
+            }
+            stat_to_qid(&stbuf, &qids[name_idx]);
         }
+        v9fs_string_free(&path);
     } else {
-        vs->newfidp = alloc_fid(s, newfid);
-        if (vs->newfidp == NULL) {
+        newfidp = alloc_fid(s, newfid);
+        if (newfidp == NULL) {
             err = -EINVAL;
             goto out;
         }
-
-        vs->newfidp->uid = vs->fidp->uid;
-        v9fs_string_init(&vs->path);
-        vs->name_idx = 0;
-        v9fs_string_copy(&vs->newfidp->path, &vs->fidp->path);
-
-        if (vs->name_idx < vs->nwnames) {
-            v9fs_string_sprintf(&vs->path, "%s/%s", vs->newfidp->path.data,
-                                vs->wnames[vs->name_idx].data);
-            v9fs_string_copy(&vs->newfidp->path, &vs->path);
-
-            err = v9fs_do_lstat(s, &vs->newfidp->path, &vs->stbuf);
-            v9fs_walk_post_newfid_lstat(s, vs, err);
-            return;
+        newfidp->uid = fidp->uid;
+        v9fs_string_init(&path);
+        v9fs_string_copy(&newfidp->path, &fidp->path);
+        for (name_idx = 0; name_idx < nwnames; name_idx++) {
+            v9fs_string_sprintf(&path, "%s/%s", newfidp->path.data,
+                                wnames[name_idx].data);
+            v9fs_string_copy(&newfidp->path, &path);
+            err = v9fs_co_lstat(s, &newfidp->path, &stbuf);
+            if (err < 0) {
+                free_fid(s, newfidp->fid);
+                v9fs_string_free(&path);
+                goto out;
+            }
+            stat_to_qid(&stbuf, &qids[name_idx]);
         }
+        v9fs_string_free(&path);
     }
-
-    v9fs_walk_marshal(vs);
-    err = vs->offset;
+    err = v9fs_walk_marshal(pdu, nwnames, qids);
 out:
-    v9fs_walk_complete(s, vs, err);
+    complete_pdu(s, pdu, err);
+    if (nwnames && nwnames <= P9_MAXWELEM) {
+        for (name_idx = 0; name_idx < nwnames; name_idx++) {
+            v9fs_string_free(&wnames[name_idx]);
+        }
+        g_free(wnames);
+        g_free(qids);
+    }
 }
 
 static int32_t get_iounit(V9fsState *s, V9fsString *name)
@@ -1546,467 +1296,323 @@
      * iounit should be multiples of f_bsize (host filesystem block size
      * and as well as less than (client msize - P9_IOHDRSZ))
      */
-    if (!v9fs_do_statfs(s, name, &stbuf)) {
+    if (!v9fs_co_statfs(s, name, &stbuf)) {
         iounit = stbuf.f_bsize;
         iounit *= (s->msize - P9_IOHDRSZ)/stbuf.f_bsize;
     }
-
     if (!iounit) {
         iounit = s->msize - P9_IOHDRSZ;
     }
     return iounit;
 }
 
-static void v9fs_open_post_opendir(V9fsState *s, V9fsOpenState *vs, int err)
-{
-    if (vs->fidp->fs.dir == NULL) {
-        err = -errno;
-        goto out;
-    }
-    vs->fidp->fid_type = P9_FID_DIR;
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, 0);
-    err = vs->offset;
-out:
-    complete_pdu(s, vs->pdu, err);
-    g_free(vs);
-
-}
-
-static void v9fs_open_post_getiounit(V9fsState *s, V9fsOpenState *vs)
-{
-    int err;
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, vs->iounit);
-    err = vs->offset;
-    complete_pdu(s, vs->pdu, err);
-    g_free(vs);
-}
-
-static void v9fs_open_post_open(V9fsState *s, V9fsOpenState *vs, int err)
-{
-    if (vs->fidp->fs.fd == -1) {
-        err = -errno;
-        goto out;
-    }
-    vs->fidp->fid_type = P9_FID_FILE;
-    vs->iounit = get_iounit(s, &vs->fidp->path);
-    v9fs_open_post_getiounit(s, vs);
-    return;
-out:
-    complete_pdu(s, vs->pdu, err);
-    g_free(vs);
-}
-
-static void v9fs_open_post_lstat(V9fsState *s, V9fsOpenState *vs, int err)
+static void v9fs_open(void *opaque)
 {
     int flags;
+    int iounit;
+    int32_t fid;
+    int32_t mode;
+    V9fsQID qid;
+    ssize_t err = 0;
+    size_t offset = 7;
+    struct stat stbuf;
+    V9fsFidState *fidp;
+    V9fsPDU *pdu = opaque;
+    V9fsState *s = pdu->s;
 
-    if (err) {
-        err = -errno;
+    if (s->proto_version == V9FS_PROTO_2000L) {
+        pdu_unmarshal(pdu, offset, "dd", &fid, &mode);
+    } else {
+        pdu_unmarshal(pdu, offset, "db", &fid, &mode);
+    }
+    fidp = lookup_fid(s, fid);
+    if (fidp == NULL) {
+        err = -ENOENT;
         goto out;
     }
+    BUG_ON(fidp->fid_type != P9_FID_NONE);
 
-    stat_to_qid(&vs->stbuf, &vs->qid);
-
-    if (S_ISDIR(vs->stbuf.st_mode)) {
-        vs->fidp->fs.dir = v9fs_do_opendir(s, &vs->fidp->path);
-        v9fs_open_post_opendir(s, vs, err);
+    err = v9fs_co_lstat(s, &fidp->path, &stbuf);
+    if (err < 0) {
+        goto out;
+    }
+    stat_to_qid(&stbuf, &qid);
+    if (S_ISDIR(stbuf.st_mode)) {
+        err = v9fs_co_opendir(s, fidp);
+        if (err < 0) {
+            goto out;
+        }
+        fidp->fid_type = P9_FID_DIR;
+        offset += pdu_marshal(pdu, offset, "Qd", &qid, 0);
+        err = offset;
     } else {
         if (s->proto_version == V9FS_PROTO_2000L) {
-            flags = vs->mode;
+            flags = mode;
             flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT);
             /* Ignore direct disk access hint until the server supports it. */
             flags &= ~O_DIRECT;
         } else {
-            flags = omode_to_uflags(vs->mode);
+            flags = omode_to_uflags(mode);
         }
-        vs->fidp->fs.fd = v9fs_do_open(s, &vs->fidp->path, flags);
-        v9fs_open_post_open(s, vs, err);
+        err = v9fs_co_open(s, fidp, flags);
+        if (err < 0) {
+            goto out;
+        }
+        fidp->fid_type = P9_FID_FILE;
+        iounit = get_iounit(s, &fidp->path);
+        offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
+        err = offset;
     }
-    return;
-out:
-    complete_pdu(s, vs->pdu, err);
-    g_free(vs);
-}
-
-static void v9fs_open(void *opaque)
-{
-    V9fsPDU *pdu = opaque;
-    V9fsState *s = pdu->s;
-    int32_t fid;
-    V9fsOpenState *vs;
-    ssize_t err = 0;
-
-    vs = g_malloc(sizeof(*vs));
-    vs->pdu = pdu;
-    vs->offset = 7;
-    vs->mode = 0;
-
-    if (s->proto_version == V9FS_PROTO_2000L) {
-        pdu_unmarshal(vs->pdu, vs->offset, "dd", &fid, &vs->mode);
-    } else {
-        pdu_unmarshal(vs->pdu, vs->offset, "db", &fid, &vs->mode);
-    }
-
-    vs->fidp = lookup_fid(s, fid);
-    if (vs->fidp == NULL) {
-        err = -ENOENT;
-        goto out;
-    }
-
-    BUG_ON(vs->fidp->fid_type != P9_FID_NONE);
-
-    err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
-
-    v9fs_open_post_lstat(s, vs, err);
-    return;
 out:
     complete_pdu(s, pdu, err);
-    g_free(vs);
-}
-
-static void v9fs_post_lcreate(V9fsState *s, V9fsLcreateState *vs, int err)
-{
-    if (err == 0) {
-        v9fs_string_copy(&vs->fidp->path, &vs->fullname);
-        stat_to_qid(&vs->stbuf, &vs->qid);
-        vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid,
-                vs->iounit);
-        err = vs->offset;
-    } else {
-        vs->fidp->fid_type = P9_FID_NONE;
-        err = -errno;
-        if (vs->fidp->fs.fd > 0) {
-            close(vs->fidp->fs.fd);
-        }
-    }
-
-    complete_pdu(s, vs->pdu, err);
-    v9fs_string_free(&vs->name);
-    v9fs_string_free(&vs->fullname);
-    g_free(vs);
-}
-
-static void v9fs_lcreate_post_get_iounit(V9fsState *s, V9fsLcreateState *vs,
-        int err)
-{
-    if (err) {
-        err = -errno;
-        goto out;
-    }
-    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
-
-out:
-    v9fs_post_lcreate(s, vs, err);
-}
-
-static void v9fs_lcreate_post_do_open2(V9fsState *s, V9fsLcreateState *vs,
-        int err)
-{
-    if (vs->fidp->fs.fd == -1) {
-        err = -errno;
-        goto out;
-    }
-    vs->fidp->fid_type = P9_FID_FILE;
-    vs->iounit =  get_iounit(s, &vs->fullname);
-    v9fs_lcreate_post_get_iounit(s, vs, err);
-    return;
-
-out:
-    v9fs_post_lcreate(s, vs, err);
 }
 
 static void v9fs_lcreate(void *opaque)
 {
-    V9fsPDU *pdu = opaque;
-    V9fsState *s = pdu->s;
     int32_t dfid, flags, mode;
     gid_t gid;
-    V9fsLcreateState *vs;
     ssize_t err = 0;
+    ssize_t offset = 7;
+    V9fsString fullname;
+    V9fsString name;
+    V9fsFidState *fidp;
+    struct stat stbuf;
+    V9fsQID qid;
+    int32_t iounit;
+    V9fsPDU *pdu = opaque;
 
-    vs = g_malloc(sizeof(*vs));
-    vs->pdu = pdu;
-    vs->offset = 7;
+    v9fs_string_init(&fullname);
+    pdu_unmarshal(pdu, offset, "dsddd", &dfid, &name, &flags,
+                  &mode, &gid);
 
-    v9fs_string_init(&vs->fullname);
-
-    pdu_unmarshal(vs->pdu, vs->offset, "dsddd", &dfid, &vs->name, &flags,
-            &mode, &gid);
-
-    vs->fidp = lookup_fid(s, dfid);
-    if (vs->fidp == NULL) {
+    fidp = lookup_fid(pdu->s, dfid);
+    if (fidp == NULL) {
         err = -ENOENT;
         goto out;
     }
-
-    v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->fidp->path.data,
-             vs->name.data);
+    v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
 
     /* Ignore direct disk access hint until the server supports it. */
     flags &= ~O_DIRECT;
 
-    vs->fidp->fs.fd = v9fs_do_open2(s, vs->fullname.data, vs->fidp->uid,
-            gid, flags, mode);
-    v9fs_lcreate_post_do_open2(s, vs, err);
-    return;
-
-out:
-    complete_pdu(s, vs->pdu, err);
-    v9fs_string_free(&vs->name);
-    g_free(vs);
-}
-
-static void v9fs_post_do_fsync(V9fsState *s, V9fsPDU *pdu, int err)
-{
-    if (err == -1) {
-        err = -errno;
+    err = v9fs_co_open2(pdu->s, fidp, fullname.data, gid, flags, mode);
+    if (err < 0) {
+        goto out;
     }
-    complete_pdu(s, pdu, err);
+    fidp->fid_type = P9_FID_FILE;
+    iounit =  get_iounit(pdu->s, &fullname);
+
+    err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
+    if (err < 0) {
+        fidp->fid_type = P9_FID_NONE;
+        if (fidp->fs.fd > 0) {
+            close(fidp->fs.fd);
+        }
+        goto out;
+    }
+    v9fs_string_copy(&fidp->path, &fullname);
+    stat_to_qid(&stbuf, &qid);
+    offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
+    err = offset;
+out:
+    complete_pdu(pdu->s, pdu, err);
+    v9fs_string_free(&name);
+    v9fs_string_free(&fullname);
 }
 
 static void v9fs_fsync(void *opaque)
 {
-    V9fsPDU *pdu = opaque;
-    V9fsState *s = pdu->s;
+    int err;
     int32_t fid;
+    int datasync;
     size_t offset = 7;
     V9fsFidState *fidp;
-    int datasync;
-    int err;
+    V9fsPDU *pdu = opaque;
+    V9fsState *s = pdu->s;
 
     pdu_unmarshal(pdu, offset, "dd", &fid, &datasync);
     fidp = lookup_fid(s, fid);
     if (fidp == NULL) {
         err = -ENOENT;
-        v9fs_post_do_fsync(s, pdu, err);
-        return;
+        goto out;
     }
-    err = v9fs_do_fsync(s, fidp->fs.fd, datasync);
-    v9fs_post_do_fsync(s, pdu, err);
+    err = v9fs_co_fsync(s, fidp, datasync);
+    if (!err) {
+        err = offset;
+    }
+out:
+    complete_pdu(s, pdu, err);
 }
 
 static void v9fs_clunk(void *opaque)
 {
-    V9fsPDU *pdu = opaque;
-    V9fsState *s = pdu->s;
+    int err;
     int32_t fid;
     size_t offset = 7;
-    int err;
+    V9fsPDU *pdu = opaque;
+    V9fsState *s = pdu->s;
 
     pdu_unmarshal(pdu, offset, "d", &fid);
-
     err = free_fid(s, fid);
     if (err < 0) {
         goto out;
     }
-
-    offset = 7;
     err = offset;
 out:
     complete_pdu(s, pdu, err);
 }
 
-static void v9fs_read_post_readdir(V9fsState *, V9fsReadState *, ssize_t);
-
-static void v9fs_read_post_seekdir(V9fsState *s, V9fsReadState *vs, ssize_t err)
+static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu,
+                           V9fsFidState *fidp, int64_t off, int32_t max_count)
 {
-    if (err) {
-        goto out;
-    }
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
-    vs->offset += vs->count;
-    err = vs->offset;
-out:
-    complete_pdu(s, vs->pdu, err);
-    v9fs_stat_free(&vs->v9stat);
-    v9fs_string_free(&vs->name);
-    g_free(vs);
-    return;
-}
-
-static void v9fs_read_post_dir_lstat(V9fsState *s, V9fsReadState *vs,
-                                    ssize_t err)
-{
-    if (err) {
-        err = -errno;
-        goto out;
-    }
-    err = stat_to_v9stat(s, &vs->name, &vs->stbuf, &vs->v9stat);
-    if (err) {
-        goto out;
-    }
-
-    vs->len = pdu_marshal(vs->pdu, vs->offset + 4 + vs->count, "S",
-                            &vs->v9stat);
-    if ((vs->len != (vs->v9stat.size + 2)) ||
-            ((vs->count + vs->len) > vs->max_count)) {
-        v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->dir_pos);
-        v9fs_read_post_seekdir(s, vs, err);
-        return;
-    }
-    vs->count += vs->len;
-    v9fs_stat_free(&vs->v9stat);
-    v9fs_string_free(&vs->name);
-    vs->dir_pos = vs->dent->d_off;
-    v9fs_co_readdir(s, vs->fidp, &vs->dent);
-    v9fs_read_post_readdir(s, vs, err);
-    return;
-out:
-    v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->dir_pos);
-    v9fs_read_post_seekdir(s, vs, err);
-    return;
-
-}
-
-static void v9fs_read_post_readdir(V9fsState *s, V9fsReadState *vs, ssize_t err)
-{
-    if (vs->dent) {
-        memset(&vs->v9stat, 0, sizeof(vs->v9stat));
-        v9fs_string_init(&vs->name);
-        v9fs_string_sprintf(&vs->name, "%s/%s", vs->fidp->path.data,
-                            vs->dent->d_name);
-        err = v9fs_do_lstat(s, &vs->name, &vs->stbuf);
-        v9fs_read_post_dir_lstat(s, vs, err);
-        return;
-    }
-
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
-    vs->offset += vs->count;
-    err = vs->offset;
-    complete_pdu(s, vs->pdu, err);
-    g_free(vs);
-    return;
-}
-
-static void v9fs_read_post_telldir(V9fsState *s, V9fsReadState *vs, ssize_t err)
-{
-    v9fs_co_readdir(s, vs->fidp, &vs->dent);
-    v9fs_read_post_readdir(s, vs, err);
-    return;
-}
-
-static void v9fs_read_post_rewinddir(V9fsState *s, V9fsReadState *vs,
-                                       ssize_t err)
-{
-    vs->dir_pos = v9fs_do_telldir(s, vs->fidp->fs.dir);
-    v9fs_read_post_telldir(s, vs, err);
-    return;
-}
-
-static void v9fs_read_post_preadv(V9fsState *s, V9fsReadState *vs, ssize_t err)
-{
-    if (err  < 0) {
-        /* IO error return the error */
-        err = -errno;
-        goto out;
-    }
-    vs->total += vs->len;
-    vs->sg = adjust_sg(vs->sg, vs->len, &vs->cnt);
-    if (vs->total < vs->count && vs->len > 0) {
-        do {
-            if (0) {
-                print_sg(vs->sg, vs->cnt);
-            }
-            vs->len = v9fs_do_preadv(s, vs->fidp->fs.fd, vs->sg, vs->cnt,
-                      vs->off);
-            if (vs->len > 0) {
-                vs->off += vs->len;
-            }
-        } while (vs->len == -1 && errno == EINTR);
-        if (vs->len == -1) {
-            err  = -errno;
-        }
-        v9fs_read_post_preadv(s, vs, err);
-        return;
-    }
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total);
-    vs->offset += vs->count;
-    err = vs->offset;
-
-out:
-    complete_pdu(s, vs->pdu, err);
-    g_free(vs);
-}
-
-static void v9fs_xattr_read(V9fsState *s, V9fsReadState *vs)
-{
-    ssize_t err = 0;
+    size_t offset = 7;
     int read_count;
     int64_t xattr_len;
 
-    xattr_len = vs->fidp->fs.xattr.len;
-    read_count = xattr_len - vs->off;
-    if (read_count > vs->count) {
-        read_count = vs->count;
+    xattr_len = fidp->fs.xattr.len;
+    read_count = xattr_len - off;
+    if (read_count > max_count) {
+        read_count = max_count;
     } else if (read_count < 0) {
         /*
          * read beyond XATTR value
          */
         read_count = 0;
     }
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", read_count);
-    vs->offset += pdu_pack(vs->pdu, vs->offset,
-                           ((char *)vs->fidp->fs.xattr.value) + vs->off,
-                           read_count);
-    err = vs->offset;
-    complete_pdu(s, vs->pdu, err);
-    g_free(vs);
+    offset += pdu_marshal(pdu, offset, "d", read_count);
+    offset += pdu_pack(pdu, offset,
+                       ((char *)fidp->fs.xattr.value) + off,
+                       read_count);
+    return offset;
+}
+
+static int v9fs_do_readdir_with_stat(V9fsState *s, V9fsPDU *pdu,
+                                     V9fsFidState *fidp, int32_t max_count)
+{
+    V9fsString name;
+    V9fsStat v9stat;
+    int len, err = 0;
+    int32_t count = 0;
+    struct stat stbuf;
+    off_t saved_dir_pos;
+    struct dirent *dent, *result;
+
+    /* save the directory position */
+    saved_dir_pos = v9fs_co_telldir(s, fidp);
+    if (saved_dir_pos < 0) {
+        return saved_dir_pos;
+    }
+
+    dent = g_malloc(sizeof(struct dirent));
+
+    while (1) {
+        v9fs_string_init(&name);
+        err = v9fs_co_readdir_r(s, fidp, dent, &result);
+        if (err || !result) {
+            break;
+        }
+        v9fs_string_sprintf(&name, "%s/%s", fidp->path.data, dent->d_name);
+        err = v9fs_co_lstat(s, &name, &stbuf);
+        if (err < 0) {
+            goto out;
+        }
+        err = stat_to_v9stat(s, &name, &stbuf, &v9stat);
+        if (err < 0) {
+            goto out;
+        }
+        /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
+        len = pdu_marshal(pdu, 11 + count, "S", &v9stat);
+        if ((len != (v9stat.size + 2)) || ((count + len) > max_count)) {
+            /* Ran out of buffer. Set dir back to old position and return */
+            v9fs_co_seekdir(s, fidp, saved_dir_pos);
+            v9fs_stat_free(&v9stat);
+            v9fs_string_free(&name);
+            g_free(dent);
+            return count;
+        }
+        count += len;
+        v9fs_stat_free(&v9stat);
+        v9fs_string_free(&name);
+        saved_dir_pos = dent->d_off;
+    }
+out:
+    g_free(dent);
+    v9fs_string_free(&name);
+    if (err < 0) {
+        return err;
+    }
+    return count;
 }
 
 static void v9fs_read(void *opaque)
 {
+    int32_t fid;
+    int64_t off;
+    ssize_t err = 0;
+    int32_t count = 0;
+    size_t offset = 7;
+    int32_t max_count;
+    V9fsFidState *fidp;
     V9fsPDU *pdu = opaque;
     V9fsState *s = pdu->s;
-    int32_t fid;
-    V9fsReadState *vs;
-    ssize_t err = 0;
 
-    vs = g_malloc(sizeof(*vs));
-    vs->pdu = pdu;
-    vs->offset = 7;
-    vs->total = 0;
-    vs->len = 0;
-    vs->count = 0;
-
-    pdu_unmarshal(vs->pdu, vs->offset, "dqd", &fid, &vs->off, &vs->count);
-
-    vs->fidp = lookup_fid(s, fid);
-    if (vs->fidp == NULL) {
+    pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &max_count);
+    fidp = lookup_fid(s, fid);
+    if (fidp == NULL) {
         err = -EINVAL;
         goto out;
     }
+    if (fidp->fid_type == P9_FID_DIR) {
 
-    if (vs->fidp->fid_type == P9_FID_DIR) {
-        vs->max_count = vs->count;
-        vs->count = 0;
-        if (vs->off == 0) {
-            v9fs_do_rewinddir(s, vs->fidp->fs.dir);
+        if (off == 0) {
+            v9fs_co_rewinddir(s, fidp);
         }
-        v9fs_read_post_rewinddir(s, vs, err);
-        return;
-    } else if (vs->fidp->fid_type == P9_FID_FILE) {
-        vs->sg = vs->iov;
-        pdu_marshal(vs->pdu, vs->offset + 4, "v", vs->sg, &vs->cnt);
-        vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
-        if (vs->total <= vs->count) {
-            vs->len = v9fs_do_preadv(s, vs->fidp->fs.fd, vs->sg, vs->cnt,
-                                    vs->off);
-            if (vs->len > 0) {
-                vs->off += vs->len;
+        count = v9fs_do_readdir_with_stat(s, pdu, fidp, max_count);
+        if (count < 0) {
+            err = count;
+            goto out;
+        }
+        err = offset;
+        err += pdu_marshal(pdu, offset, "d", count);
+        err += count;
+    } else if (fidp->fid_type == P9_FID_FILE) {
+        int32_t cnt;
+        int32_t len;
+        struct iovec *sg;
+        struct iovec iov[128]; /* FIXME: bad, bad, bad */
+
+        sg = iov;
+        pdu_marshal(pdu, offset + 4, "v", sg, &cnt);
+        sg = cap_sg(sg, max_count, &cnt);
+        do {
+            if (0) {
+                print_sg(sg, cnt);
             }
-            err = vs->len;
-            v9fs_read_post_preadv(s, vs, err);
-        }
-        return;
-    } else if (vs->fidp->fid_type == P9_FID_XATTR) {
-        v9fs_xattr_read(s, vs);
-        return;
+            /* Loop in case of EINTR */
+            do {
+                len = v9fs_co_preadv(s, fidp, sg, cnt, off);
+                if (len >= 0) {
+                    off   += len;
+                    count += len;
+                }
+            } while (len == -EINTR);
+            if (len < 0) {
+                /* IO error return the error */
+                err = len;
+                goto out;
+            }
+            sg = adjust_sg(sg, len, &cnt);
+        } while (count < max_count && len > 0);
+        err = offset;
+        err += pdu_marshal(pdu, offset, "d", count);
+        err += count;
+    } else if (fidp->fid_type == P9_FID_XATTR) {
+        err = v9fs_xattr_read(s, pdu, fidp, off, max_count);
     } else {
         err = -EINVAL;
     }
 out:
     complete_pdu(s, pdu, err);
-    g_free(vs);
 }
 
 static size_t v9fs_readdir_data_size(V9fsString *name)
@@ -2027,16 +1633,19 @@
     int len, err = 0;
     int32_t count = 0;
     off_t saved_dir_pos;
-    struct dirent *dent;
+    struct dirent *dent, *result;
 
     /* save the directory position */
     saved_dir_pos = v9fs_co_telldir(s, fidp);
     if (saved_dir_pos < 0) {
         return saved_dir_pos;
     }
+
+    dent = g_malloc(sizeof(struct dirent));
+
     while (1) {
-        err = v9fs_co_readdir(s, fidp, &dent);
-        if (err || !dent) {
+        err = v9fs_co_readdir_r(s, fidp, dent, &result);
+        if (err || !result) {
             break;
         }
         v9fs_string_init(&name);
@@ -2045,6 +1654,7 @@
             /* Ran out of buffer. Set dir back to old position and return */
             v9fs_co_seekdir(s, fidp, saved_dir_pos);
             v9fs_string_free(&name);
+            g_free(dent);
             return count;
         }
         /*
@@ -2066,6 +1676,7 @@
         v9fs_string_free(&name);
         saved_dir_pos = dent->d_off;
     }
+    g_free(dent);
     if (err < 0) {
         return err;
     }
@@ -2107,51 +1718,21 @@
     complete_pdu(s, pdu, retval);
 }
 
-static void v9fs_write_post_pwritev(V9fsState *s, V9fsWriteState *vs,
-                                   ssize_t err)
-{
-    if (err  < 0) {
-        /* IO error return the error */
-        err = -errno;
-        goto out;
-    }
-    vs->total += vs->len;
-    vs->sg = adjust_sg(vs->sg, vs->len, &vs->cnt);
-    if (vs->total < vs->count && vs->len > 0) {
-        do {
-            if (0) {
-                print_sg(vs->sg, vs->cnt);
-            }
-            vs->len = v9fs_do_pwritev(s, vs->fidp->fs.fd, vs->sg, vs->cnt,
-                      vs->off);
-            if (vs->len > 0) {
-                vs->off += vs->len;
-            }
-        } while (vs->len == -1 && errno == EINTR);
-        if (vs->len == -1) {
-            err  = -errno;
-        }
-        v9fs_write_post_pwritev(s, vs, err);
-        return;
-    }
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total);
-    err = vs->offset;
-out:
-    complete_pdu(s, vs->pdu, err);
-    g_free(vs);
-}
-
-static void v9fs_xattr_write(V9fsState *s, V9fsWriteState *vs)
+static int v9fs_xattr_write(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
+                            int64_t off, int32_t count,
+                            struct iovec *sg, int cnt)
 {
     int i, to_copy;
     ssize_t err = 0;
     int write_count;
     int64_t xattr_len;
+    size_t offset = 7;
 
-    xattr_len = vs->fidp->fs.xattr.len;
-    write_count = xattr_len - vs->off;
-    if (write_count > vs->count) {
-        write_count = vs->count;
+
+    xattr_len = fidp->fs.xattr.len;
+    write_count = xattr_len - off;
+    if (write_count > count) {
+        write_count = count;
     } else if (write_count < 0) {
         /*
          * write beyond XATTR value len specified in
@@ -2160,225 +1741,161 @@
         err = -ENOSPC;
         goto out;
     }
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", write_count);
-    err = vs->offset;
-    vs->fidp->fs.xattr.copied_len += write_count;
+    offset += pdu_marshal(pdu, offset, "d", write_count);
+    err = offset;
+    fidp->fs.xattr.copied_len += write_count;
     /*
      * Now copy the content from sg list
      */
-    for (i = 0; i < vs->cnt; i++) {
-        if (write_count > vs->sg[i].iov_len) {
-            to_copy = vs->sg[i].iov_len;
+    for (i = 0; i < cnt; i++) {
+        if (write_count > sg[i].iov_len) {
+            to_copy = sg[i].iov_len;
         } else {
             to_copy = write_count;
         }
-        memcpy((char *)vs->fidp->fs.xattr.value + vs->off,
-               vs->sg[i].iov_base, to_copy);
+        memcpy((char *)fidp->fs.xattr.value + off, sg[i].iov_base, to_copy);
         /* updating vs->off since we are not using below */
-        vs->off += to_copy;
+        off += to_copy;
         write_count -= to_copy;
     }
 out:
-    complete_pdu(s, vs->pdu, err);
-    g_free(vs);
+    return err;
 }
 
 static void v9fs_write(void *opaque)
 {
+    int cnt;
+    ssize_t err;
+    int32_t fid;
+    int64_t off;
+    int32_t count;
+    int32_t len = 0;
+    int32_t total = 0;
+    size_t offset = 7;
+    V9fsFidState *fidp;
+    struct iovec iov[128]; /* FIXME: bad, bad, bad */
+    struct iovec *sg = iov;
     V9fsPDU *pdu = opaque;
     V9fsState *s = pdu->s;
-    int32_t fid;
-    V9fsWriteState *vs;
-    ssize_t err;
 
-    vs = g_malloc(sizeof(*vs));
-
-    vs->pdu = pdu;
-    vs->offset = 7;
-    vs->sg = vs->iov;
-    vs->total = 0;
-    vs->len = 0;
-
-    pdu_unmarshal(vs->pdu, vs->offset, "dqdv", &fid, &vs->off, &vs->count,
-                  vs->sg, &vs->cnt);
-
-    vs->fidp = lookup_fid(s, fid);
-    if (vs->fidp == NULL) {
+    pdu_unmarshal(pdu, offset, "dqdv", &fid, &off, &count, sg, &cnt);
+    fidp = lookup_fid(s, fid);
+    if (fidp == NULL) {
         err = -EINVAL;
         goto out;
     }
-
-    if (vs->fidp->fid_type == P9_FID_FILE) {
-        if (vs->fidp->fs.fd == -1) {
+    if (fidp->fid_type == P9_FID_FILE) {
+        if (fidp->fs.fd == -1) {
             err = -EINVAL;
             goto out;
         }
-    } else if (vs->fidp->fid_type == P9_FID_XATTR) {
+    } else if (fidp->fid_type == P9_FID_XATTR) {
         /*
          * setxattr operation
          */
-        v9fs_xattr_write(s, vs);
-        return;
+        err = v9fs_xattr_write(s, pdu, fidp, off, count, sg, cnt);
+        goto out;
     } else {
         err = -EINVAL;
         goto out;
     }
-    vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
-    if (vs->total <= vs->count) {
-        vs->len = v9fs_do_pwritev(s, vs->fidp->fs.fd, vs->sg, vs->cnt, vs->off);
-        if (vs->len > 0) {
-            vs->off += vs->len;
+    sg = cap_sg(sg, count, &cnt);
+    do {
+        if (0) {
+            print_sg(sg, cnt);
         }
-        err = vs->len;
-        v9fs_write_post_pwritev(s, vs, err);
-    }
-    return;
+        /* Loop in case of EINTR */
+        do {
+            len = v9fs_co_pwritev(s, fidp, sg, cnt, off);
+            if (len >= 0) {
+                off   += len;
+                total += len;
+            }
+        } while (len == -EINTR);
+        if (len < 0) {
+            /* IO error return the error */
+            err = len;
+            goto out;
+        }
+        sg = adjust_sg(sg, len, &cnt);
+    } while (total < count && len > 0);
+    offset += pdu_marshal(pdu, offset, "d", total);
+    err = offset;
 out:
-    complete_pdu(s, vs->pdu, err);
-    g_free(vs);
+    complete_pdu(s, pdu, err);
 }
 
-static void v9fs_create_post_getiounit(V9fsState *s, V9fsCreateState *vs)
+static void v9fs_create(void *opaque)
 {
-    int err;
-    v9fs_string_copy(&vs->fidp->path, &vs->fullname);
-    stat_to_qid(&vs->stbuf, &vs->qid);
+    int32_t fid;
+    int err = 0;
+    size_t offset = 7;
+    V9fsFidState *fidp;
+    V9fsQID qid;
+    int32_t perm;
+    int8_t mode;
+    struct stat stbuf;
+    V9fsString name;
+    V9fsString extension;
+    V9fsString fullname;
+    int iounit;
+    V9fsPDU *pdu = opaque;
 
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, vs->iounit);
-    err = vs->offset;
+    v9fs_string_init(&fullname);
 
-    complete_pdu(s, vs->pdu, err);
-    v9fs_string_free(&vs->name);
-    v9fs_string_free(&vs->extension);
-    v9fs_string_free(&vs->fullname);
-    g_free(vs);
-}
+    pdu_unmarshal(pdu, offset, "dsdbs", &fid, &name,
+                  &perm, &mode, &extension);
 
-static void v9fs_post_create(V9fsState *s, V9fsCreateState *vs, int err)
-{
-    if (err == 0) {
-        vs->iounit = get_iounit(s, &vs->fidp->path);
-        v9fs_create_post_getiounit(s, vs);
-        return;
-    }
-
-    complete_pdu(s, vs->pdu, err);
-    v9fs_string_free(&vs->name);
-    v9fs_string_free(&vs->extension);
-    v9fs_string_free(&vs->fullname);
-    g_free(vs);
-}
-
-static void v9fs_create_post_perms(V9fsState *s, V9fsCreateState *vs, int err)
-{
-    if (err) {
-        err = -errno;
-    }
-    v9fs_post_create(s, vs, err);
-}
-
-static void v9fs_create_post_opendir(V9fsState *s, V9fsCreateState *vs,
-                                                                    int err)
-{
-    if (!vs->fidp->fs.dir) {
-        err = -errno;
-    }
-    vs->fidp->fid_type = P9_FID_DIR;
-    v9fs_post_create(s, vs, err);
-}
-
-static void v9fs_create_post_dir_lstat(V9fsState *s, V9fsCreateState *vs,
-                                                                    int err)
-{
-    if (err) {
-        err = -errno;
+    fidp = lookup_fid(pdu->s, fid);
+    if (fidp == NULL) {
+        err = -EINVAL;
         goto out;
     }
 
-    vs->fidp->fs.dir = v9fs_do_opendir(s, &vs->fullname);
-    v9fs_create_post_opendir(s, vs, err);
-    return;
-
-out:
-    v9fs_post_create(s, vs, err);
-}
-
-static void v9fs_create_post_mkdir(V9fsState *s, V9fsCreateState *vs, int err)
-{
-    if (err < 0) {
+    v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
+    err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
+    if (!err) {
+        err = -EEXIST;
+        goto out;
+    } else if (err != -ENOENT) {
         goto out;
     }
-
-    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
-    v9fs_create_post_dir_lstat(s, vs, err);
-    return;
-
-out:
-    v9fs_post_create(s, vs, err);
-}
-
-static void v9fs_create_post_fstat(V9fsState *s, V9fsCreateState *vs, int err)
-{
-    if (err) {
-        vs->fidp->fid_type = P9_FID_NONE;
-        close(vs->fidp->fs.fd);
-        err = -errno;
-    }
-    v9fs_post_create(s, vs, err);
-    return;
-}
-
-static void v9fs_create_post_open2(V9fsState *s, V9fsCreateState *vs, int err)
-{
-    if (vs->fidp->fs.fd == -1) {
-        err = -errno;
-        goto out;
-    }
-    vs->fidp->fid_type = P9_FID_FILE;
-    err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf);
-    v9fs_create_post_fstat(s, vs, err);
-
-    return;
-
-out:
-    v9fs_post_create(s, vs, err);
-
-}
-
-static void v9fs_create_post_lstat(V9fsState *s, V9fsCreateState *vs, int err)
-{
-
-    if (err == 0 || errno != ENOENT) {
-        err = -errno;
-        goto out;
-    }
-
-    if (vs->perm & P9_STAT_MODE_DIR) {
-        err = v9fs_co_mkdir(s, vs->fullname.data, vs->perm & 0777,
-                vs->fidp->uid, -1);
-        v9fs_create_post_mkdir(s, vs, err);
-    } else if (vs->perm & P9_STAT_MODE_SYMLINK) {
-        err = v9fs_do_symlink(s, vs->fidp, vs->extension.data,
-                vs->fullname.data, -1);
-        v9fs_create_post_perms(s, vs, err);
-    } else if (vs->perm & P9_STAT_MODE_LINK) {
-        int32_t nfid = atoi(vs->extension.data);
-        V9fsFidState *nfidp = lookup_fid(s, nfid);
+    if (perm & P9_STAT_MODE_DIR) {
+        err = v9fs_co_mkdir(pdu->s, fullname.data, perm & 0777,
+                            fidp->uid, -1);
+        if (err < 0) {
+            goto out;
+        }
+        err = v9fs_co_opendir(pdu->s, fidp);
+        if (err < 0) {
+            goto out;
+        }
+        fidp->fid_type = P9_FID_DIR;
+    } else if (perm & P9_STAT_MODE_SYMLINK) {
+        err = v9fs_co_symlink(pdu->s, fidp, extension.data,
+                              fullname.data, -1);
+        if (err < 0) {
+            goto out;
+        }
+    } else if (perm & P9_STAT_MODE_LINK) {
+        int32_t nfid = atoi(extension.data);
+        V9fsFidState *nfidp = lookup_fid(pdu->s, nfid);
         if (nfidp == NULL) {
-            err = -errno;
-            v9fs_post_create(s, vs, err);
+            err = -EINVAL;
+            goto out;
         }
-        err = v9fs_do_link(s, &nfidp->path, &vs->fullname);
-        v9fs_create_post_perms(s, vs, err);
-    } else if (vs->perm & P9_STAT_MODE_DEVICE) {
+        err = v9fs_co_link(pdu->s, &nfidp->path, &fullname);
+        if (err < 0) {
+            goto out;
+        }
+    } else if (perm & P9_STAT_MODE_DEVICE) {
         char ctype;
         uint32_t major, minor;
         mode_t nmode = 0;
 
-        if (sscanf(vs->extension.data, "%c %u %u", &ctype, &major,
-                                        &minor) != 3) {
+        if (sscanf(extension.data, "%c %u %u", &ctype, &major, &minor) != 3) {
             err = -errno;
-            v9fs_post_create(s, vs, err);
+            goto out;
         }
 
         switch (ctype) {
@@ -2390,134 +1907,95 @@
             break;
         default:
             err = -EIO;
-            v9fs_post_create(s, vs, err);
+            goto out;
         }
 
-        nmode |= vs->perm & 0777;
-        err = v9fs_do_mknod(s, vs->fullname.data, nmode,
-                makedev(major, minor), vs->fidp->uid, -1);
-        v9fs_create_post_perms(s, vs, err);
-    } else if (vs->perm & P9_STAT_MODE_NAMED_PIPE) {
-        err = v9fs_do_mknod(s, vs->fullname.data, S_IFIFO | (vs->perm & 0777),
-                0, vs->fidp->uid, -1);
-        v9fs_post_create(s, vs, err);
-    } else if (vs->perm & P9_STAT_MODE_SOCKET) {
-        err = v9fs_do_mknod(s, vs->fullname.data, S_IFSOCK | (vs->perm & 0777),
-                0, vs->fidp->uid, -1);
-        v9fs_post_create(s, vs, err);
+        nmode |= perm & 0777;
+        err = v9fs_co_mknod(pdu->s, &fullname, fidp->uid, -1,
+                            makedev(major, minor), nmode);
+        if (err < 0) {
+            goto out;
+        }
+    } else if (perm & P9_STAT_MODE_NAMED_PIPE) {
+        err = v9fs_co_mknod(pdu->s, &fullname, fidp->uid, -1,
+                            0, S_IFIFO | (perm & 0777));
+        if (err < 0) {
+            goto out;
+        }
+    } else if (perm & P9_STAT_MODE_SOCKET) {
+        err = v9fs_co_mknod(pdu->s, &fullname, fidp->uid, -1,
+                            0, S_IFSOCK | (perm & 0777));
+        if (err < 0) {
+            goto out;
+        }
     } else {
-        vs->fidp->fs.fd = v9fs_do_open2(s, vs->fullname.data, vs->fidp->uid,
-                -1, omode_to_uflags(vs->mode)|O_CREAT, vs->perm);
-
-        v9fs_create_post_open2(s, vs, err);
+        err = v9fs_co_open2(pdu->s, fidp, fullname.data, -1,
+                            omode_to_uflags(mode)|O_CREAT, perm);
+        if (err < 0) {
+            goto out;
+        }
+        fidp->fid_type = P9_FID_FILE;
     }
-
-    return;
-
-out:
-    v9fs_post_create(s, vs, err);
-}
-
-static void v9fs_create(void *opaque)
-{
-    V9fsPDU *pdu = opaque;
-    V9fsState *s = pdu->s;
-    int32_t fid;
-    V9fsCreateState *vs;
-    int err = 0;
-
-    vs = g_malloc(sizeof(*vs));
-    vs->pdu = pdu;
-    vs->offset = 7;
-
-    v9fs_string_init(&vs->fullname);
-
-    pdu_unmarshal(vs->pdu, vs->offset, "dsdbs", &fid, &vs->name,
-                                &vs->perm, &vs->mode, &vs->extension);
-
-    vs->fidp = lookup_fid(s, fid);
-    if (vs->fidp == NULL) {
-        err = -EINVAL;
+    err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
+    if (err < 0) {
+        fidp->fid_type = P9_FID_NONE;
+        if (fidp->fs.fd) {
+            close(fidp->fs.fd);
+        }
         goto out;
     }
-
-    v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->fidp->path.data,
-                                                        vs->name.data);
-
-    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
-    v9fs_create_post_lstat(s, vs, err);
-    return;
-
+    iounit = get_iounit(pdu->s, &fidp->path);
+    v9fs_string_copy(&fidp->path, &fullname);
+    stat_to_qid(&stbuf, &qid);
+    offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
+    err = offset;
 out:
-    complete_pdu(s, vs->pdu, err);
-    v9fs_string_free(&vs->name);
-    v9fs_string_free(&vs->extension);
-    g_free(vs);
-}
-
-static void v9fs_post_symlink(V9fsState *s, V9fsSymlinkState *vs, int err)
-{
-    if (err == 0) {
-        stat_to_qid(&vs->stbuf, &vs->qid);
-        vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qid);
-        err = vs->offset;
-    } else {
-        err = -errno;
-    }
-    complete_pdu(s, vs->pdu, err);
-    v9fs_string_free(&vs->name);
-    v9fs_string_free(&vs->symname);
-    v9fs_string_free(&vs->fullname);
-    g_free(vs);
-}
-
-static void v9fs_symlink_post_do_symlink(V9fsState *s, V9fsSymlinkState *vs,
-        int err)
-{
-    if (err) {
-        goto out;
-    }
-    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
-out:
-    v9fs_post_symlink(s, vs, err);
+   complete_pdu(pdu->s, pdu, err);
+   v9fs_string_free(&name);
+   v9fs_string_free(&extension);
+   v9fs_string_free(&fullname);
 }
 
 static void v9fs_symlink(void *opaque)
 {
     V9fsPDU *pdu = opaque;
-    V9fsState *s = pdu->s;
+    V9fsString name;
+    V9fsString symname;
+    V9fsString fullname;
+    V9fsFidState *dfidp;
+    V9fsQID qid;
+    struct stat stbuf;
     int32_t dfid;
-    V9fsSymlinkState *vs;
     int err = 0;
     gid_t gid;
+    size_t offset = 7;
 
-    vs = g_malloc(sizeof(*vs));
-    vs->pdu = pdu;
-    vs->offset = 7;
+    v9fs_string_init(&fullname);
+    pdu_unmarshal(pdu, offset, "dssd", &dfid, &name, &symname, &gid);
 
-    v9fs_string_init(&vs->fullname);
-
-    pdu_unmarshal(vs->pdu, vs->offset, "dssd", &dfid, &vs->name,
-            &vs->symname, &gid);
-
-    vs->dfidp = lookup_fid(s, dfid);
-    if (vs->dfidp == NULL) {
+    dfidp = lookup_fid(pdu->s, dfid);
+    if (dfidp == NULL) {
         err = -EINVAL;
         goto out;
     }
 
-    v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->dfidp->path.data,
-            vs->name.data);
-    err = v9fs_do_symlink(s, vs->dfidp, vs->symname.data,
-            vs->fullname.data, gid);
-    v9fs_symlink_post_do_symlink(s, vs, err);
-    return;
-
+    v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name.data);
+    err = v9fs_co_symlink(pdu->s, dfidp, symname.data, fullname.data, gid);
+    if (err < 0) {
+        goto out;
+    }
+    err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
+    if (err < 0) {
+        goto out;
+    }
+    stat_to_qid(&stbuf, &qid);
+    offset += pdu_marshal(pdu, offset, "Q", &qid);
+    err = offset;
 out:
-    complete_pdu(s, vs->pdu, err);
-    v9fs_string_free(&vs->name);
-    v9fs_string_free(&vs->symname);
-    g_free(vs);
+    complete_pdu(pdu->s, pdu, err);
+    v9fs_string_free(&name);
+    v9fs_string_free(&symname);
+    v9fs_string_free(&fullname);
 }
 
 static void v9fs_flush(void *opaque)
@@ -2545,21 +2023,20 @@
 
     dfidp = lookup_fid(s, dfid);
     if (dfidp == NULL) {
-        err = -errno;
+        err = -ENOENT;
         goto out;
     }
 
     oldfidp = lookup_fid(s, oldfid);
     if (oldfidp == NULL) {
-        err = -errno;
+        err = -ENOENT;
         goto out;
     }
 
     v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name.data);
-    err = offset;
-    err = v9fs_do_link(s, &oldfidp->path, &fullname);
-    if (err) {
-        err = -errno;
+    err = v9fs_co_link(s, &oldfidp->path, &fullname);
+    if (!err) {
+        err = offset;
     }
     v9fs_string_free(&fullname);
 
@@ -2594,39 +2071,6 @@
     complete_pdu(pdu->s, pdu, err);
 }
 
-static void v9fs_wstat_post_truncate(V9fsState *s, V9fsWstatState *vs, int err)
-{
-    if (err < 0) {
-        goto out;
-    }
-
-    err = vs->offset;
-
-out:
-    v9fs_stat_free(&vs->v9stat);
-    complete_pdu(s, vs->pdu, err);
-    g_free(vs);
-}
-
-static void v9fs_wstat_post_rename(V9fsState *s, V9fsWstatState *vs, int err)
-{
-    if (err < 0) {
-        goto out;
-    }
-    if (vs->v9stat.length != -1) {
-        if (v9fs_do_truncate(s, &vs->fidp->path, vs->v9stat.length) < 0) {
-            err = -errno;
-        }
-    }
-    v9fs_wstat_post_truncate(s, vs, err);
-    return;
-
-out:
-    v9fs_stat_free(&vs->v9stat);
-    complete_pdu(s, vs->pdu, err);
-    g_free(vs);
-}
-
 static int v9fs_complete_rename(V9fsState *s, V9fsFidState *fidp,
                                 int32_t newdirfid, V9fsString *name)
 {
@@ -2695,24 +2139,6 @@
     return err;
 }
 
-static void v9fs_wstat_post_chown(V9fsState *s, V9fsWstatState *vs, int err)
-{
-    if (err < 0) {
-        goto out;
-    }
-
-    if (vs->v9stat.name.size != 0) {
-        err = v9fs_complete_rename(s, vs->fidp, -1, &vs->v9stat.name);
-    }
-    v9fs_wstat_post_rename(s, vs, err);
-    return;
-
-out:
-    v9fs_stat_free(&vs->v9stat);
-    complete_pdu(s, vs->pdu, err);
-    g_free(vs);
-}
-
 static void v9fs_rename(void *opaque)
 {
     int32_t fid;
@@ -2742,143 +2168,90 @@
     v9fs_string_free(&name);
 }
 
-static void v9fs_wstat_post_utime(V9fsState *s, V9fsWstatState *vs, int err)
+static void v9fs_wstat(void *opaque)
 {
-    if (err < 0) {
+    int32_t fid;
+    int err = 0;
+    int16_t unused;
+    V9fsStat v9stat;
+    size_t offset = 7;
+    struct stat stbuf;
+    V9fsFidState *fidp;
+    V9fsPDU *pdu = opaque;
+    V9fsState *s = pdu->s;
+
+    pdu_unmarshal(pdu, offset, "dwS", &fid, &unused, &v9stat);
+    fidp = lookup_fid(s, fid);
+    if (fidp == NULL) {
+        err = -EINVAL;
         goto out;
     }
-
-    if (vs->v9stat.n_gid != -1 || vs->v9stat.n_uid != -1) {
-        if (v9fs_do_chown(s, &vs->fidp->path, vs->v9stat.n_uid,
-                    vs->v9stat.n_gid)) {
-            err = -errno;
+    /* do we need to sync the file? */
+    if (donttouch_stat(&v9stat)) {
+        err = v9fs_co_fsync(s, fidp, 0);
+        goto out;
+    }
+    if (v9stat.mode != -1) {
+        uint32_t v9_mode;
+        err = v9fs_co_lstat(s, &fidp->path, &stbuf);
+        if (err < 0) {
+            goto out;
+        }
+        v9_mode = stat_to_v9mode(&stbuf);
+        if ((v9stat.mode & P9_STAT_MODE_TYPE_BITS) !=
+            (v9_mode & P9_STAT_MODE_TYPE_BITS)) {
+            /* Attempting to change the type */
+            err = -EIO;
+            goto out;
+        }
+        err = v9fs_co_chmod(s, &fidp->path,
+                            v9mode_to_mode(v9stat.mode,
+                                           &v9stat.extension));
+        if (err < 0) {
+            goto out;
         }
     }
-    v9fs_wstat_post_chown(s, vs, err);
-    return;
-
-out:
-    v9fs_stat_free(&vs->v9stat);
-    complete_pdu(s, vs->pdu, err);
-    g_free(vs);
-}
-
-static void v9fs_wstat_post_chmod(V9fsState *s, V9fsWstatState *vs, int err)
-{
-    if (err < 0) {
-        goto out;
-    }
-
-    if (vs->v9stat.mtime != -1 || vs->v9stat.atime != -1) {
+    if (v9stat.mtime != -1 || v9stat.atime != -1) {
         struct timespec times[2];
-        if (vs->v9stat.atime != -1) {
-            times[0].tv_sec = vs->v9stat.atime;
+        if (v9stat.atime != -1) {
+            times[0].tv_sec = v9stat.atime;
             times[0].tv_nsec = 0;
         } else {
             times[0].tv_nsec = UTIME_OMIT;
         }
-        if (vs->v9stat.mtime != -1) {
-            times[1].tv_sec = vs->v9stat.mtime;
+        if (v9stat.mtime != -1) {
+            times[1].tv_sec = v9stat.mtime;
             times[1].tv_nsec = 0;
         } else {
             times[1].tv_nsec = UTIME_OMIT;
         }
-
-        if (v9fs_do_utimensat(s, &vs->fidp->path, times)) {
-            err = -errno;
+        err = v9fs_co_utimensat(s, &fidp->path, times);
+        if (err < 0) {
+            goto out;
         }
     }
-
-    v9fs_wstat_post_utime(s, vs, err);
-    return;
-
-out:
-    v9fs_stat_free(&vs->v9stat);
-    complete_pdu(s, vs->pdu, err);
-    g_free(vs);
-}
-
-static void v9fs_wstat_post_fsync(V9fsState *s, V9fsWstatState *vs, int err)
-{
-    if (err == -1) {
-        err = -errno;
-    }
-    v9fs_stat_free(&vs->v9stat);
-    complete_pdu(s, vs->pdu, err);
-    g_free(vs);
-}
-
-static void v9fs_wstat_post_lstat(V9fsState *s, V9fsWstatState *vs, int err)
-{
-    uint32_t v9_mode;
-
-    if (err == -1) {
-        err = -errno;
-        goto out;
-    }
-
-    v9_mode = stat_to_v9mode(&vs->stbuf);
-
-    if ((vs->v9stat.mode & P9_STAT_MODE_TYPE_BITS) !=
-        (v9_mode & P9_STAT_MODE_TYPE_BITS)) {
-            /* Attempting to change the type */
-            err = -EIO;
+    if (v9stat.n_gid != -1 || v9stat.n_uid != -1) {
+        err = v9fs_co_chown(s, &fidp->path, v9stat.n_uid, v9stat.n_gid);
+        if (err < 0) {
             goto out;
+        }
     }
-
-    if (v9fs_do_chmod(s, &vs->fidp->path, v9mode_to_mode(vs->v9stat.mode,
-                    &vs->v9stat.extension))) {
-            err = -errno;
-     }
-    v9fs_wstat_post_chmod(s, vs, err);
-    return;
-
+    if (v9stat.name.size != 0) {
+        err = v9fs_complete_rename(s, fidp, -1, &v9stat.name);
+        if (err < 0) {
+            goto out;
+        }
+    }
+    if (v9stat.length != -1) {
+        err = v9fs_co_truncate(s, &fidp->path, v9stat.length);
+        if (err < 0) {
+            goto out;
+        }
+    }
+    err = offset;
 out:
-    v9fs_stat_free(&vs->v9stat);
-    complete_pdu(s, vs->pdu, err);
-    g_free(vs);
-}
-
-static void v9fs_wstat(void *opaque)
-{
-    V9fsPDU *pdu = opaque;
-    V9fsState *s = pdu->s;
-    int32_t fid;
-    V9fsWstatState *vs;
-    int err = 0;
-
-    vs = g_malloc(sizeof(*vs));
-    vs->pdu = pdu;
-    vs->offset = 7;
-
-    pdu_unmarshal(pdu, vs->offset, "dwS", &fid, &vs->unused, &vs->v9stat);
-
-    vs->fidp = lookup_fid(s, fid);
-    if (vs->fidp == NULL) {
-        err = -EINVAL;
-        goto out;
-    }
-
-    /* do we need to sync the file? */
-    if (donttouch_stat(&vs->v9stat)) {
-        err = v9fs_do_fsync(s, vs->fidp->fs.fd, 0);
-        v9fs_wstat_post_fsync(s, vs, err);
-        return;
-    }
-
-    if (vs->v9stat.mode != -1) {
-        err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
-        v9fs_wstat_post_lstat(s, vs, err);
-        return;
-    }
-
-    v9fs_wstat_post_chmod(s, vs, err);
-    return;
-
-out:
-    v9fs_stat_free(&vs->v9stat);
-    complete_pdu(s, vs->pdu, err);
-    g_free(vs);
+    v9fs_stat_free(&v9stat);
+    complete_pdu(s, pdu, err);
 }
 
 static int v9fs_fill_statfs(V9fsState *s, V9fsPDU *pdu, struct statfs *stbuf)
@@ -3006,89 +2379,81 @@
  * do any thing in * qemu 9p server side lock code path.
  * So when a TLOCK request comes, always return success
  */
-
 static void v9fs_lock(void *opaque)
 {
+    int8_t status;
+    V9fsFlock *flock;
+    size_t offset = 7;
+    struct stat stbuf;
+    V9fsFidState *fidp;
+    int32_t fid, err = 0;
     V9fsPDU *pdu = opaque;
     V9fsState *s = pdu->s;
-    int32_t fid, err = 0;
-    V9fsLockState *vs;
 
-    vs = g_malloc0(sizeof(*vs));
-    vs->pdu = pdu;
-    vs->offset = 7;
-
-    vs->flock = g_malloc(sizeof(*vs->flock));
-    pdu_unmarshal(vs->pdu, vs->offset, "dbdqqds", &fid, &vs->flock->type,
-                &vs->flock->flags, &vs->flock->start, &vs->flock->length,
-                            &vs->flock->proc_id, &vs->flock->client_id);
-
-    vs->status = P9_LOCK_ERROR;
+    flock = g_malloc(sizeof(*flock));
+    pdu_unmarshal(pdu, offset, "dbdqqds", &fid, &flock->type,
+                  &flock->flags, &flock->start, &flock->length,
+                  &flock->proc_id, &flock->client_id);
+    status = P9_LOCK_ERROR;
 
     /* We support only block flag now (that too ignored currently) */
-    if (vs->flock->flags & ~P9_LOCK_FLAGS_BLOCK) {
+    if (flock->flags & ~P9_LOCK_FLAGS_BLOCK) {
         err = -EINVAL;
         goto out;
     }
-    vs->fidp = lookup_fid(s, fid);
-    if (vs->fidp == NULL) {
+    fidp = lookup_fid(s, fid);
+    if (fidp == NULL) {
         err = -ENOENT;
         goto out;
     }
-
-    err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf);
+    err = v9fs_co_fstat(s, fidp->fs.fd, &stbuf);
     if (err < 0) {
-        err = -errno;
         goto out;
     }
-    vs->status = P9_LOCK_SUCCESS;
+    status = P9_LOCK_SUCCESS;
 out:
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "b", vs->status);
-    complete_pdu(s, vs->pdu, err);
-    g_free(vs->flock);
-    g_free(vs);
+    err = offset;
+    err += pdu_marshal(pdu, offset, "b", status);
+    complete_pdu(s, pdu, err);
+    g_free(flock);
 }
 
 /*
  * When a TGETLOCK request comes, always return success because all lock
  * handling is done by client's VFS layer.
  */
-
 static void v9fs_getlock(void *opaque)
 {
+    size_t offset = 7;
+    struct stat stbuf;
+    V9fsFidState *fidp;
+    V9fsGetlock *glock;
+    int32_t fid, err = 0;
     V9fsPDU *pdu = opaque;
     V9fsState *s = pdu->s;
-    int32_t fid, err = 0;
-    V9fsGetlockState *vs;
 
-    vs = g_malloc0(sizeof(*vs));
-    vs->pdu = pdu;
-    vs->offset = 7;
+    glock = g_malloc(sizeof(*glock));
+    pdu_unmarshal(pdu, offset, "dbqqds", &fid, &glock->type,
+                  &glock->start, &glock->length, &glock->proc_id,
+                  &glock->client_id);
 
-    vs->glock = g_malloc(sizeof(*vs->glock));
-    pdu_unmarshal(vs->pdu, vs->offset, "dbqqds", &fid, &vs->glock->type,
-                &vs->glock->start, &vs->glock->length, &vs->glock->proc_id,
-		&vs->glock->client_id);
-
-    vs->fidp = lookup_fid(s, fid);
-    if (vs->fidp == NULL) {
+    fidp = lookup_fid(s, fid);
+    if (fidp == NULL) {
         err = -ENOENT;
         goto out;
     }
-
-    err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf);
+    err = v9fs_co_fstat(s, fidp->fs.fd, &stbuf);
     if (err < 0) {
-        err = -errno;
         goto out;
     }
-    vs->glock->type = F_UNLCK;
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "bqqds", vs->glock->type,
-                vs->glock->start, vs->glock->length, vs->glock->proc_id,
-		&vs->glock->client_id);
+    glock->type = F_UNLCK;
+    offset += pdu_marshal(pdu, offset, "bqqds", glock->type,
+                          glock->start, glock->length, glock->proc_id,
+                          &glock->client_id);
+    err = offset;
 out:
-    complete_pdu(s, vs->pdu, err);
-    g_free(vs->glock);
-    g_free(vs);
+    complete_pdu(s, pdu, err);
+    g_free(glock);
 }
 
 static void v9fs_mkdir(void *opaque)
diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
index 46d79da..1d8c1b1 100644
--- a/hw/9pfs/virtio-9p.h
+++ b/hw/9pfs/virtio-9p.h
@@ -222,31 +222,6 @@
     int32_t msize;
 } V9fsState;
 
-typedef struct V9fsCreateState {
-    V9fsPDU *pdu;
-    size_t offset;
-    V9fsFidState *fidp;
-    V9fsQID qid;
-    int32_t perm;
-    int8_t mode;
-    struct stat stbuf;
-    V9fsString name;
-    V9fsString extension;
-    V9fsString fullname;
-    int iounit;
-} V9fsCreateState;
-
-typedef struct V9fsLcreateState {
-    V9fsPDU *pdu;
-    size_t offset;
-    V9fsFidState *fidp;
-    V9fsQID qid;
-    int32_t iounit;
-    struct stat stbuf;
-    V9fsString name;
-    V9fsString fullname;
-} V9fsLcreateState;
-
 typedef struct V9fsStatState {
     V9fsPDU *pdu;
     size_t offset;
@@ -278,19 +253,6 @@
     uint64_t st_data_version;
 } V9fsStatDotl;
 
-typedef struct V9fsWalkState {
-    V9fsPDU *pdu;
-    size_t offset;
-    uint16_t nwnames;
-    int name_idx;
-    V9fsQID *qids;
-    V9fsFidState *fidp;
-    V9fsFidState *newfidp;
-    V9fsString path;
-    V9fsString *wnames;
-    struct stat stbuf;
-} V9fsWalkState;
-
 typedef struct V9fsOpenState {
     V9fsPDU *pdu;
     size_t offset;
@@ -333,28 +295,6 @@
     int cnt;
 } V9fsWriteState;
 
-typedef struct V9fsWstatState
-{
-    V9fsPDU *pdu;
-    size_t offset;
-    int16_t unused;
-    V9fsStat v9stat;
-    V9fsFidState *fidp;
-    struct stat stbuf;
-} V9fsWstatState;
-
-typedef struct V9fsSymlinkState
-{
-    V9fsPDU *pdu;
-    size_t offset;
-    V9fsString name;
-    V9fsString symname;
-    V9fsString fullname;
-    V9fsFidState *dfidp;
-    V9fsQID qid;
-    struct stat stbuf;
-} V9fsSymlinkState;
-
 typedef struct V9fsIattr
 {
     int32_t valid;
@@ -403,16 +343,6 @@
     V9fsString client_id;
 } V9fsFlock;
 
-typedef struct V9fsLockState
-{
-    V9fsPDU *pdu;
-    size_t offset;
-    int8_t status;
-    struct stat stbuf;
-    V9fsFidState *fidp;
-    V9fsFlock *flock;
-} V9fsLockState;
-
 typedef struct V9fsGetlock
 {
     uint8_t type;
@@ -422,15 +352,6 @@
     V9fsString client_id;
 } V9fsGetlock;
 
-typedef struct V9fsGetlockState
-{
-    V9fsPDU *pdu;
-    size_t offset;
-    struct stat stbuf;
-    V9fsFidState *fidp;
-    V9fsGetlock *glock;
-} V9fsGetlockState;
-
 size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count,
                       size_t offset, size_t size, int pack);
 
diff --git a/hw/g364fb.c b/hw/g364fb.c
index b3020c5..5e7bcfa 100644
--- a/hw/g364fb.c
+++ b/hw/g364fb.c
@@ -1,7 +1,7 @@
 /*
  * QEMU G364 framebuffer Emulator.
  *
- * Copyright (c) 2007-2009 Herve Poussineau
+ * Copyright (c) 2007-2011 Herve Poussineau
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -18,27 +18,18 @@
  */
 
 #include "hw.h"
-#include "mips.h"
 #include "console.h"
 #include "pixel_ops.h"
-
-//#define DEBUG_G364
-
-#ifdef DEBUG_G364
-#define DPRINTF(fmt, ...) \
-do { printf("g364: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while (0)
-#endif
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "g364 ERROR: " fmt , ## __VA_ARGS__);} while (0)
+#include "trace.h"
+#include "sysbus.h"
 
 typedef struct G364State {
     /* hardware */
     uint8_t *vram;
-    ram_addr_t vram_offset;
-    int vram_size;
+    uint32_t vram_size;
     qemu_irq irq;
+    MemoryRegion mem_vram;
+    MemoryRegion mem_ctrl;
     /* registers */
     uint8_t color_palette[256][3];
     uint8_t cursor_palette[3][3];
@@ -53,31 +44,32 @@
     int blanked;
 } G364State;
 
-#define REG_ID       0x000000
-#define REG_BOOT     0x080000
-#define REG_DISPLAY  0x080118
-#define REG_VDISPLAY 0x080150
-#define REG_CTLA     0x080300
-#define REG_TOP      0x080400
-#define REG_CURS_PAL 0x080508
-#define REG_CURS_POS 0x080638
-#define REG_CLR_PAL  0x080800
-#define REG_CURS_PAT 0x081000
-#define REG_RESET    0x180000
+#define REG_BOOT     0x000000
+#define REG_DISPLAY  0x000118
+#define REG_VDISPLAY 0x000150
+#define REG_CTLA     0x000300
+#define REG_TOP      0x000400
+#define REG_CURS_PAL 0x000508
+#define REG_CURS_POS 0x000638
+#define REG_CLR_PAL  0x000800
+#define REG_CURS_PAT 0x001000
+#define REG_RESET    0x100000
 
 #define CTLA_FORCE_BLANK 0x00000400
 #define CTLA_NO_CURSOR   0x00800000
 
-static inline int check_dirty(ram_addr_t page)
+static inline int check_dirty(G364State *s, ram_addr_t page)
 {
-    return cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG);
+    return memory_region_get_dirty(&s->mem_vram, page, DIRTY_MEMORY_VGA);
 }
 
 static inline void reset_dirty(G364State *s,
                                ram_addr_t page_min, ram_addr_t page_max)
 {
-    cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE - 1,
-                                    VGA_DIRTY_FLAG);
+    memory_region_reset_dirty(&s->mem_vram,
+                              page_min,
+                              page_max + TARGET_PAGE_SIZE - page_min - 1,
+                              DIRTY_MEMORY_VGA);
 }
 
 static void g364fb_draw_graphic8(G364State *s)
@@ -110,11 +102,12 @@
             w = 4;
             break;
         default:
-            BADF("unknown host depth %d\n", ds_get_bits_per_pixel(s->ds));
+            hw_error("g364: unknown host depth %d",
+                     ds_get_bits_per_pixel(s->ds));
             return;
     }
 
-    page = s->vram_offset;
+    page = 0;
     page_min = (ram_addr_t)-1;
     page_max = 0;
 
@@ -135,7 +128,7 @@
     /* XXX: out of range in vram? */
     data_display = dd = ds_get_data(s->ds);
     while (y < s->height) {
-        if (check_dirty(page)) {
+        if (check_dirty(s, page)) {
             if (y < ymin)
                 ymin = ymax = y;
             if (page_min == (ram_addr_t)-1)
@@ -262,7 +255,7 @@
     } else if (s->depth == 8) {
         g364fb_draw_graphic8(s);
     } else {
-        BADF("unknown guest depth %d\n", s->depth);
+        error_report("g364: unknown guest depth %d", s->depth);
     }
 
     qemu_irq_raise(s->irq);
@@ -275,13 +268,12 @@
 
     s->blanked = 0;
     for (i = 0; i < s->vram_size; i += TARGET_PAGE_SIZE) {
-        cpu_physical_memory_set_dirty(s->vram_offset + i);
+        memory_region_set_dirty(&s->mem_vram, i);
     }
 }
 
-static void g364fb_reset(void *opaque)
+static void g364fb_reset(G364State *s)
 {
-    G364State *s = opaque;
     qemu_irq_lower(s->irq);
 
     memset(s->color_palette, 0, sizeof(s->color_palette));
@@ -292,7 +284,7 @@
     s->top_of_screen = 0;
     s->width = s->height = 0;
     memset(s->vram, 0, s->vram_size);
-    g364fb_invalidate_display(opaque);
+    g364fb_invalidate_display(s);
 }
 
 static void g364fb_screen_dump(void *opaque, const char *filename)
@@ -304,7 +296,7 @@
     FILE *f;
 
     if (s->depth != 8) {
-        BADF("unknown guest depth %d\n", s->depth);
+        error_report("g364: unknown guest depth %d", s->depth);
         return;
     }
 
@@ -336,7 +328,9 @@
 }
 
 /* called for accesses to io ports */
-static uint32_t g364fb_ctrl_readl(void *opaque, target_phys_addr_t addr)
+static uint64_t g364fb_ctrl_read(void *opaque,
+                                 target_phys_addr_t addr,
+                                 unsigned int size)
 {
     G364State *s = opaque;
     uint32_t val;
@@ -353,9 +347,6 @@
         val |= ((uint32_t)s->cursor_palette[idx][2] << 0);
     } else {
         switch (addr) {
-            case REG_ID:
-                val = 0x10; /* Mips G364 */
-                break;
             case REG_DISPLAY:
                 val = s->width / 4;
                 break;
@@ -367,33 +358,19 @@
                 break;
             default:
             {
-                BADF("invalid read at [" TARGET_FMT_plx "]\n", addr);
+                error_report("g364: invalid read at [" TARGET_FMT_plx "]",
+                             addr);
                 val = 0;
                 break;
             }
         }
     }
 
-    DPRINTF("read 0x%08x at [" TARGET_FMT_plx "]\n", val, addr);
+    trace_g364fb_read(addr, val);
 
     return val;
 }
 
-static uint32_t g364fb_ctrl_readw(void *opaque, target_phys_addr_t addr)
-{
-    uint32_t v = g364fb_ctrl_readl(opaque, addr & ~0x3);
-    if (addr & 0x2)
-        return v >> 16;
-    else
-        return v & 0xffff;
-}
-
-static uint32_t g364fb_ctrl_readb(void *opaque, target_phys_addr_t addr)
-{
-    uint32_t v = g364fb_ctrl_readl(opaque, addr & ~0x3);
-    return (v >> (8 * (addr & 0x3))) & 0xff;
-}
-
 static void g364fb_update_depth(G364State *s)
 {
     static const int depths[8] = { 1, 2, 4, 8, 15, 16, 0 };
@@ -411,15 +388,18 @@
     end = (ymax + 1) * ds_get_linesize(s->ds);
 
     for (i = start; i < end; i += TARGET_PAGE_SIZE) {
-        cpu_physical_memory_set_dirty(s->vram_offset + i);
+        memory_region_set_dirty(&s->mem_vram, i);
     }
 }
 
-static void g364fb_ctrl_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+static void g364fb_ctrl_write(void *opaque,
+                              target_phys_addr_t addr,
+                              uint64_t val,
+                              unsigned int size)
 {
     G364State *s = opaque;
 
-    DPRINTF("write 0x%08x at [" TARGET_FMT_plx "]\n", val, addr);
+    trace_g364fb_write(addr, val);
 
     if (addr >= REG_CLR_PAL && addr < REG_CLR_PAL + 0x800) {
         /* color palette */
@@ -442,120 +422,65 @@
         g364fb_invalidate_display(s);
     } else {
         switch (addr) {
-            case REG_ID: /* Card identifier; read-only */
-            case REG_BOOT: /* Boot timing */
-            case 0x80108: /* Line timing: half sync */
-            case 0x80110: /* Line timing: back porch */
-            case 0x80120: /* Line timing: short display */
-            case 0x80128: /* Frame timing: broad pulse */
-            case 0x80130: /* Frame timing: v sync */
-            case 0x80138: /* Frame timing: v preequalise */
-            case 0x80140: /* Frame timing: v postequalise */
-            case 0x80148: /* Frame timing: v blank */
-            case 0x80158: /* Line timing: line time */
-            case 0x80160: /* Frame store: line start */
-            case 0x80168: /* vram cycle: mem init */
-            case 0x80170: /* vram cycle: transfer delay */
-            case 0x80200: /* vram cycle: mask register */
-                /* ignore */
-                break;
-            case REG_TOP:
-                s->top_of_screen = val;
-                g364fb_invalidate_display(s);
-                break;
-            case REG_DISPLAY:
-                s->width = val * 4;
-                break;
-            case REG_VDISPLAY:
-                s->height = val / 2;
-                break;
-            case REG_CTLA:
-                s->ctla = val;
-                g364fb_update_depth(s);
-                g364fb_invalidate_display(s);
-                break;
-            case REG_CURS_POS:
-                g364_invalidate_cursor_position(s);
-                s->cursor_position = val;
-                g364_invalidate_cursor_position(s);
-                break;
-            case REG_RESET:
-                g364fb_reset(s);
-                break;
-            default:
-                BADF("invalid write of 0x%08x at [" TARGET_FMT_plx "]\n", val, addr);
-                break;
+        case REG_BOOT: /* Boot timing */
+        case 0x00108: /* Line timing: half sync */
+        case 0x00110: /* Line timing: back porch */
+        case 0x00120: /* Line timing: short display */
+        case 0x00128: /* Frame timing: broad pulse */
+        case 0x00130: /* Frame timing: v sync */
+        case 0x00138: /* Frame timing: v preequalise */
+        case 0x00140: /* Frame timing: v postequalise */
+        case 0x00148: /* Frame timing: v blank */
+        case 0x00158: /* Line timing: line time */
+        case 0x00160: /* Frame store: line start */
+        case 0x00168: /* vram cycle: mem init */
+        case 0x00170: /* vram cycle: transfer delay */
+        case 0x00200: /* vram cycle: mask register */
+            /* ignore */
+            break;
+        case REG_TOP:
+            s->top_of_screen = val;
+            g364fb_invalidate_display(s);
+            break;
+        case REG_DISPLAY:
+            s->width = val * 4;
+            break;
+        case REG_VDISPLAY:
+            s->height = val / 2;
+            break;
+        case REG_CTLA:
+            s->ctla = val;
+            g364fb_update_depth(s);
+            g364fb_invalidate_display(s);
+            break;
+        case REG_CURS_POS:
+            g364_invalidate_cursor_position(s);
+            s->cursor_position = val;
+            g364_invalidate_cursor_position(s);
+            break;
+        case REG_RESET:
+            g364fb_reset(s);
+            break;
+        default:
+            error_report("g364: invalid write of 0x%" PRIx64
+                         " at [" TARGET_FMT_plx "]", val, addr);
+            break;
         }
     }
     qemu_irq_lower(s->irq);
 }
 
-static void g364fb_ctrl_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    uint32_t old_val = g364fb_ctrl_readl(opaque, addr & ~0x3);
-
-    if (addr & 0x2)
-        val = (val << 16) | (old_val & 0x0000ffff);
-    else
-        val = val | (old_val & 0xffff0000);
-    g364fb_ctrl_writel(opaque, addr & ~0x3, val);
-}
-
-static void g364fb_ctrl_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    uint32_t old_val = g364fb_ctrl_readl(opaque, addr & ~0x3);
-
-    switch (addr & 3) {
-    case 0:
-        val = val | (old_val & 0xffffff00);
-        break;
-    case 1:
-        val = (val << 8) | (old_val & 0xffff00ff);
-        break;
-    case 2:
-        val = (val << 16) | (old_val & 0xff00ffff);
-        break;
-    case 3:
-        val = (val << 24) | (old_val & 0x00ffffff);
-        break;
-    }
-    g364fb_ctrl_writel(opaque, addr & ~0x3, val);
-}
-
-static CPUReadMemoryFunc * const g364fb_ctrl_read[3] = {
-    g364fb_ctrl_readb,
-    g364fb_ctrl_readw,
-    g364fb_ctrl_readl,
+static const MemoryRegionOps g364fb_ctrl_ops = {
+    .read = g364fb_ctrl_read,
+    .write = g364fb_ctrl_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl.min_access_size = 4,
+    .impl.max_access_size = 4,
 };
 
-static CPUWriteMemoryFunc * const g364fb_ctrl_write[3] = {
-    g364fb_ctrl_writeb,
-    g364fb_ctrl_writew,
-    g364fb_ctrl_writel,
-};
-
-static int g364fb_load(QEMUFile *f, void *opaque, int version_id)
+static int g364fb_post_load(void *opaque, int version_id)
 {
     G364State *s = opaque;
-    unsigned int i, vram_size;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    vram_size = qemu_get_be32(f);
-    if (vram_size < s->vram_size)
-        return -EINVAL;
-    qemu_get_buffer(f, s->vram, s->vram_size);
-    for (i = 0; i < 256; i++)
-        qemu_get_buffer(f, s->color_palette[i], 3);
-    for (i = 0; i < 3; i++)
-        qemu_get_buffer(f, s->cursor_palette[i], 3);
-    qemu_get_buffer(f, (uint8_t *)s->cursor, sizeof(s->cursor));
-    s->cursor_position = qemu_get_be32(f);
-    s->ctla = qemu_get_be32(f);
-    s->top_of_screen = qemu_get_be32(f);
-    s->width = qemu_get_be32(f);
-    s->height = qemu_get_be32(f);
 
     /* force refresh */
     g364fb_update_depth(s);
@@ -564,52 +489,80 @@
     return 0;
 }
 
-static void g364fb_save(QEMUFile *f, void *opaque)
+static const VMStateDescription vmstate_g364fb = {
+    .name = "g364fb",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = g364fb_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_VBUFFER_UINT32(vram, G364State, 1, NULL, 0, vram_size),
+        VMSTATE_BUFFER_UNSAFE(color_palette, G364State, 0, 256 * 3),
+        VMSTATE_BUFFER_UNSAFE(cursor_palette, G364State, 0, 9),
+        VMSTATE_UINT16_ARRAY(cursor, G364State, 512),
+        VMSTATE_UINT32(cursor_position, G364State),
+        VMSTATE_UINT32(ctla, G364State),
+        VMSTATE_UINT32(top_of_screen, G364State),
+        VMSTATE_UINT32(width, G364State),
+        VMSTATE_UINT32(height, G364State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void g364fb_init(DeviceState *dev, G364State *s)
 {
-    G364State *s = opaque;
-    int i;
-
-    qemu_put_be32(f, s->vram_size);
-    qemu_put_buffer(f, s->vram, s->vram_size);
-    for (i = 0; i < 256; i++)
-        qemu_put_buffer(f, s->color_palette[i], 3);
-    for (i = 0; i < 3; i++)
-        qemu_put_buffer(f, s->cursor_palette[i], 3);
-    qemu_put_buffer(f, (uint8_t *)s->cursor, sizeof(s->cursor));
-    qemu_put_be32(f, s->cursor_position);
-    qemu_put_be32(f, s->ctla);
-    qemu_put_be32(f, s->top_of_screen);
-    qemu_put_be32(f, s->width);
-    qemu_put_be32(f, s->height);
-}
-
-int g364fb_mm_init(target_phys_addr_t vram_base,
-                   target_phys_addr_t ctrl_base, int it_shift,
-                   qemu_irq irq)
-{
-    G364State *s;
-    int io_ctrl;
-
-    s = g_malloc0(sizeof(G364State));
-
-    s->vram_size = 8 * 1024 * 1024;
-    s->vram_offset = qemu_ram_alloc(NULL, "g364fb.vram", s->vram_size);
-    s->vram = qemu_get_ram_ptr(s->vram_offset);
-    s->irq = irq;
-
-    qemu_register_reset(g364fb_reset, s);
-    register_savevm(NULL, "g364fb", 0, 1, g364fb_save, g364fb_load, s);
-    g364fb_reset(s);
+    s->vram = g_malloc0(s->vram_size);
 
     s->ds = graphic_console_init(g364fb_update_display,
                                  g364fb_invalidate_display,
                                  g364fb_screen_dump, NULL, s);
 
-    cpu_register_physical_memory(vram_base, s->vram_size, s->vram_offset);
+    memory_region_init_io(&s->mem_ctrl, &g364fb_ctrl_ops, s, "ctrl", 0x180000);
+    memory_region_init_ram_ptr(&s->mem_vram, dev, "vram",
+                               s->vram_size, s->vram);
+    memory_region_set_coalescing(&s->mem_vram);
+}
 
-    io_ctrl = cpu_register_io_memory(g364fb_ctrl_read, g364fb_ctrl_write, s,
-                                     DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(ctrl_base, 0x200000, io_ctrl);
+typedef struct {
+    SysBusDevice busdev;
+    G364State g364;
+} G364SysBusState;
+
+static int g364fb_sysbus_init(SysBusDevice *dev)
+{
+    G364State *s = &FROM_SYSBUS(G364SysBusState, dev)->g364;
+
+    g364fb_init(&dev->qdev, s);
+    sysbus_init_irq(dev, &s->irq);
+    sysbus_init_mmio_region(dev, &s->mem_ctrl);
+    sysbus_init_mmio_region(dev, &s->mem_vram);
 
     return 0;
 }
+
+static void g364fb_sysbus_reset(DeviceState *d)
+{
+    G364SysBusState *s = DO_UPCAST(G364SysBusState, busdev.qdev, d);
+    g364fb_reset(&s->g364);
+}
+
+static SysBusDeviceInfo g364fb_sysbus_info = {
+    .init = g364fb_sysbus_init,
+    .qdev.name = "sysbus-g364",
+    .qdev.desc = "G364 framebuffer",
+    .qdev.size = sizeof(G364SysBusState),
+    .qdev.vmsd = &vmstate_g364fb,
+    .qdev.reset = g364fb_sysbus_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_HEX32("vram_size", G364SysBusState, g364.vram_size,
+                          8 * 1024 * 1024),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void g364fb_register(void)
+{
+    sysbus_register_withprop(&g364fb_sysbus_info);
+}
+
+device_init(g364fb_register);
diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c
index 6af9782..1c34253 100644
--- a/hw/gt64xxx.c
+++ b/hw/gt64xxx.c
@@ -297,7 +297,11 @@
       s->PCI0IO_start = s->regs[GT_PCI0IOLD] << 21;
       s->PCI0IO_length = ((s->regs[GT_PCI0IOHD] + 1) - (s->regs[GT_PCI0IOLD] & 0x7f)) << 21;
       isa_mem_base = s->PCI0IO_start;
-      isa_mmio_init(s->PCI0IO_start, s->PCI0IO_length);
+      if (s->PCI0IO_length) {
+          isa_mmio_setup(&s->PCI0IO_mem, s->PCI0IO_length);
+          memory_region_add_subregion(get_system_memory(), s->PCI0IO_start,
+                                      &s->PCI0IO_mem);
+      }
     }
 }
 
diff --git a/hw/mips.h b/hw/mips.h
index cae5f4c..8ce41fc 100644
--- a/hw/mips.h
+++ b/hw/mips.h
@@ -8,11 +8,6 @@
 /* bonito.c */
 PCIBus *bonito_init(qemu_irq *pic);
 
-/* g364fb.c */
-int g364fb_mm_init(target_phys_addr_t vram_base,
-                   target_phys_addr_t ctrl_base, int it_shift,
-                   qemu_irq irq);
-
 /* mipsnet.c */
 void mipsnet_init(int base, qemu_irq irq, NICInfo *nd);
 
diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c
index 84ce061..f3c9f93 100644
--- a/hw/mips_jazz.c
+++ b/hw/mips_jazz.c
@@ -195,7 +195,20 @@
     /* Video card */
     switch (jazz_model) {
     case JAZZ_MAGNUM:
-        g364fb_mm_init(0x40000000, 0x60000000, 0, rc4030[3]);
+        dev = qdev_create(NULL, "sysbus-g364");
+        qdev_init_nofail(dev);
+        sysbus = sysbus_from_qdev(dev);
+        sysbus_mmio_map(sysbus, 0, 0x60080000);
+        sysbus_mmio_map(sysbus, 1, 0x40000000);
+        sysbus_connect_irq(sysbus, 0, rc4030[3]);
+        {
+            /* Simple ROM, so user doesn't have to provide one */
+            ram_addr_t rom_offset = qemu_ram_alloc(NULL, "g364fb.rom", 0x80000);
+            uint8_t *rom = qemu_get_ram_ptr(rom_offset);
+            cpu_register_physical_memory(0x60000000, 0x80000,
+                                         rom_offset | IO_MEM_ROM);
+            rom[0] = 0x10; /* Mips G364 */
+        }
         break;
     case JAZZ_PICA61:
         isa_vga_mm_init(0x40000000, 0x60000000, 0, get_system_memory());
diff --git a/hw/omap_gpmc.c b/hw/omap_gpmc.c
index 922d622..673dddd 100644
--- a/hw/omap_gpmc.c
+++ b/hw/omap_gpmc.c
@@ -135,7 +135,6 @@
                             s->cs_file[i].config[6] & 0x1f,	/* MASKADDR */
                         (s->cs_file[i].config[6] >> 8 & 0xf));	/* BASEADDR */
     }
-    omap_gpmc_cs_map(s->cs_file, 0, 0xf);
     s->ecc_cs = 0;
     s->ecc_ptr = 0;
     s->ecc_cfg = 0x3fcff000;
diff --git a/hw/pci.c b/hw/pci.c
index 6124790..57ff7b1 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -1811,6 +1811,25 @@
     return next;
 }
 
+static uint8_t pci_find_capability_at_offset(PCIDevice *pdev, uint8_t offset)
+{
+    uint8_t next, prev, found = 0;
+
+    if (!(pdev->used[offset])) {
+        return 0;
+    }
+
+    assert(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST);
+
+    for (prev = PCI_CAPABILITY_LIST; (next = pdev->config[prev]);
+         prev = next + PCI_CAP_LIST_NEXT) {
+        if (next <= offset && next > found) {
+            found = next;
+        }
+    }
+    return found;
+}
+
 /* Patch the PCI vendor and device ids in a PCI rom image if necessary.
    This is needed for an option rom which is used for more than one device. */
 static void pci_patch_ids(PCIDevice *pdev, uint8_t *ptr, int size)
@@ -1952,11 +1971,30 @@
                        uint8_t offset, uint8_t size)
 {
     uint8_t *config;
+    int i, overlapping_cap;
+
     if (!offset) {
         offset = pci_find_space(pdev, size);
         if (!offset) {
             return -ENOSPC;
         }
+    } else {
+        /* Verify that capabilities don't overlap.  Note: device assignment
+         * depends on this check to verify that the device is not broken.
+         * Should never trigger for emulated devices, but it's helpful
+         * for debugging these. */
+        for (i = offset; i < offset + size; i++) {
+            overlapping_cap = pci_find_capability_at_offset(pdev, i);
+            if (overlapping_cap) {
+                fprintf(stderr, "ERROR: %04x:%02x:%02x.%x "
+                        "Attempt to add PCI capability %x at offset "
+                        "%x overlaps existing capability %x at offset %x\n",
+                        pci_find_domain(pdev->bus), pci_bus_num(pdev->bus),
+                        PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
+                        cap_id, offset, overlapping_cap, i);
+                return -EINVAL;
+            }
+        }
     }
 
     config = pdev->config + offset;
diff --git a/hw/pcie.c b/hw/pcie.c
index 39607bf..5c9eb2f 100644
--- a/hw/pcie.c
+++ b/hw/pcie.c
@@ -175,6 +175,14 @@
     }
 }
 
+static void hotplug_event_clear(PCIDevice *dev)
+{
+    hotplug_event_update_event_status(dev);
+    if (!msix_enabled(dev) && !msi_enabled(dev) && !dev->exp.hpev_notified) {
+        qemu_set_irq(dev->irq[dev->exp.hpev_intx], 0);
+    }
+}
+
 /*
  * A PCI Express Hot-Plug Event has occurred, so update slot status register
  * and notify OS of the event if necessary.
@@ -320,6 +328,10 @@
     uint8_t *exp_cap = dev->config + pos;
     uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
 
+    if (ranges_overlap(addr, len, pos + PCI_EXP_SLTSTA, 2)) {
+        hotplug_event_clear(dev);
+    }
+
     if (!ranges_overlap(addr, len, pos + PCI_EXP_SLTCTL, 2)) {
         return;
     }
diff --git a/hw/pcie_aer.c b/hw/pcie_aer.c
index 2ae65ec..62c06ea 100644
--- a/hw/pcie_aer.c
+++ b/hw/pcie_aer.c
@@ -415,7 +415,7 @@
     int i;
 
     assert(err->status);
-    assert(err->status & (err->status - 1));
+    assert(!(err->status & (err->status - 1)));
 
     errcap &= ~(PCI_ERR_CAP_FEP_MASK | PCI_ERR_CAP_TLP);
     errcap |= PCI_ERR_CAP_FEP(first_bit);
@@ -495,7 +495,7 @@
     int fep = PCI_ERR_CAP_FEP(errcap);
 
     assert(err->status);
-    assert(err->status & (err->status - 1));
+    assert(!(err->status & (err->status - 1)));
 
     if (errcap & PCI_ERR_CAP_MHRE &&
         (pci_get_long(aer_cap + PCI_ERR_UNCOR_STATUS) & (1U << fep))) {
@@ -979,20 +979,21 @@
     if (pcie_aer_parse_error_string(error_name, &error_status, &correctable)) {
         char *e = NULL;
         error_status = strtoul(error_name, &e, 0);
-        correctable = !!qdict_get_int(qdict, "correctable");
+        correctable = qdict_get_try_bool(qdict, "correctable", 0);
         if (!e || *e != '\0') {
             monitor_printf(mon, "invalid error status value. \"%s\"",
                            error_name);
             return -EINVAL;
         }
     }
+    err.status = error_status;
     err.source_id = (pci_bus_num(dev->bus) << 8) | dev->devfn;
 
     err.flags = 0;
     if (correctable) {
         err.flags |= PCIE_AER_ERR_IS_CORRECTABLE;
     }
-    if (qdict_get_int(qdict, "advisory_non_fatal")) {
+    if (qdict_get_try_bool(qdict, "advisory_non_fatal", 0)) {
         err.flags |= PCIE_AER_ERR_MAYBE_ADVISORY;
     }
     if (qdict_haskey(qdict, "header0")) {
diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c
index 4727e07..fbd443d 100644
--- a/hw/ppc_newworld.c
+++ b/hw/ppc_newworld.c
@@ -146,6 +146,7 @@
     MacIONVRAMState *nvr;
     int bios_size;
     MemoryRegion *pic_mem, *dbdma_mem, *cuda_mem, *escc_mem;
+    MemoryRegion *escc_bar = g_new(MemoryRegion, 1);
     MemoryRegion *ide_mem[3];
     int ppc_boot_device;
     DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
@@ -328,6 +329,8 @@
 
     escc_mem = escc_init(0x80013000, pic[0x25], pic[0x24],
                          serial_hds[0], serial_hds[1], ESCC_CLOCK, 4);
+    memory_region_init_alias(escc_bar, "escc-bar",
+                             escc_mem, 0, memory_region_size(escc_mem));
 
     for(i = 0; i < nb_nics; i++)
         pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL);
@@ -350,7 +353,7 @@
     adb_mouse_init(&adb_bus);
 
     macio_init(pci_bus, PCI_DEVICE_ID_APPLE_UNI_N_KEYL, 0, pic_mem,
-               dbdma_mem, cuda_mem, NULL, 3, ide_mem, escc_mem);
+               dbdma_mem, cuda_mem, NULL, 3, ide_mem, escc_bar);
 
     if (usb_enabled) {
         usb_ohci_init_pci(pci_bus, -1);
diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c
index 0071fc9..235d2ef 100644
--- a/hw/ppc_oldworld.c
+++ b/hw/ppc_oldworld.c
@@ -83,7 +83,7 @@
     MacIONVRAMState *nvr;
     int bios_size;
     MemoryRegion *pic_mem, *dbdma_mem, *cuda_mem;
-    MemoryRegion *escc_mem, *ide_mem[2];
+    MemoryRegion *escc_mem, *escc_bar = g_new(MemoryRegion, 1), *ide_mem[2];
     uint16_t ppc_boot_device;
     DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
     void *fw_cfg;
@@ -241,6 +241,8 @@
 
     escc_mem = escc_init(0x80013000, pic[0x0f], pic[0x10], serial_hds[0],
                                serial_hds[1], ESCC_CLOCK, 4);
+    memory_region_init_alias(escc_bar, "escc-bar",
+                             escc_mem, 0, memory_region_size(escc_mem));
 
     for(i = 0; i < nb_nics; i++)
         pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL);
@@ -269,7 +271,7 @@
     pmac_format_nvram_partition(nvr, 0x2000);
 
     macio_init(pci_bus, PCI_DEVICE_ID_APPLE_343S1201, 1, pic_mem,
-               dbdma_mem, cuda_mem, nvr, 2, ide_mem, escc_mem);
+               dbdma_mem, cuda_mem, nvr, 2, ide_mem, escc_bar);
 
     if (usb_enabled) {
         usb_ohci_init_pci(pci_bus, -1);
diff --git a/hw/sh_pci.c b/hw/sh_pci.c
index 76061bb..36f3930 100644
--- a/hw/sh_pci.c
+++ b/hw/sh_pci.c
@@ -150,7 +150,7 @@
                               PCI_DEVFN(0, 0), 4);
     memory_region_init_io(&s->memconfig_p4, &sh_pci_reg_ops, s,
                           "sh_pci", 0x224);
-    memory_region_init_alias(&s->memconfig_a7, "sh_pci.2", &s->memconfig_a7,
+    memory_region_init_alias(&s->memconfig_a7, "sh_pci.2", &s->memconfig_p4,
                              0, 0x224);
     isa_mmio_setup(&s->isa, 0x40000);
     sysbus_init_mmio_cb2(dev, sh_pci_map, sh_pci_unmap);
diff --git a/hw/sun4u.c b/hw/sun4u.c
index 1b60e4e..32e6ab9 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -261,7 +261,9 @@
         pil |= 1 << 14;
     }
 
-    if (!pil) {
+    /* The bit corresponding to psrpil is (1<< psrpil), the next bit
+       is (2 << psrpil). */
+    if (pil < (2 << env->psrpil)){
         if (env->interrupt_request & CPU_INTERRUPT_HARD) {
             CPUIRQ_DPRINTF("Reset CPU IRQ (current interrupt %x)\n",
                            env->interrupt_index);
@@ -293,10 +295,12 @@
                 break;
             }
         }
-    } else {
+    } else if (env->interrupt_request & CPU_INTERRUPT_HARD) {
         CPUIRQ_DPRINTF("Interrupts disabled, pil=%08x pil_in=%08x softint=%08x "
                        "current interrupt %x\n",
                        pil, env->pil_in, env->softint, env->interrupt_index);
+        env->interrupt_index = 0;
+        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
     }
 }
 
diff --git a/hw/vga.c b/hw/vga.c
index 851fd68..125fb29 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -176,6 +176,7 @@
             size = 0x8000;
             break;
         case 3:
+        default:
             base = 0xb8000;
             size = 0x8000;
             break;
diff --git a/hw/vhost.c b/hw/vhost.c
index 1886067..0870cb7 100644
--- a/hw/vhost.c
+++ b/hw/vhost.c
@@ -515,11 +515,6 @@
     };
     struct VirtQueue *vvq = virtio_get_queue(vdev, idx);
 
-    if (!vdev->binding->set_host_notifier) {
-        fprintf(stderr, "binding does not support host notifiers\n");
-        return -ENOSYS;
-    }
-
     vq->num = state.num = virtio_queue_get_num(vdev, idx);
     r = ioctl(dev->control, VHOST_SET_VRING_NUM, &state);
     if (r) {
@@ -567,12 +562,6 @@
         r = -errno;
         goto fail_alloc;
     }
-    r = vdev->binding->set_host_notifier(vdev->binding_opaque, idx, true);
-    if (r < 0) {
-        fprintf(stderr, "Error binding host notifier: %d\n", -r);
-        goto fail_host_notifier;
-    }
-
     file.fd = event_notifier_get_fd(virtio_queue_get_host_notifier(vvq));
     r = ioctl(dev->control, VHOST_SET_VRING_KICK, &file);
     if (r) {
@@ -591,8 +580,6 @@
 
 fail_call:
 fail_kick:
-    vdev->binding->set_host_notifier(vdev->binding_opaque, idx, false);
-fail_host_notifier:
 fail_alloc:
     cpu_physical_memory_unmap(vq->ring, virtio_queue_get_ring_size(vdev, idx),
                               0, 0);
@@ -618,12 +605,6 @@
         .index = idx,
     };
     int r;
-    r = vdev->binding->set_host_notifier(vdev->binding_opaque, idx, false);
-    if (r < 0) {
-        fprintf(stderr, "vhost VQ %d host cleanup failed: %d\n", idx, r);
-        fflush(stderr);
-    }
-    assert (r >= 0);
     r = ioctl(dev->control, VHOST_GET_VRING_BASE, &state);
     if (r < 0) {
         fprintf(stderr, "vhost VQ %d ring restore failed: %d\n", idx, r);
@@ -697,6 +678,60 @@
         hdev->force;
 }
 
+/* Stop processing guest IO notifications in qemu.
+ * Start processing them in vhost in kernel.
+ */
+int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
+{
+    int i, r;
+    if (!vdev->binding->set_host_notifier) {
+        fprintf(stderr, "binding does not support host notifiers\n");
+        r = -ENOSYS;
+        goto fail;
+    }
+
+    for (i = 0; i < hdev->nvqs; ++i) {
+        r = vdev->binding->set_host_notifier(vdev->binding_opaque, i, true);
+        if (r < 0) {
+            fprintf(stderr, "vhost VQ %d notifier binding failed: %d\n", i, -r);
+            goto fail_vq;
+        }
+    }
+
+    return 0;
+fail_vq:
+    while (--i >= 0) {
+        r = vdev->binding->set_host_notifier(vdev->binding_opaque, i, false);
+        if (r < 0) {
+            fprintf(stderr, "vhost VQ %d notifier cleanup error: %d\n", i, -r);
+            fflush(stderr);
+        }
+        assert (r >= 0);
+    }
+fail:
+    return r;
+}
+
+/* Stop processing guest IO notifications in vhost.
+ * Start processing them in qemu.
+ * This might actually run the qemu handlers right away,
+ * so virtio in qemu must be completely setup when this is called.
+ */
+void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
+{
+    int i, r;
+
+    for (i = 0; i < hdev->nvqs; ++i) {
+        r = vdev->binding->set_host_notifier(vdev->binding_opaque, i, false);
+        if (r < 0) {
+            fprintf(stderr, "vhost VQ %d notifier cleanup failed: %d\n", i, -r);
+            fflush(stderr);
+        }
+        assert (r >= 0);
+    }
+}
+
+/* Host notifiers must be enabled at this point. */
 int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
 {
     int i, r;
@@ -762,6 +797,7 @@
     return r;
 }
 
+/* Host notifiers must be enabled at this point. */
 void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev)
 {
     int i, r;
diff --git a/hw/vhost.h b/hw/vhost.h
index c8c595a..c9452f0 100644
--- a/hw/vhost.h
+++ b/hw/vhost.h
@@ -46,5 +46,7 @@
 bool vhost_dev_query(struct vhost_dev *hdev, VirtIODevice *vdev);
 int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev);
 void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev);
+int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev);
+void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev);
 
 #endif
diff --git a/hw/vhost_net.c b/hw/vhost_net.c
index a559812..950a6b8 100644
--- a/hw/vhost_net.c
+++ b/hw/vhost_net.c
@@ -139,16 +139,22 @@
 {
     struct vhost_vring_file file = { };
     int r;
+
+    net->dev.nvqs = 2;
+    net->dev.vqs = net->vqs;
+
+    r = vhost_dev_enable_notifiers(&net->dev, dev);
+    if (r < 0) {
+        goto fail_notifiers;
+    }
     if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
         tap_set_vnet_hdr_len(net->vc,
                              sizeof(struct virtio_net_hdr_mrg_rxbuf));
     }
 
-    net->dev.nvqs = 2;
-    net->dev.vqs = net->vqs;
     r = vhost_dev_start(&net->dev, dev);
     if (r < 0) {
-        return r;
+        goto fail_start;
     }
 
     net->vc->info->poll(net->vc, false);
@@ -173,6 +179,9 @@
     if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
         tap_set_vnet_hdr_len(net->vc, sizeof(struct virtio_net_hdr));
     }
+fail_start:
+    vhost_dev_disable_notifiers(&net->dev, dev);
+fail_notifiers:
     return r;
 }
 
@@ -190,6 +199,7 @@
     if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
         tap_set_vnet_hdr_len(net->vc, sizeof(struct virtio_net_hdr));
     }
+    vhost_dev_disable_notifiers(&net->dev, dev);
 }
 
 void vhost_net_cleanup(struct vhost_net *net)
diff --git a/hw/xilinx_ethlite.c b/hw/xilinx_ethlite.c
index f35ba84..6f44c84 100644
--- a/hw/xilinx_ethlite.c
+++ b/hw/xilinx_ethlite.c
@@ -50,6 +50,7 @@
 struct xlx_ethlite
 {
     SysBusDevice busdev;
+    MemoryRegion mmio;
     qemu_irq irq;
     NICState *nic;
     NICConf conf;
@@ -70,7 +71,8 @@
     }
 }
 
-static uint32_t eth_readl (void *opaque, target_phys_addr_t addr)
+static uint64_t
+eth_read(void *opaque, target_phys_addr_t addr, unsigned int size)
 {
     struct xlx_ethlite *s = opaque;
     uint32_t r = 0;
@@ -98,10 +100,12 @@
 }
 
 static void
-eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+eth_write(void *opaque, target_phys_addr_t addr,
+          uint64_t val64, unsigned int size)
 {
     struct xlx_ethlite *s = opaque;
     unsigned int base = 0;
+    uint32_t value = val64;
 
     addr >>= 2;
     switch (addr) 
@@ -146,12 +150,14 @@
     }
 }
 
-static CPUReadMemoryFunc * const eth_read[] = {
-    NULL, NULL, &eth_readl,
-};
-
-static CPUWriteMemoryFunc * const eth_write[] = {
-    NULL, NULL, &eth_writel,
+static const MemoryRegionOps eth_ops = {
+    .read = eth_read,
+    .write = eth_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
 };
 
 static int eth_can_rx(VLANClientState *nc)
@@ -206,13 +212,12 @@
 static int xilinx_ethlite_init(SysBusDevice *dev)
 {
     struct xlx_ethlite *s = FROM_SYSBUS(typeof (*s), dev);
-    int regs;
 
     sysbus_init_irq(dev, &s->irq);
     s->rxbuf = 0;
 
-    regs = cpu_register_io_memory(eth_read, eth_write, s, DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, R_MAX * 4, regs);
+    memory_region_init_io(&s->mmio, &eth_ops, s, "xilinx-ethlite", R_MAX * 4);
+    sysbus_init_mmio_region(dev, &s->mmio);
 
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
     s->nic = qemu_new_nic(&net_xilinx_ethlite_info, &s->conf,
diff --git a/hw/xilinx_intc.c b/hw/xilinx_intc.c
index cb72d5a..58b73d9 100644
--- a/hw/xilinx_intc.c
+++ b/hw/xilinx_intc.c
@@ -40,6 +40,7 @@
 struct xlx_pic
 {
     SysBusDevice busdev;
+    MemoryRegion mmio;
     qemu_irq parent_irq;
 
     /* Configuration reg chosen at synthesis-time. QEMU populates
@@ -72,7 +73,8 @@
     }
 }
 
-static uint32_t pic_readl (void *opaque, target_phys_addr_t addr)
+static uint64_t
+pic_read(void *opaque, target_phys_addr_t addr, unsigned int size)
 {
     struct xlx_pic *p = opaque;
     uint32_t r = 0;
@@ -91,9 +93,11 @@
 }
 
 static void
-pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+pic_write(void *opaque, target_phys_addr_t addr,
+          uint64_t val64, unsigned int size)
 {
     struct xlx_pic *p = opaque;
+    uint32_t value = val64;
 
     addr >>= 2;
     D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value));
@@ -116,14 +120,14 @@
     update_irq(p);
 }
 
-static CPUReadMemoryFunc * const pic_read[] = {
-    NULL, NULL,
-    &pic_readl,
-};
-
-static CPUWriteMemoryFunc * const pic_write[] = {
-    NULL, NULL,
-    &pic_writel,
+static const MemoryRegionOps pic_ops = {
+    .read = pic_read,
+    .write = pic_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
 };
 
 static void irq_handler(void *opaque, int irq, int level)
@@ -148,13 +152,12 @@
 static int xilinx_intc_init(SysBusDevice *dev)
 {
     struct xlx_pic *p = FROM_SYSBUS(typeof (*p), dev);
-    int pic_regs;
 
     qdev_init_gpio_in(&dev->qdev, irq_handler, 32);
     sysbus_init_irq(dev, &p->parent_irq);
 
-    pic_regs = cpu_register_io_memory(pic_read, pic_write, p, DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, R_MAX * 4, pic_regs);
+    memory_region_init_io(&p->mmio, &pic_ops, p, "xilinx-pic", R_MAX * 4);
+    sysbus_init_mmio_region(dev, &p->mmio);
     return 0;
 }
 
diff --git a/hw/xilinx_timer.c b/hw/xilinx_timer.c
index f1c7abc..8779c56 100644
--- a/hw/xilinx_timer.c
+++ b/hw/xilinx_timer.c
@@ -59,6 +59,7 @@
 struct timerblock
 {
     SysBusDevice busdev;
+    MemoryRegion mmio;
     qemu_irq irq;
     uint32_t nr_timers;
     uint32_t freq_hz;
@@ -85,7 +86,8 @@
     qemu_set_irq(t->irq, !!irq);
 }
 
-static uint32_t timer_readl (void *opaque, target_phys_addr_t addr)
+static uint64_t
+timer_read(void *opaque, target_phys_addr_t addr, unsigned int size)
 {
     struct timerblock *t = opaque;
     struct xlx_timer *xt;
@@ -134,11 +136,13 @@
 }
 
 static void
-timer_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+timer_write(void *opaque, target_phys_addr_t addr,
+            uint64_t val64, unsigned int size)
 {
     struct timerblock *t = opaque;
     struct xlx_timer *xt;
     unsigned int timer;
+    uint32_t value = val64;
 
     addr >>= 2;
     timer = timer_from_addr(addr);
@@ -166,14 +170,14 @@
     timer_update_irq(t);
 }
 
-static CPUReadMemoryFunc * const timer_read[] = {
-    NULL, NULL,
-    &timer_readl,
-};
-
-static CPUWriteMemoryFunc * const timer_write[] = {
-    NULL, NULL,
-    &timer_writel,
+static const MemoryRegionOps timer_ops = {
+    .read = timer_read,
+    .write = timer_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
 };
 
 static void timer_hit(void *opaque)
@@ -192,7 +196,6 @@
 {
     struct timerblock *t = FROM_SYSBUS(typeof (*t), dev);
     unsigned int i;
-    int timer_regs;
 
     /* All timers share a single irq line.  */
     sysbus_init_irq(dev, &t->irq);
@@ -209,9 +212,9 @@
         ptimer_set_freq(xt->ptimer, t->freq_hz);
     }
 
-    timer_regs = cpu_register_io_memory(timer_read, timer_write, t,
-                                        DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, R_MAX * 4 * t->nr_timers, timer_regs);
+    memory_region_init_io(&t->mmio, &timer_ops, t, "xilinx-timer",
+                          R_MAX * 4 * t->nr_timers);
+    sysbus_init_mmio_region(dev, &t->mmio);
     return 0;
 }
 
diff --git a/hw/xilinx_uartlite.c b/hw/xilinx_uartlite.c
index 467a26c..ceb7b4d 100644
--- a/hw/xilinx_uartlite.c
+++ b/hw/xilinx_uartlite.c
@@ -49,6 +49,7 @@
 struct xlx_uartlite
 {
     SysBusDevice busdev;
+    MemoryRegion mmio;
     CharDriverState *chr;
     qemu_irq irq;
 
@@ -82,7 +83,8 @@
     s->regs[R_STATUS] = r;
 }
 
-static uint32_t uart_readl (void *opaque, target_phys_addr_t addr)
+static uint64_t
+uart_read(void *opaque, target_phys_addr_t addr, unsigned int size)
 {
     struct xlx_uartlite *s = opaque;
     uint32_t r = 0;
@@ -107,9 +109,11 @@
 }
 
 static void
-uart_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+uart_write(void *opaque, target_phys_addr_t addr,
+           uint64_t val64, unsigned int size)
 {
     struct xlx_uartlite *s = opaque;
+    uint32_t value = val64;
     unsigned char ch = value;
 
     addr >>= 2;
@@ -147,16 +151,14 @@
     uart_update_irq(s);
 }
 
-static CPUReadMemoryFunc * const uart_read[] = {
-    &uart_readl,
-    &uart_readl,
-    &uart_readl,
-};
-
-static CPUWriteMemoryFunc * const uart_write[] = {
-    &uart_writel,
-    &uart_writel,
-    &uart_writel,
+static const MemoryRegionOps uart_ops = {
+    .read = uart_read,
+    .write = uart_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 4
+    }
 };
 
 static void uart_rx(void *opaque, const uint8_t *buf, int size)
@@ -196,14 +198,12 @@
 static int xilinx_uartlite_init(SysBusDevice *dev)
 {
     struct xlx_uartlite *s = FROM_SYSBUS(typeof (*s), dev);
-    int uart_regs;
 
     sysbus_init_irq(dev, &s->irq);
 
     uart_update_status(s);
-    uart_regs = cpu_register_io_memory(uart_read, uart_write, s,
-                                       DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, R_MAX * 4, uart_regs);
+    memory_region_init_io(&s->mmio, &uart_ops, s, "xilinx-uartlite", R_MAX * 4);
+    sysbus_init_mmio_region(dev, &s->mmio);
 
     s->chr = qdev_init_chardev(&dev->qdev);
     if (s->chr)
diff --git a/i386.ld b/i386.ld
index f8df7bf..cc3f160 100644
--- a/i386.ld
+++ b/i386.ld
@@ -42,16 +42,16 @@
   .rel.plt      :
   {
     *(.rel.plt)
-    PROVIDE_HIDDEN (__rel_iplt_start = .);
+    PROVIDE (__rel_iplt_start = .);
     *(.rel.iplt)
-    PROVIDE_HIDDEN (__rel_iplt_end = .);
+    PROVIDE (__rel_iplt_end = .);
   }
   .rela.plt       :
   {
     *(.rela.plt)
-    PROVIDE_HIDDEN (__rela_iplt_start = .);
+    PROVIDE (__rela_iplt_start = .);
     *(.rela.iplt)
-    PROVIDE_HIDDEN (__rela_iplt_end = .);
+    PROVIDE (__rela_iplt_end = .);
   }
   .init          : { *(.init)	} =0x47ff041f
   .text      :
diff --git a/libcacard/Makefile b/libcacard/Makefile
index b3f5e6c..bf052bc 100644
--- a/libcacard/Makefile
+++ b/libcacard/Makefile
@@ -20,7 +20,7 @@
 libcacard.lib-y=$(addsuffix .lo,$(basename $(libcacard-y)))
 
 vscclient: $(libcacard-y) $(QEMU_OBJS) vscclient.o
-	$(call quiet-command,$(CC) -o $@ $^ $(libcacard_libs) $(LIBS) -lrt,"  LINK  $@")
+	$(call quiet-command,$(CC) -o $@ $^ $(libcacard_libs) $(LIBS),"  LINK  $@")
 
 clean:
 	rm -f *.o */*.o *.d */*.d *.a */*.a *~ */*~ vscclient *.lo .libs/* *.la *.pc
@@ -39,7 +39,7 @@
 	@echo "libtool is missing, please install and rerun configure"; exit 1
 else
 libcacard.la: $(libcacard.lib-y) $(QEMU_OBJS_LIB)
-	$(call quiet-command,$(LIBTOOL) --mode=link --quiet --tag=CC $(CC) -rpath $(libdir) -o $@ $^ $(libcacard_libs) -lrt,"  lt LINK $@")
+	$(call quiet-command,$(LIBTOOL) --mode=link --quiet --tag=CC $(CC) -rpath $(libdir) -o $@ $^ $(libcacard_libs),"  lt LINK $@")
 
 libcacard.pc: $(libcacard_srcpath)/libcacard.pc.in
 	sed -e 's|@LIBDIR@|$(libdir)|' \
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 07ad07a..89276eb 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -3064,10 +3064,10 @@
         goto give_sigsegv;
 
     /* Set up registers for signal handler */
-    regs->gregs[15] = (unsigned long) frame;
+    regs->gregs[15] = frame_addr;
     regs->gregs[4] = signal; /* Arg for signal handler */
     regs->gregs[5] = 0;
-    regs->gregs[6] = (unsigned long) &frame->sc;
+    regs->gregs[6] = frame_addr += offsetof(typeof(*frame), sc);
     regs->pc = (unsigned long) ka->_sa_handler;
 
     unlock_user_struct(frame, frame_addr, 1);
@@ -3127,10 +3127,10 @@
         goto give_sigsegv;
 
     /* Set up registers for signal handler */
-    regs->gregs[15] = (unsigned long) frame;
+    regs->gregs[15] = frame_addr;
     regs->gregs[4] = signal; /* Arg for signal handler */
-    regs->gregs[5] = (unsigned long) &frame->info;
-    regs->gregs[6] = (unsigned long) &frame->uc;
+    regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info);
+    regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc);
     regs->pc = (unsigned long) ka->_sa_handler;
 
     unlock_user_struct(frame, frame_addr, 1);
@@ -3381,11 +3381,12 @@
         goto badframe;
 
     /* Set up registers for signal handler */
-    env->regs[1] = (unsigned long) frame;
+    env->regs[1] = frame_addr;
     /* Signal handler args: */
     env->regs[5] = sig; /* Arg 0: signum */
     env->regs[6] = 0;
-    env->regs[7] = (unsigned long) &frame->uc; /* arg 1: sigcontext */
+    /* arg 1: sigcontext */
+    env->regs[7] = frame_addr += offsetof(typeof(*frame), uc);
 
     /* Offset of 4 to handle microblaze rtid r14, 0 */
     env->sregs[SR_PC] = (unsigned long)ka->_sa_handler;
@@ -3559,11 +3560,11 @@
 	setup_sigcontext(&frame->sc, env);
 
 	/* Move the stack and setup the arguments for the handler.  */
-	env->regs[R_SP] = (uint32_t) (unsigned long) frame;
+	env->regs[R_SP] = frame_addr;
 	env->regs[10] = sig;
 	env->pc = (unsigned long) ka->_sa_handler;
 	/* Link SRP so the guest returns through the trampoline.  */
-	env->pregs[PR_SRP] = (uint32_t) (unsigned long) &frame->retcode[0];
+	env->pregs[PR_SRP] = frame_addr + offsetof(typeof(*frame), retcode);
 
 	unlock_user_struct(frame, frame_addr, 1);
 	return;
@@ -3769,11 +3770,11 @@
     }
 
     /* Set up registers for signal handler */
-    env->regs[15] = (target_ulong)(unsigned long) frame;
+    env->regs[15] = frame_addr;
     env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
 
     env->regs[2] = sig; //map_signal(sig);
-    env->regs[3] = (target_ulong)(unsigned long) &frame->sc;
+    env->regs[3] = frame_addr += offsetof(typeof(*frame), sc);
 
     /* We forgot to include these in the sigcontext.
        To avoid breaking binary compatibility, they are passed as args. */
@@ -3844,12 +3845,12 @@
     }
 
     /* Set up registers for signal handler */
-    env->regs[15] = (target_ulong)(unsigned long) frame;
+    env->regs[15] = frame_addr;
     env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
 
     env->regs[2] = sig; //map_signal(sig);
-    env->regs[3] = (target_ulong)(unsigned long) &frame->info;
-    env->regs[4] = (target_ulong)(unsigned long) &frame->uc;
+    env->regs[3] = frame_addr + offsetof(typeof(*frame), info);
+    env->regs[4] = frame_addr + offsetof(typeof(*frame), uc);
     return;
 
 give_sigsegv:
diff --git a/memory.c b/memory.c
index 8e9ac46..eb31fa8 100644
--- a/memory.c
+++ b/memory.c
@@ -304,7 +304,7 @@
     }
 
     if (!fr->readable) {
-        phys_offset &= TARGET_PAGE_MASK;
+        phys_offset &= ~TARGET_PAGE_MASK & ~IO_MEM_ROMD;
     }
 
     cpu_register_physical_memory_log(fr->addr.start,
@@ -962,11 +962,14 @@
 
 void memory_region_init_rom_device(MemoryRegion *mr,
                                    const MemoryRegionOps *ops,
+                                   void *opaque,
                                    DeviceState *dev,
                                    const char *name,
                                    uint64_t size)
 {
     memory_region_init(mr, name, size);
+    mr->ops = ops;
+    mr->opaque = opaque;
     mr->terminates = true;
     mr->destructor = memory_region_destructor_rom_device;
     mr->ram_addr = qemu_ram_alloc(dev, name, size);
diff --git a/memory.h b/memory.h
index 0553cc7..06b83ae 100644
--- a/memory.h
+++ b/memory.h
@@ -235,6 +235,7 @@
  */
 void memory_region_init_rom_device(MemoryRegion *mr,
                                    const MemoryRegionOps *ops,
+                                   void *opaque,
                                    DeviceState *dev, /* FIXME: layering violation */
                                    const char *name,
                                    uint64_t size);
diff --git a/mips.ld b/mips.ld
index 4294761..7b610ce 100644
--- a/mips.ld
+++ b/mips.ld
@@ -79,36 +79,34 @@
   }
   .sbss2          : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
   .eh_frame_hdr : { *(.eh_frame_hdr) }
-  .eh_frame       : ONLY_IF_RO { KEEP (*(.eh_frame)) }
-  .gcc_except_table   : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
   /* Adjust the address for the data segment.  We want to adjust up to
      the same address within the page on the next page up.  */
   . = ALIGN (0x40000) - ((0x40000 - .) & (0x40000 - 1)); . = DATA_SEGMENT_ALIGN (0x40000, 0x1000);
   /* Exception handling  */
-  .eh_frame       : ONLY_IF_RW { KEEP (*(.eh_frame)) }
-  .gcc_except_table   : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
+  .eh_frame       : { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : { *(.gcc_except_table .gcc_except_table.*) }
   /* Thread Local Storage sections  */
   .tdata         : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
   .tbss                  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
   .preinit_array     :
   {
-    PROVIDE_HIDDEN (__preinit_array_start = .);
+    PROVIDE (__preinit_array_start = .);
     KEEP (*(.preinit_array))
-    PROVIDE_HIDDEN (__preinit_array_end = .);
+    PROVIDE (__preinit_array_end = .);
   }
   .init_array     :
   {
-     PROVIDE_HIDDEN (__init_array_start = .);
+     PROVIDE (__init_array_start = .);
      KEEP (*(SORT(.init_array.*)))
      KEEP (*(.init_array))
-     PROVIDE_HIDDEN (__init_array_end = .);
+     PROVIDE (__init_array_end = .);
   }
   .fini_array     :
   {
-    PROVIDE_HIDDEN (__fini_array_start = .);
+    PROVIDE (__fini_array_start = .);
     KEEP (*(.fini_array))
     KEEP (*(SORT(.fini_array.*)))
-    PROVIDE_HIDDEN (__fini_array_end = .);
+    PROVIDE (__fini_array_end = .);
   }
   .ctors          :
   {
diff --git a/monitor.c b/monitor.c
index ada51d0..04f465a 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1189,7 +1189,6 @@
 {
     const char *protocol  = qdict_get_str(qdict, "protocol");
     const char *fdname = qdict_get_str(qdict, "fdname");
-    int skipauth = qdict_get_try_bool(qdict, "skipauth", 0);
     CharDriverState *s;
 
     if (strcmp(protocol, "spice") == 0) {
@@ -1203,6 +1202,7 @@
 #ifdef CONFIG_VNC
     } else if (strcmp(protocol, "vnc") == 0) {
 	int fd = monitor_get_fd(mon, fdname);
+        int skipauth = qdict_get_try_bool(qdict, "skipauth", 0);
 	vnc_display_add_client(NULL, fd, skipauth);
 	return 0;
 #endif
diff --git a/ppc.ld b/ppc.ld
index 5248ef1..69aa3f2 100644
--- a/ppc.ld
+++ b/ppc.ld
@@ -79,36 +79,34 @@
   }
   .sbss2          : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
   .eh_frame_hdr : { *(.eh_frame_hdr) }
-  .eh_frame       : ONLY_IF_RO { KEEP (*(.eh_frame)) }
-  .gcc_except_table   : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
   /* Adjust the address for the data segment.  We want to adjust up to
      the same address within the page on the next page up.  */
   . = ALIGN (0x10000) - ((0x10000 - .) & (0x10000 - 1)); . = DATA_SEGMENT_ALIGN (0x10000, 0x1000);
   /* Exception handling  */
-  .eh_frame       : ONLY_IF_RW { KEEP (*(.eh_frame)) }
-  .gcc_except_table   : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
+  .eh_frame       : { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : { *(.gcc_except_table .gcc_except_table.*) }
   /* Thread Local Storage sections  */
   .tdata	  : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
   .tbss		  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
   .preinit_array     :
   {
-    PROVIDE_HIDDEN (__preinit_array_start = .);
+    PROVIDE (__preinit_array_start = .);
     KEEP (*(.preinit_array))
-    PROVIDE_HIDDEN (__preinit_array_end = .);
+    PROVIDE (__preinit_array_end = .);
   }
   .init_array     :
   {
-     PROVIDE_HIDDEN (__init_array_start = .);
+     PROVIDE (__init_array_start = .);
      KEEP (*(SORT(.init_array.*)))
      KEEP (*(.init_array))
-     PROVIDE_HIDDEN (__init_array_end = .);
+     PROVIDE (__init_array_end = .);
   }
   .fini_array     :
   {
-    PROVIDE_HIDDEN (__fini_array_start = .);
+    PROVIDE (__fini_array_start = .);
     KEEP (*(.fini_array))
     KEEP (*(SORT(.fini_array.*)))
-    PROVIDE_HIDDEN (__fini_array_end = .);
+    PROVIDE (__fini_array_end = .);
   }
   .ctors          :
   {
diff --git a/ppc64.ld b/ppc64.ld
index dea0dbd..0059ee5 100644
--- a/ppc64.ld
+++ b/ppc64.ld
@@ -81,14 +81,12 @@
   .sdata2         : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) }
   .sbss2          : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
   .eh_frame_hdr : { *(.eh_frame_hdr) }
-  .eh_frame       : ONLY_IF_RO { KEEP (*(.eh_frame)) }
-  .gcc_except_table   : ONLY_IF_RO { KEEP (*(.gcc_except_table))
 *(.gcc_except_table.*) } /* Adjust the address for the data segment.  We want to
 adjust up to +     the same address within the page on the next page up.  */
   . = ALIGN (0x10000) - ((0x10000 - .) & (0x10000 - 1)); . = DATA_SEGMENT_ALIGN
 (0x10000, 0x1000);   /* Exception handling  */
-  .eh_frame       : ONLY_IF_RW { KEEP (*(.eh_frame)) }
-  .gcc_except_table   : ONLY_IF_RW { KEEP (*(.gcc_except_table))
+  .eh_frame       : { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : { KEEP (*(.gcc_except_table))
 *(.gcc_except_table.*) }   /* Thread Local Storage sections  */
   .tdata	  : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
   .tbss		  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 3498425..0eba357 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -2532,7 +2532,7 @@
 						$allowed = 1;
 					}
 				}
-				if (!$seen) {
+				if ($seen != ($#chunks + 1)) {
 					WARN("braces {} are necessary for all arms of this statement\n" . $herectx);
 				}
 			}
diff --git a/sparc.ld b/sparc.ld
index 31321be..56efe34 100644
--- a/sparc.ld
+++ b/sparc.ld
@@ -67,23 +67,23 @@
   .tbss    : { *(.tbss) }
   .preinit_array     :
   {
-    PROVIDE_HIDDEN (__preinit_array_start = .);
+    PROVIDE (__preinit_array_start = .);
     KEEP (*(.preinit_array))
-    PROVIDE_HIDDEN (__preinit_array_end = .);
+    PROVIDE (__preinit_array_end = .);
   }
   .init_array     :
   {
-     PROVIDE_HIDDEN (__init_array_start = .);
+     PROVIDE (__init_array_start = .);
      KEEP (*(SORT(.init_array.*)))
      KEEP (*(.init_array))
-     PROVIDE_HIDDEN (__init_array_end = .);
+     PROVIDE (__init_array_end = .);
   }
   .fini_array     :
   {
-    PROVIDE_HIDDEN (__fini_array_start = .);
+    PROVIDE (__fini_array_start = .);
     KEEP (*(.fini_array))
     KEEP (*(SORT(.fini_array.*)))
-    PROVIDE_HIDDEN (__fini_array_end = .);
+    PROVIDE (__fini_array_end = .);
   }
   .ctors         :
   {
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index bd850ed..1d9b20c 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -501,8 +501,9 @@
     qemu_add_vm_change_state_handler(cpu_update_state, env);
 
     r = kvm_vcpu_ioctl(env, KVM_SET_CPUID2, &cpuid_data);
-    if (r)
-	    return r;
+    if (r) {
+        return r;
+    }
 
     r = kvm_check_extension(env->kvm_state, KVM_CAP_TSC_CONTROL);
     if (r && env->tsc_khz) {
diff --git a/target-microblaze/cpu.h b/target-microblaze/cpu.h
index a81da62..3530286 100644
--- a/target-microblaze/cpu.h
+++ b/target-microblaze/cpu.h
@@ -65,6 +65,7 @@
 #define MSR_DCE (1<<7) /* 0x080 */
 #define MSR_EE  (1<<8) /* 0x100 */
 #define MSR_EIP (1<<9) /* 0x200 */
+#define MSR_PVR (1<<10) /* 0x400 */
 #define MSR_CC  (1<<31)
 
 /* Machine State Register (MSR) Fields */
diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c
index 1a862d3..366fd3e 100644
--- a/target-microblaze/translate.c
+++ b/target-microblaze/translate.c
@@ -424,10 +424,15 @@
 
 static inline void msr_write(DisasContext *dc, TCGv v)
 {
+    TCGv t;
+
+    t = tcg_temp_new();
     dc->cpustate_changed = 1;
-    tcg_gen_mov_tl(cpu_SR[SR_MSR], v);
-    /* PVR, we have a processor version register.  */
-    tcg_gen_ori_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR], (1 << 10));
+    /* PVR bit is not writable.  */
+    tcg_gen_andi_tl(t, v, ~MSR_PVR);
+    tcg_gen_andi_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR], MSR_PVR);
+    tcg_gen_or_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR], v);
+    tcg_temp_free(t);
 }
 
 static void dec_msr(DisasContext *dc)
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 024eb6f..b8d42e0 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -516,7 +516,22 @@
 #endif
 
 /* Exception state register bits definition                                  */
-#define ESR_ST    23    /* Exception was caused by a store type access.      */
+#define ESR_PIL   (1 << (63 - 36)) /* Illegal Instruction                    */
+#define ESR_PPR   (1 << (63 - 37)) /* Privileged Instruction                 */
+#define ESR_PTR   (1 << (63 - 38)) /* Trap                                   */
+#define ESR_FP    (1 << (63 - 39)) /* Floating-Point Operation               */
+#define ESR_ST    (1 << (63 - 40)) /* Store Operation                        */
+#define ESR_AP    (1 << (63 - 44)) /* Auxiliary Processor Operation          */
+#define ESR_PUO   (1 << (63 - 45)) /* Unimplemented Operation                */
+#define ESR_BO    (1 << (63 - 46)) /* Byte Ordering                          */
+#define ESR_PIE   (1 << (63 - 47)) /* Imprecise exception                    */
+#define ESR_DATA  (1 << (63 - 53)) /* Data Access (Embedded page table)      */
+#define ESR_TLBI  (1 << (63 - 54)) /* TLB Ineligible (Embedded page table)   */
+#define ESR_PT    (1 << (63 - 55)) /* Page Table (Embedded page table)       */
+#define ESR_SPV   (1 << (63 - 56)) /* SPE/VMX operation                      */
+#define ESR_EPID  (1 << (63 - 57)) /* External Process ID operation          */
+#define ESR_VLEMI (1 << (63 - 58)) /* VLE operation                          */
+#define ESR_MIF   (1 << (63 - 62)) /* Misaligned instruction (VLE)           */
 
 enum {
     POWERPC_FLAG_NONE     = 0x00000000,
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 3abab1a..5ec83f2 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -1837,7 +1837,7 @@
                     env->exception_index = POWERPC_EXCP_DTLB;
                     env->error_code = 0;
                     env->spr[SPR_BOOKE_DEAR] = address;
-                    env->spr[SPR_BOOKE_ESR] = rw ? 1 << ESR_ST : 0;
+                    env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
                     return -1;
                 case POWERPC_MMU_REAL:
                     cpu_abort(env, "PowerPC in real mode should never raise "
@@ -1861,7 +1861,7 @@
                 } else if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
                            (env->mmu_model == POWERPC_MMU_BOOKE206)) {
                     env->spr[SPR_BOOKE_DEAR] = address;
-                    env->spr[SPR_BOOKE_ESR] = rw ? 1 << ESR_ST : 0;
+                    env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
                 } else {
                     env->spr[SPR_DAR] = address;
                     if (rw == 1) {
@@ -2484,16 +2484,19 @@
             if (lpes1 == 0)
                 new_msr |= (target_ulong)MSR_HVB;
             msr |= 0x00080000;
+            env->spr[SPR_BOOKE_ESR] = ESR_PIL;
             break;
         case POWERPC_EXCP_PRIV:
             if (lpes1 == 0)
                 new_msr |= (target_ulong)MSR_HVB;
             msr |= 0x00040000;
+            env->spr[SPR_BOOKE_ESR] = ESR_PPR;
             break;
         case POWERPC_EXCP_TRAP:
             if (lpes1 == 0)
                 new_msr |= (target_ulong)MSR_HVB;
             msr |= 0x00020000;
+            env->spr[SPR_BOOKE_ESR] = ESR_PTR;
             break;
         default:
             /* Should never occur */
@@ -2556,16 +2559,19 @@
         cpu_abort(env, "Debug exception is not implemented yet !\n");
         goto store_next;
     case POWERPC_EXCP_SPEU:      /* SPE/embedded floating-point unavailable  */
+        env->spr[SPR_BOOKE_ESR] = ESR_SPV;
         goto store_current;
     case POWERPC_EXCP_EFPDI:     /* Embedded floating-point data interrupt   */
         /* XXX: TODO */
         cpu_abort(env, "Embedded floating point data exception "
                   "is not implemented yet !\n");
+        env->spr[SPR_BOOKE_ESR] = ESR_SPV;
         goto store_next;
     case POWERPC_EXCP_EFPRI:     /* Embedded floating-point round interrupt  */
         /* XXX: TODO */
         cpu_abort(env, "Embedded floating point round exception "
                   "is not implemented yet !\n");
+        env->spr[SPR_BOOKE_ESR] = ESR_SPV;
         goto store_next;
     case POWERPC_EXCP_EPERFM:    /* Embedded performance monitor interrupt   */
         /* XXX: TODO */
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index fd7c208..4277460 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -6622,7 +6622,7 @@
 {
 
     if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_APU);
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
         return;
     }
 
@@ -6693,7 +6693,7 @@
 static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],                \
@@ -6704,7 +6704,7 @@
 static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],                \
@@ -6729,7 +6729,7 @@
 static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
@@ -6750,7 +6750,7 @@
 static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     tcg_opi(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],               \
@@ -6770,7 +6770,7 @@
 static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
@@ -6791,7 +6791,7 @@
 static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);               \
@@ -6829,7 +6829,7 @@
 static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
@@ -6855,7 +6855,7 @@
 static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],                \
@@ -6933,7 +6933,7 @@
 static inline void gen_evmergehi(DisasContext *ctx)
 {
     if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_APU);
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
         return;
     }
 #if defined(TARGET_PPC64)
@@ -6962,7 +6962,7 @@
 static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
@@ -6983,7 +6983,7 @@
 static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],                \
@@ -7001,7 +7001,7 @@
 static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     int l1 = gen_new_label();                                                 \
@@ -7041,7 +7041,7 @@
 static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     int l1 = gen_new_label();                                                 \
@@ -7084,7 +7084,7 @@
 static inline void gen_evmergelo(DisasContext *ctx)
 {
     if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_APU);
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
         return;
     }
 #if defined(TARGET_PPC64)
@@ -7103,7 +7103,7 @@
 static inline void gen_evmergehilo(DisasContext *ctx)
 {
     if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_APU);
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
         return;
     }
 #if defined(TARGET_PPC64)
@@ -7122,7 +7122,7 @@
 static inline void gen_evmergelohi(DisasContext *ctx)
 {
     if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_APU);
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
         return;
     }
 #if defined(TARGET_PPC64)
@@ -7245,7 +7245,7 @@
     TCGv_i64 t0, t1;
 
     if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_APU);
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
         return;
     }
 
@@ -7274,7 +7274,7 @@
     TCGv_i64 tmp;
 
     if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_APU);
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
         return;
     }
 
@@ -7294,7 +7294,7 @@
     TCGv_i64 tmp;
 
     if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_APU);
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
         return;
     }
 
@@ -7327,7 +7327,7 @@
     TCGv_i64 t0, t1;
 
     if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_APU);
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
         return;
     }
 
@@ -7746,7 +7746,7 @@
 {                                                                             \
     TCGv t0;                                                                  \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     gen_set_access_type(ctx, ACCESS_INT);                                     \
@@ -7904,7 +7904,7 @@
     TCGv_i32 t0, t1;                                                          \
     TCGv_i64 t2;                                                              \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     t0 = tcg_temp_new_i32();                                                  \
@@ -7925,7 +7925,7 @@
 static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],     \
@@ -7936,7 +7936,7 @@
 {                                                                             \
     TCGv_i32 t0, t1;                                                          \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     t0 = tcg_temp_new_i32();                                                  \
@@ -7951,7 +7951,7 @@
 static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     gen_helper_##name(cpu_crf[crfD(ctx->opcode)],                             \
@@ -7992,7 +7992,7 @@
 static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     gen_helper_##name(cpu_gpr[rD(ctx->opcode)],                               \
@@ -8003,7 +8003,7 @@
 {                                                                             \
     TCGv_i64 t0, t1;                                                          \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     t0 = tcg_temp_new_i64();                                                  \
@@ -8019,7 +8019,7 @@
 static inline void gen_##name(DisasContext *ctx)                              \
 {                                                                             \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     gen_helper_##name(cpu_crf[crfD(ctx->opcode)],                             \
@@ -8030,7 +8030,7 @@
 {                                                                             \
     TCGv_i64 t0, t1;                                                          \
     if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
         return;                                                               \
     }                                                                         \
     t0 = tcg_temp_new_i64();                                                  \
@@ -8052,7 +8052,7 @@
 static inline void gen_evfsabs(DisasContext *ctx)
 {
     if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_APU);
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
         return;
     }
 #if defined(TARGET_PPC64)
@@ -8065,7 +8065,7 @@
 static inline void gen_evfsnabs(DisasContext *ctx)
 {
     if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_APU);
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
         return;
     }
 #if defined(TARGET_PPC64)
@@ -8078,7 +8078,7 @@
 static inline void gen_evfsneg(DisasContext *ctx)
 {
     if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_APU);
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
         return;
     }
 #if defined(TARGET_PPC64)
@@ -8134,7 +8134,7 @@
 static inline void gen_efsabs(DisasContext *ctx)
 {
     if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_APU);
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
         return;
     }
     tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], (target_long)~0x80000000LL);
@@ -8142,7 +8142,7 @@
 static inline void gen_efsnabs(DisasContext *ctx)
 {
     if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_APU);
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
         return;
     }
     tcg_gen_ori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
@@ -8150,7 +8150,7 @@
 static inline void gen_efsneg(DisasContext *ctx)
 {
     if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_APU);
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
         return;
     }
     tcg_gen_xori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
@@ -8202,7 +8202,7 @@
 static inline void gen_efdabs(DisasContext *ctx)
 {
     if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_APU);
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
         return;
     }
 #if defined(TARGET_PPC64)
@@ -8215,7 +8215,7 @@
 static inline void gen_efdnabs(DisasContext *ctx)
 {
     if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_APU);
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
         return;
     }
 #if defined(TARGET_PPC64)
@@ -8228,7 +8228,7 @@
 static inline void gen_efdneg(DisasContext *ctx)
 {
     if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_APU);
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
         return;
     }
 #if defined(TARGET_PPC64)
diff --git a/tcg/optimize.c b/tcg/optimize.c
index 7e7f2b2..9c65474 100644
--- a/tcg/optimize.c
+++ b/tcg/optimize.c
@@ -87,13 +87,13 @@
     }
 }
 
-static int op_bits(enum TCGOpcode op)
+static int op_bits(TCGOpcode op)
 {
     const TCGOpDef *def = &tcg_op_defs[op];
     return def->flags & TCG_OPF_64BIT ? 64 : 32;
 }
 
-static int op_to_movi(int op)
+static TCGOpcode op_to_movi(TCGOpcode op)
 {
     switch (op_bits(op)) {
     case 32:
@@ -143,7 +143,7 @@
         gen_args[1] = val;
 }
 
-static int op_to_mov(int op)
+static TCGOpcode op_to_mov(TCGOpcode op)
 {
     switch (op_bits(op)) {
     case 32:
@@ -157,7 +157,7 @@
     }
 }
 
-static TCGArg do_constant_folding_2(int op, TCGArg x, TCGArg y)
+static TCGArg do_constant_folding_2(TCGOpcode op, TCGArg x, TCGArg y)
 {
     switch (op) {
     CASE_OP_32_64(add):
@@ -258,7 +258,7 @@
     }
 }
 
-static TCGArg do_constant_folding(int op, TCGArg x, TCGArg y)
+static TCGArg do_constant_folding(TCGOpcode op, TCGArg x, TCGArg y)
 {
     TCGArg res = do_constant_folding_2(op, x, y);
     if (op_bits(op) == 32) {
@@ -271,7 +271,8 @@
 static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
                                     TCGArg *args, TCGOpDef *tcg_op_defs)
 {
-    int i, nb_ops, op_index, op, nb_temps, nb_globals, nb_call_args;
+    int i, nb_ops, op_index, nb_temps, nb_globals, nb_call_args;
+    TCGOpcode op;
     const TCGOpDef *def;
     TCGArg *gen_args;
     TCGArg tmp;
@@ -377,6 +378,8 @@
                 continue;
             }
             break;
+        default:
+            break;
         }
 
         /* Propagate constants through copy operations and do constant
diff --git a/tcg/tcg.c b/tcg/tcg.c
index 06ce214..411f971 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -1128,18 +1128,19 @@
 #if defined(CONFIG_DEBUG_TCG)
     i = 0;
     for (op = 0; op < ARRAY_SIZE(tcg_op_defs); op++) {
-        if (op < INDEX_op_call || op == INDEX_op_debug_insn_start) {
+        const TCGOpDef *def = &tcg_op_defs[op];
+        if (op < INDEX_op_call
+            || op == INDEX_op_debug_insn_start
+            || (def->flags & TCG_OPF_NOT_PRESENT)) {
             /* Wrong entry in op definitions? */
-            if (tcg_op_defs[op].used) {
-                fprintf(stderr, "Invalid op definition for %s\n",
-                        tcg_op_defs[op].name);
+            if (def->used) {
+                fprintf(stderr, "Invalid op definition for %s\n", def->name);
                 i = 1;
             }
         } else {
             /* Missing entry in op definitions? */
-            if (!tcg_op_defs[op].used) {
-                fprintf(stderr, "Missing op definition for %s\n",
-                        tcg_op_defs[op].name);
+            if (!def->used) {
+                fprintf(stderr, "Missing op definition for %s\n", def->name);
                 i = 1;
             }
         }
diff --git a/trace-events b/trace-events
index dc300a2..f08d6d0 100644
--- a/trace-events
+++ b/trace-events
@@ -284,6 +284,10 @@
 disable qed_aio_write_postfill(void *s, void *acb, uint64_t start, size_t len, uint64_t offset) "s %p acb %p start %"PRIu64" len %zu offset %"PRIu64""
 disable qed_aio_write_main(void *s, void *acb, int ret, uint64_t offset, size_t len) "s %p acb %p ret %d offset %"PRIu64" len %zu"
 
+# hw/g364fb.c
+disable g364fb_read(uint64_t addr, uint32_t val) "read addr=0x%"PRIx64": 0x%x"
+disable g364fb_write(uint64_t addr, uint32_t new) "write addr=0x%"PRIx64": 0x%x"
+
 # hw/grlib_gptimer.c
 disable grlib_gptimer_enable(int id, uint32_t count) "timer:%d set count 0x%x and run"
 disable grlib_gptimer_disabled(int id, uint32_t config) "timer:%d Timer disable config 0x%x"
diff --git a/x86_64.ld b/x86_64.ld
index 46d8d4d..b7a9f4e 100644
--- a/x86_64.ld
+++ b/x86_64.ld
@@ -38,16 +38,16 @@
   .rel.plt      :
   {
     *(.rel.plt)
-    PROVIDE_HIDDEN (__rel_iplt_start = .);
+    PROVIDE (__rel_iplt_start = .);
     *(.rel.iplt)
-    PROVIDE_HIDDEN (__rel_iplt_end = .);
+    PROVIDE (__rel_iplt_end = .);
   }
   .rela.plt       :
   {
     *(.rela.plt)
-    PROVIDE_HIDDEN (__rela_iplt_start = .);
+    PROVIDE (__rela_iplt_start = .);
     *(.rela.iplt)
-    PROVIDE_HIDDEN (__rela_iplt_end = .);
+    PROVIDE (__rela_iplt_end = .);
   }
   .init           :
   {
@@ -70,8 +70,6 @@
   .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
   .rodata1        : { *(.rodata1) }
   .eh_frame_hdr : { *(.eh_frame_hdr) }
-  .eh_frame       : ONLY_IF_RO { KEEP (*(.eh_frame)) }
-  .gcc_except_table   : ONLY_IF_RO { *(.gcc_except_table) }
   /* Adjust the address for the data segment.  We want to adjust up to
      the same address within the page on the next page up.  */
   . = ALIGN (0x100000) - ((0x100000 - .) & (0x100000 - 1)); . = DATA_SEGMENT_ALIGN (0x100000, 0x1000);
@@ -97,8 +95,8 @@
   .data1          : { *(.data1) }
   .tdata	  : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
   .tbss		  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
-  .eh_frame       : ONLY_IF_RW { KEEP (*(.eh_frame)) }
-  .gcc_except_table   : ONLY_IF_RW { *(.gcc_except_table) }
+  .eh_frame       : { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : { *(.gcc_except_table) }
   .dynamic        : { *(.dynamic) }
   .ctors          :
   {