summary refs log tree commit diff stats
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/acpi.c28
-rw-r--r--hw/acpi_piix4.c35
-rw-r--r--hw/apic.c48
-rw-r--r--hw/bonito.c1
-rw-r--r--hw/cirrus_vga.c30
-rw-r--r--hw/cirrus_vga_rop.h38
-rw-r--r--hw/cirrus_vga_rop2.h12
-rw-r--r--hw/device-hotplug.c1
-rw-r--r--hw/e1000.c38
-rw-r--r--hw/eepro100.c36
-rw-r--r--hw/elf_ops.h5
-rw-r--r--hw/escc.c56
-rw-r--r--hw/esp.c53
-rw-r--r--hw/esp.h3
-rw-r--r--hw/etraxfs.c1
-rw-r--r--hw/etraxfs_eth.c3
-rw-r--r--hw/fdc.c1
-rw-r--r--hw/fdc.h1
-rw-r--r--hw/file-op-9p.h40
-rw-r--r--hw/fmopl.c6
-rw-r--r--hw/gumstix.c1
-rw-r--r--hw/hw.h8
-rw-r--r--hw/ide/core.c99
-rw-r--r--hw/ide/pci.c61
-rw-r--r--hw/ide/qdev.c1
-rw-r--r--hw/ide/via.c1
-rw-r--r--hw/ivshmem.c829
-rw-r--r--hw/jazz_led.c21
-rw-r--r--hw/loader.c5
-rw-r--r--hw/lsi53c895a.c5
-rw-r--r--hw/mainstone.c1
-rw-r--r--hw/mips_fulong2e.c34
-rw-r--r--hw/mips_int.c32
-rw-r--r--hw/mips_jazz.c5
-rw-r--r--hw/mips_malta.c22
-rw-r--r--hw/mips_r4k.c4
-rw-r--r--hw/mipsnet.c2
-rw-r--r--hw/msix.c1
-rw-r--r--hw/multiboot.c2
-rw-r--r--hw/musicpal.c1
-rw-r--r--hw/omap.h6
-rw-r--r--hw/omap1.c18
-rw-r--r--hw/omap2.c6
-rw-r--r--hw/omap_clk.c1
-rw-r--r--hw/omap_i2c.c5
-rw-r--r--hw/omap_mmc.c5
-rw-r--r--hw/omap_sx1.c1
-rw-r--r--hw/omap_uart.c12
-rw-r--r--hw/pc.c7
-rw-r--r--hw/pc_piix.c8
-rw-r--r--hw/pci-hotplug.c3
-rw-r--r--hw/pci.c3
-rw-r--r--hw/pci.h29
-rw-r--r--hw/pckbd.c23
-rw-r--r--hw/pcmcia.h1
-rw-r--r--hw/petalogix_s3adsp1800_mmu.c14
-rw-r--r--hw/piix_pci.c1
-rw-r--r--hw/ppc.c27
-rw-r--r--hw/ppc.h7
-rw-r--r--hw/ppc405_boards.c29
-rw-r--r--hw/ppc405_uc.c28
-rw-r--r--hw/ppc440_bamboo.c41
-rw-r--r--hw/ppc4xx_devs.c5
-rw-r--r--hw/ppc_mac.h1
-rw-r--r--hw/ppc_newworld.c55
-rw-r--r--hw/ppc_oldworld.c121
-rw-r--r--hw/ppc_prep.c7
-rw-r--r--hw/ppce500_mpc8544ds.c13
-rw-r--r--hw/pxa2xx.c16
-rw-r--r--hw/qdev-properties.c3
-rw-r--r--hw/qdev.c3
-rw-r--r--hw/qdev.h1
-rw-r--r--hw/r2d.c1
-rw-r--r--hw/rc4030.c5
-rw-r--r--hw/realview.c1
-rw-r--r--hw/s390-virtio-bus.c8
-rw-r--r--hw/s390-virtio-bus.h1
-rw-r--r--hw/scsi-bus.c16
-rw-r--r--hw/scsi-disk.c146
-rw-r--r--hw/scsi-generic.c40
-rw-r--r--hw/scsi.h1
-rw-r--r--hw/sd.c3
-rw-r--r--hw/serial.c26
-rw-r--r--hw/sh_intc.c3
-rw-r--r--hw/slavio_timer.c4
-rw-r--r--hw/sm501.c5
-rw-r--r--hw/soc_dma.c5
-rw-r--r--hw/sparc32_dma.c23
-rw-r--r--hw/spitz.c1
-rw-r--r--hw/sun4m.c80
-rw-r--r--hw/sun4u.c1
-rw-r--r--hw/syborg_virtio.c8
-rw-r--r--hw/sysbus.c3
-rw-r--r--hw/sysbus.h5
-rw-r--r--hw/tc6393xb_template.h2
-rw-r--r--hw/tosa.c1
-rw-r--r--hw/usb-msd.c3
-rw-r--r--hw/usb-net.c2
-rw-r--r--hw/usb-wacom.c13
-rw-r--r--hw/versatilepb.c1
-rw-r--r--hw/vga.c7
-rw-r--r--hw/vhost.c58
-rw-r--r--hw/vhost_net.c27
-rw-r--r--hw/virtex_ml507.c276
-rw-r--r--hw/virtio-9p-debug.c195
-rw-r--r--hw/virtio-9p-debug.h1
-rw-r--r--hw/virtio-9p-local.c142
-rw-r--r--hw/virtio-9p-posix-acl.c140
-rw-r--r--hw/virtio-9p-xattr-user.c109
-rw-r--r--hw/virtio-9p-xattr.c156
-rw-r--r--hw/virtio-9p-xattr.h103
-rw-r--r--hw/virtio-9p.c1969
-rw-r--r--hw/virtio-9p.h257
-rw-r--r--hw/virtio-balloon.c12
-rw-r--r--hw/virtio-blk.c32
-rw-r--r--hw/virtio-net.c218
-rw-r--r--hw/virtio-net.h14
-rw-r--r--hw/virtio-pci.c54
-rw-r--r--hw/virtio-serial-bus.c31
-rw-r--r--hw/virtio.c59
-rw-r--r--hw/virtio.h11
-rw-r--r--hw/vmmouse.c31
-rw-r--r--hw/vmware_vga.c80
-rw-r--r--hw/vt82c686.c5
-rw-r--r--hw/watchdog.c2
-rw-r--r--hw/wm8750.c5
-rw-r--r--hw/xen_backend.h4
-rw-r--r--hw/xen_devconfig.c2
-rw-r--r--hw/xen_disk.c1
-rw-r--r--hw/xen_machine_pv.c1
130 files changed, 5352 insertions, 1129 deletions
diff --git a/hw/acpi.c b/hw/acpi.c
index c7044b1fae..8071e7beba 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -50,6 +50,8 @@ int acpi_table_add(const char *t)
     char buf[1024], *p, *f;
     struct acpi_table_header acpi_hdr;
     unsigned long val;
+    uint32_t length;
+    struct acpi_table_header *acpi_hdr_p;
     size_t off;
 
     memset(&acpi_hdr, 0, sizeof(acpi_hdr));
@@ -108,7 +110,7 @@ int acpi_table_add(const char *t)
          buf[0] = '\0';
     }
 
-    acpi_hdr.length = sizeof(acpi_hdr);
+    length = sizeof(acpi_hdr);
 
     f = buf;
     while (buf[0]) {
@@ -120,7 +122,7 @@ int acpi_table_add(const char *t)
             fprintf(stderr, "Can't stat file '%s': %s\n", f, strerror(errno));
             goto out;
         }
-        acpi_hdr.length += s.st_size;
+        length += s.st_size;
         if (!n)
             break;
         *n = ':';
@@ -131,12 +133,12 @@ int acpi_table_add(const char *t)
         acpi_tables_len = sizeof(uint16_t);
         acpi_tables = qemu_mallocz(acpi_tables_len);
     }
+    acpi_tables = qemu_realloc(acpi_tables,
+                               acpi_tables_len + sizeof(uint16_t) + length);
     p = acpi_tables + acpi_tables_len;
-    acpi_tables_len += sizeof(uint16_t) + acpi_hdr.length;
-    acpi_tables = qemu_realloc(acpi_tables, acpi_tables_len);
+    acpi_tables_len += sizeof(uint16_t) + length;
 
-    acpi_hdr.length = cpu_to_le32(acpi_hdr.length);
-    *(uint16_t*)p = acpi_hdr.length;
+    *(uint16_t*)p = cpu_to_le32(length);
     p += sizeof(uint16_t);
     memcpy(p, &acpi_hdr, sizeof(acpi_hdr));
     off = sizeof(acpi_hdr);
@@ -157,7 +159,9 @@ int acpi_table_add(const char *t)
             goto out;
         }
 
-        do {
+        /* off < length is necessary because file size can be changed
+           under our foot */
+        while(s.st_size && off < length) {
             int r;
             r = read(fd, p + off, s.st_size);
             if (r > 0) {
@@ -167,15 +171,21 @@ int acpi_table_add(const char *t)
                 close(fd);
                 goto out;
             }
-        } while(s.st_size);
+        }
 
         close(fd);
         if (!n)
             break;
         f = n + 1;
     }
+    if (off < length) {
+        /* don't pass random value in process to guest */
+        memset(p + off, 0, length - off);
+    }
 
-    ((struct acpi_table_header*)p)->checksum = acpi_checksum((uint8_t*)p, off);
+    acpi_hdr_p = (struct acpi_table_header*)p;
+    acpi_hdr_p->length = cpu_to_le32(length);
+    acpi_hdr_p->checksum = acpi_checksum((uint8_t*)p, length);
     /* increase number of tables */
     (*(uint16_t*)acpi_tables) =
 	    cpu_to_le32(le32_to_cpu(*(uint16_t*)acpi_tables) + 1);
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index 24dfcf2039..66c7885d62 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -22,6 +22,7 @@
 #include "pci.h"
 #include "acpi.h"
 #include "sysemu.h"
+#include "range.h"
 
 //#define DEBUG
 
@@ -37,6 +38,8 @@
 #define PCI_BASE 0xae00
 #define PCI_EJ_BASE 0xae08
 
+#define PIIX4_PCI_HOTPLUG_STATUS 2
+
 struct gpe_regs {
     uint16_t sts; /* status */
     uint16_t en;  /* enabled */
@@ -104,7 +107,9 @@ static void pm_update_sci(PIIX4PMState *s)
                   (ACPI_BITMASK_RT_CLOCK_ENABLE |
                    ACPI_BITMASK_POWER_BUTTON_ENABLE |
                    ACPI_BITMASK_GLOBAL_LOCK_ENABLE |
-                   ACPI_BITMASK_TIMER_ENABLE)) != 0);
+                   ACPI_BITMASK_TIMER_ENABLE)) != 0) ||
+        (((s->gpe.sts & s->gpe.en) & PIIX4_PCI_HOTPLUG_STATUS) != 0);
+
     qemu_set_irq(s->irq, sci_level);
     /* schedule a timer interruption if needed */
     if ((s->pmen & ACPI_BITMASK_TIMER_ENABLE) &&
@@ -459,7 +464,9 @@ static uint32_t gpe_read_val(uint16_t val, uint32_t addr)
 static uint32_t gpe_readb(void *opaque, uint32_t addr)
 {
     uint32_t val = 0;
-    struct gpe_regs *g = opaque;
+    PIIX4PMState *s = opaque;
+    struct gpe_regs *g = &s->gpe;
+
     switch (addr) {
         case GPE_BASE:
         case GPE_BASE + 1:
@@ -499,7 +506,9 @@ static void gpe_reset_val(uint16_t *cur, int addr, uint32_t val)
 
 static void gpe_writeb(void *opaque, uint32_t addr, uint32_t val)
 {
-    struct gpe_regs *g = opaque;
+    PIIX4PMState *s = opaque;
+    struct gpe_regs *g = &s->gpe;
+
     switch (addr) {
         case GPE_BASE:
         case GPE_BASE + 1:
@@ -511,7 +520,9 @@ static void gpe_writeb(void *opaque, uint32_t addr, uint32_t val)
             break;
         default:
             break;
-   }
+    }
+
+    pm_update_sci(s);
 
     PIIX4_DPRINTF("gpe write %x <== %d\n", addr, val);
 }
@@ -578,11 +589,10 @@ static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, int state);
 
 static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s)
 {
-    struct gpe_regs *gpe = &s->gpe;
     struct pci_status *pci0_status = &s->pci0_status;
 
-    register_ioport_write(GPE_BASE, 4, 1, gpe_writeb, gpe);
-    register_ioport_read(GPE_BASE, 4, 1,  gpe_readb, gpe);
+    register_ioport_write(GPE_BASE, 4, 1, gpe_writeb, s);
+    register_ioport_read(GPE_BASE, 4, 1,  gpe_readb, s);
 
     register_ioport_write(PCI_BASE, 8, 4, pcihotplug_write, pci0_status);
     register_ioport_read(PCI_BASE, 8, 4,  pcihotplug_read, pci0_status);
@@ -595,13 +605,13 @@ static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s)
 
 static void enable_device(PIIX4PMState *s, int slot)
 {
-    s->gpe.sts |= 2;
+    s->gpe.sts |= PIIX4_PCI_HOTPLUG_STATUS;
     s->pci0_status.up |= (1 << slot);
 }
 
 static void disable_device(PIIX4PMState *s, int slot)
 {
-    s->gpe.sts |= 2;
+    s->gpe.sts |= PIIX4_PCI_HOTPLUG_STATUS;
     s->pci0_status.down |= (1 << slot);
 }
 
@@ -621,9 +631,8 @@ static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, int state)
     } else {
         disable_device(s, slot);
     }
-    if (s->gpe.en & 2) {
-        qemu_set_irq(s->irq, 1);
-        qemu_set_irq(s->irq, 0);
-    }
+
+    pm_update_sci(s);
+
     return 0;
 }
diff --git a/hw/apic.c b/hw/apic.c
index d686b510b0..63d62c7553 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -21,23 +21,7 @@
 #include "qemu-timer.h"
 #include "host-utils.h"
 #include "sysbus.h"
-
-//#define DEBUG_APIC
-//#define DEBUG_COALESCING
-
-#ifdef DEBUG_APIC
-#define DPRINTF(fmt, ...)                                       \
-    do { printf("apic: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...)
-#endif
-
-#ifdef DEBUG_COALESCING
-#define DPRINTF_C(fmt, ...)                                     \
-    do { printf("apic: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF_C(fmt, ...)
-#endif
+#include "trace.h"
 
 /* APIC Local Vector Table */
 #define APIC_LVT_TIMER   0
@@ -168,8 +152,8 @@ static void apic_local_deliver(APICState *s, int vector)
     uint32_t lvt = s->lvt[vector];
     int trigger_mode;
 
-    DPRINTF("%s: vector %d delivery mode %d\n", __func__, vector,
-            (lvt >> 8) & 7);
+    trace_apic_local_deliver(vector, (lvt >> 8) & 7);
+
     if (lvt & APIC_LVT_MASKED)
         return;
 
@@ -300,9 +284,9 @@ void apic_deliver_irq(uint8_t dest, uint8_t dest_mode,
 {
     uint32_t deliver_bitmask[MAX_APIC_WORDS];
 
-    DPRINTF("%s: dest %d dest_mode %d delivery_mode %d vector %d"
-            " polarity %d trigger_mode %d\n", __func__, dest, dest_mode,
-            delivery_mode, vector_num, polarity, trigger_mode);
+    trace_apic_deliver_irq(dest, dest_mode, delivery_mode, vector_num,
+                           polarity, trigger_mode);
+
     apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
     apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, polarity,
                      trigger_mode);
@@ -312,7 +296,8 @@ void cpu_set_apic_base(DeviceState *d, uint64_t val)
 {
     APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
 
-    DPRINTF("cpu_set_apic_base: %016" PRIx64 "\n", val);
+    trace_cpu_set_apic_base(val);
+
     if (!s)
         return;
     s->apicbase = (val & 0xfffff000) |
@@ -329,8 +314,8 @@ uint64_t cpu_get_apic_base(DeviceState *d)
 {
     APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
 
-    DPRINTF("cpu_get_apic_base: %016" PRIx64 "\n",
-            s ? (uint64_t)s->apicbase: 0);
+    trace_cpu_get_apic_base(s ? (uint64_t)s->apicbase: 0);
+
     return s ? s->apicbase : 0;
 }
 
@@ -402,20 +387,23 @@ static void apic_update_irq(APICState *s)
 
 void apic_reset_irq_delivered(void)
 {
-    DPRINTF_C("%s: old coalescing %d\n", __func__, apic_irq_delivered);
+    trace_apic_reset_irq_delivered(apic_irq_delivered);
+
     apic_irq_delivered = 0;
 }
 
 int apic_get_irq_delivered(void)
 {
-    DPRINTF_C("%s: returning coalescing %d\n", __func__, apic_irq_delivered);
+    trace_apic_get_irq_delivered(apic_irq_delivered);
+
     return apic_irq_delivered;
 }
 
 static void apic_set_irq(APICState *s, int vector_num, int trigger_mode)
 {
     apic_irq_delivered += !get_bit(s->irr, vector_num);
-    DPRINTF_C("%s: coalescing %d\n", __func__, apic_irq_delivered);
+
+    trace_apic_set_irq(apic_irq_delivered);
 
     set_bit(s->irr, vector_num);
     if (trigger_mode)
@@ -769,7 +757,7 @@ static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
         val = 0;
         break;
     }
-    DPRINTF("read: " TARGET_FMT_plx " = %08x\n", addr, val);
+    trace_apic_mem_readl(addr, val);
     return val;
 }
 
@@ -805,7 +793,7 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
     }
     s = DO_UPCAST(APICState, busdev.qdev, d);
 
-    DPRINTF("write: " TARGET_FMT_plx " = %08x\n", addr, val);
+    trace_apic_mem_writel(addr, val);
 
     switch(index) {
     case 0x02:
diff --git a/hw/bonito.c b/hw/bonito.c
index 8b810321ad..dcf031134e 100644
--- a/hw/bonito.c
+++ b/hw/bonito.c
@@ -775,7 +775,6 @@ PCIBus *bonito_init(qemu_irq *pic)
                          pci_bonito_map_irq, pic, 0x28, 32);
     pcihost->bus = b;
     qdev_init_nofail(dev);
-    pci_bus_set_mem_base(pcihost->bus, 0x10000000);
 
     d = pci_create_simple(b, PCI_DEVFN(0, 0), "Bonito");
     s = DO_UPCAST(PCIBonitoState, dev, d);
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index bbd4b082d2..aadc56f692 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -280,63 +280,63 @@ static void cirrus_bitblt_fill_nop(CirrusVGAState *s,
 }
 
 #define ROP_NAME 0
-#define ROP_OP(d, s) d = 0
+#define ROP_FN(d, s) 0
 #include "cirrus_vga_rop.h"
 
 #define ROP_NAME src_and_dst
-#define ROP_OP(d, s) d = (s) & (d)
+#define ROP_FN(d, s) (s) & (d)
 #include "cirrus_vga_rop.h"
 
 #define ROP_NAME src_and_notdst
-#define ROP_OP(d, s) d = (s) & (~(d))
+#define ROP_FN(d, s) (s) & (~(d))
 #include "cirrus_vga_rop.h"
 
 #define ROP_NAME notdst
-#define ROP_OP(d, s) d = ~(d)
+#define ROP_FN(d, s) ~(d)
 #include "cirrus_vga_rop.h"
 
 #define ROP_NAME src
-#define ROP_OP(d, s) d = s
+#define ROP_FN(d, s) s
 #include "cirrus_vga_rop.h"
 
 #define ROP_NAME 1
-#define ROP_OP(d, s) d = ~0
+#define ROP_FN(d, s) ~0
 #include "cirrus_vga_rop.h"
 
 #define ROP_NAME notsrc_and_dst
-#define ROP_OP(d, s) d = (~(s)) & (d)
+#define ROP_FN(d, s) (~(s)) & (d)
 #include "cirrus_vga_rop.h"
 
 #define ROP_NAME src_xor_dst
-#define ROP_OP(d, s) d = (s) ^ (d)
+#define ROP_FN(d, s) (s) ^ (d)
 #include "cirrus_vga_rop.h"
 
 #define ROP_NAME src_or_dst
-#define ROP_OP(d, s) d = (s) | (d)
+#define ROP_FN(d, s) (s) | (d)
 #include "cirrus_vga_rop.h"
 
 #define ROP_NAME notsrc_or_notdst
-#define ROP_OP(d, s) d = (~(s)) | (~(d))
+#define ROP_FN(d, s) (~(s)) | (~(d))
 #include "cirrus_vga_rop.h"
 
 #define ROP_NAME src_notxor_dst
-#define ROP_OP(d, s) d = ~((s) ^ (d))
+#define ROP_FN(d, s) ~((s) ^ (d))
 #include "cirrus_vga_rop.h"
 
 #define ROP_NAME src_or_notdst
-#define ROP_OP(d, s) d = (s) | (~(d))
+#define ROP_FN(d, s) (s) | (~(d))
 #include "cirrus_vga_rop.h"
 
 #define ROP_NAME notsrc
-#define ROP_OP(d, s) d = (~(s))
+#define ROP_FN(d, s) (~(s))
 #include "cirrus_vga_rop.h"
 
 #define ROP_NAME notsrc_or_dst
-#define ROP_OP(d, s) d = (~(s)) | (d)
+#define ROP_FN(d, s) (~(s)) | (d)
 #include "cirrus_vga_rop.h"
 
 #define ROP_NAME notsrc_and_notdst
-#define ROP_OP(d, s) d = (~(s)) & (~(d))
+#define ROP_FN(d, s) (~(s)) & (~(d))
 #include "cirrus_vga_rop.h"
 
 static const cirrus_bitblt_rop_t cirrus_fwd_rop[16] = {
diff --git a/hw/cirrus_vga_rop.h b/hw/cirrus_vga_rop.h
index 39a7b7285b..9c7bb09286 100644
--- a/hw/cirrus_vga_rop.h
+++ b/hw/cirrus_vga_rop.h
@@ -22,6 +22,26 @@
  * THE SOFTWARE.
  */
 
+static inline void glue(rop_8_,ROP_NAME)(uint8_t *dst, uint8_t src)
+{
+    *dst = ROP_FN(*dst, src);
+}
+
+static inline void glue(rop_16_,ROP_NAME)(uint16_t *dst, uint16_t src)
+{
+    *dst = ROP_FN(*dst, src);
+}
+
+static inline void glue(rop_32_,ROP_NAME)(uint32_t *dst, uint32_t src)
+{
+    *dst = ROP_FN(*dst, src);
+}
+
+#define ROP_OP(d, s) glue(rop_8_,ROP_NAME)(d, s)
+#define ROP_OP_16(d, s) glue(rop_16_,ROP_NAME)(d, s)
+#define ROP_OP_32(d, s) glue(rop_32_,ROP_NAME)(d, s)
+#undef ROP_FN
+
 static void
 glue(cirrus_bitblt_rop_fwd_, ROP_NAME)(CirrusVGAState *s,
                              uint8_t *dst,const uint8_t *src,
@@ -39,7 +59,7 @@ glue(cirrus_bitblt_rop_fwd_, ROP_NAME)(CirrusVGAState *s,
 
     for (y = 0; y < bltheight; y++) {
         for (x = 0; x < bltwidth; x++) {
-            ROP_OP(*dst, *src);
+            ROP_OP(dst, *src);
             dst++;
             src++;
         }
@@ -59,7 +79,7 @@ glue(cirrus_bitblt_rop_bkwd_, ROP_NAME)(CirrusVGAState *s,
     srcpitch += bltwidth;
     for (y = 0; y < bltheight; y++) {
         for (x = 0; x < bltwidth; x++) {
-            ROP_OP(*dst, *src);
+            ROP_OP(dst, *src);
             dst--;
             src--;
         }
@@ -81,7 +101,7 @@ glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_8)(CirrusVGAState *s,
     for (y = 0; y < bltheight; y++) {
         for (x = 0; x < bltwidth; x++) {
 	    p = *dst;
-            ROP_OP(p, *src);
+            ROP_OP(&p, *src);
 	    if (p != s->vga.gr[0x34]) *dst = p;
             dst++;
             src++;
@@ -104,7 +124,7 @@ glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_8)(CirrusVGAState *s,
     for (y = 0; y < bltheight; y++) {
         for (x = 0; x < bltwidth; x++) {
 	    p = *dst;
-            ROP_OP(p, *src);
+            ROP_OP(&p, *src);
 	    if (p != s->vga.gr[0x34]) *dst = p;
             dst--;
             src--;
@@ -128,8 +148,8 @@ glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_16)(CirrusVGAState *s,
         for (x = 0; x < bltwidth; x+=2) {
 	    p1 = *dst;
 	    p2 = *(dst+1);
-            ROP_OP(p1, *src);
-            ROP_OP(p2, *(src+1));
+            ROP_OP(&p1, *src);
+            ROP_OP(&p2, *(src + 1));
 	    if ((p1 != s->vga.gr[0x34]) || (p2 != s->vga.gr[0x35])) {
 		*dst = p1;
 		*(dst+1) = p2;
@@ -156,8 +176,8 @@ glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_16)(CirrusVGAState *s,
         for (x = 0; x < bltwidth; x+=2) {
 	    p1 = *(dst-1);
 	    p2 = *dst;
-            ROP_OP(p1, *(src-1));
-            ROP_OP(p2, *src);
+            ROP_OP(&p1, *(src - 1));
+            ROP_OP(&p2, *src);
 	    if ((p1 != s->vga.gr[0x34]) || (p2 != s->vga.gr[0x35])) {
 		*(dst-1) = p1;
 		*dst = p2;
@@ -184,3 +204,5 @@ glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_16)(CirrusVGAState *s,
 
 #undef ROP_NAME
 #undef ROP_OP
+#undef ROP_OP_16
+#undef ROP_OP_32
diff --git a/hw/cirrus_vga_rop2.h b/hw/cirrus_vga_rop2.h
index 81a5b398e0..d28bcc6f25 100644
--- a/hw/cirrus_vga_rop2.h
+++ b/hw/cirrus_vga_rop2.h
@@ -23,15 +23,15 @@
  */
 
 #if DEPTH == 8
-#define PUTPIXEL()    ROP_OP(d[0], col)
+#define PUTPIXEL()    ROP_OP(&d[0], col)
 #elif DEPTH == 16
-#define PUTPIXEL()    ROP_OP(((uint16_t *)d)[0], col);
+#define PUTPIXEL()    ROP_OP_16((uint16_t *)&d[0], col)
 #elif DEPTH == 24
-#define PUTPIXEL()    ROP_OP(d[0], col); \
-                      ROP_OP(d[1], (col >> 8)); \
-                      ROP_OP(d[2], (col >> 16))
+#define PUTPIXEL()    ROP_OP(&d[0], col);        \
+                      ROP_OP(&d[1], (col >> 8)); \
+                      ROP_OP(&d[2], (col >> 16))
 #elif DEPTH == 32
-#define PUTPIXEL()    ROP_OP(((uint32_t *)d)[0], col)
+#define PUTPIXEL()    ROP_OP_32(((uint32_t *)&d[0]), col)
 #else
 #error unsupported DEPTH
 #endif
diff --git a/hw/device-hotplug.c b/hw/device-hotplug.c
index c1a9a561d7..9704e2feb2 100644
--- a/hw/device-hotplug.c
+++ b/hw/device-hotplug.c
@@ -25,6 +25,7 @@
 #include "hw.h"
 #include "boards.h"
 #include "net.h"
+#include "blockdev.h"
 
 DriveInfo *add_init_drive(const char *optstr)
 {
diff --git a/hw/e1000.c b/hw/e1000.c
index 8d87492e0b..532efdc27d 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -55,6 +55,7 @@ static int debugflags = DBGBIT(TXERR) | DBGBIT(GENERAL);
 
 #define IOPORT_SIZE       0x40
 #define PNPMMIO_SIZE      0x20000
+#define MIN_BUF_SIZE      60 /* Min. octets in an ethernet frame sans FCS */
 
 /*
  * HW models:
@@ -262,21 +263,20 @@ set_eecd(E1000State *s, int index, uint32_t val)
 
     s->eecd_state.old_eecd = val & (E1000_EECD_SK | E1000_EECD_CS |
             E1000_EECD_DI|E1000_EECD_FWE_MASK|E1000_EECD_REQ);
+    if (!(E1000_EECD_CS & val))			// CS inactive; nothing to do
+	return;
+    if (E1000_EECD_CS & (val ^ oldval)) {	// CS rise edge; reset state
+	s->eecd_state.val_in = 0;
+	s->eecd_state.bitnum_in = 0;
+	s->eecd_state.bitnum_out = 0;
+	s->eecd_state.reading = 0;
+    }
     if (!(E1000_EECD_SK & (val ^ oldval)))	// no clock edge
         return;
     if (!(E1000_EECD_SK & val)) {		// falling edge
         s->eecd_state.bitnum_out++;
         return;
     }
-    if (!(val & E1000_EECD_CS)) {		// rising, no CS (EEPROM reset)
-        memset(&s->eecd_state, 0, sizeof s->eecd_state);
-        /*
-         * restore old_eecd's E1000_EECD_SK (known to be on)
-         * to avoid false detection of a clock edge
-         */
-        s->eecd_state.old_eecd = E1000_EECD_SK;
-        return;
-    }
     s->eecd_state.val_in <<= 1;
     if (val & E1000_EECD_DI)
         s->eecd_state.val_in |= 1;
@@ -346,7 +346,7 @@ is_vlan_txd(uint32_t txd_lower)
 
 /* FCS aka Ethernet CRC-32. We don't get it from backends and can't
  * fill it in, just pad descriptor length by 4 bytes unless guest
- * told us to trip it off the packet. */
+ * told us to strip it off the packet. */
 static inline int
 fcs_len(E1000State *s)
 {
@@ -636,10 +636,19 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
     uint32_t rdh_start;
     uint16_t vlan_special = 0;
     uint8_t vlan_status = 0, vlan_offset = 0;
+    uint8_t min_buf[MIN_BUF_SIZE];
 
     if (!(s->mac_reg[RCTL] & E1000_RCTL_EN))
         return -1;
 
+    /* Pad to minimum Ethernet frame length */
+    if (size < sizeof(min_buf)) {
+        memcpy(min_buf, buf, size);
+        memset(&min_buf[size], 0, sizeof(min_buf) - size);
+        buf = min_buf;
+        size = sizeof(min_buf);
+    }
+
     if (size > s->rxbuf_size) {
         DBGOUT(RX, "packet too large for buffers (%lu > %d)\n",
                (unsigned long)size, s->rxbuf_size);
@@ -691,9 +700,14 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
 
     s->mac_reg[GPRC]++;
     s->mac_reg[TPR]++;
-    n = s->mac_reg[TORL];
-    if ((s->mac_reg[TORL] += size) < n)
+    /* TOR - Total Octets Received:
+     * This register includes bytes received in a packet from the <Destination
+     * Address> field through the <CRC> field, inclusively.
+     */
+    n = s->mac_reg[TORL] + size + /* Always include FCS length. */ 4;
+    if (n < s->mac_reg[TORL])
         s->mac_reg[TORH]++;
+    s->mac_reg[TORL] = n;
 
     n = E1000_ICS_RXT0;
     if ((rdt = s->mac_reg[RDT]) < s->mac_reg[RDH])
diff --git a/hw/eepro100.c b/hw/eepro100.c
index 8cbc3aa7a2..41d792ad24 100644
--- a/hw/eepro100.c
+++ b/hw/eepro100.c
@@ -219,7 +219,8 @@ typedef enum {
 
 typedef struct {
     PCIDevice dev;
-    uint8_t mult[8];            /* multicast mask array */
+    /* Hash register (multicast mask array, multiple individual addresses). */
+    uint8_t mult[8];
     int mmio_index;
     NICState *nic;
     NICConf conf;
@@ -599,7 +600,7 @@ static void nic_reset(void *opaque)
 {
     EEPRO100State *s = opaque;
     TRACE(OTHER, logout("%p\n", s));
-    /* TODO: Clearing of multicast table for selective reset, too? */
+    /* TODO: Clearing of hash register for selective reset, too? */
     memset(&s->mult[0], 0, sizeof(s->mult));
     nic_selective_reset(s);
 }
@@ -851,7 +852,14 @@ static void action_command(EEPRO100State *s)
         case CmdConfigure:
             cpu_physical_memory_read(s->cb_address + 8, &s->configuration[0],
                                      sizeof(s->configuration));
-            TRACE(OTHER, logout("configuration: %s\n", nic_dump(&s->configuration[0], 16)));
+            TRACE(OTHER, logout("configuration: %s\n",
+                                nic_dump(&s->configuration[0], 16)));
+            TRACE(OTHER, logout("configuration: %s\n",
+                                nic_dump(&s->configuration[16],
+                                ARRAY_SIZE(s->configuration) - 16)));
+            if (s->configuration[20] & BIT(6)) {
+                TRACE(OTHER, logout("Multiple IA bit\n"));
+            }
             break;
         case CmdMulticastList:
             set_multicast_list(s);
@@ -1282,7 +1290,7 @@ static void eepro100_write_port(EEPRO100State * s, uint32_t val)
 
 static uint8_t eepro100_read1(EEPRO100State * s, uint32_t addr)
 {
-    uint8_t val;
+    uint8_t val = 0;
     if (addr <= sizeof(s->mem) - sizeof(val)) {
         memcpy(&val, &s->mem[addr], sizeof(val));
     }
@@ -1325,7 +1333,7 @@ static uint8_t eepro100_read1(EEPRO100State * s, uint32_t addr)
 
 static uint16_t eepro100_read2(EEPRO100State * s, uint32_t addr)
 {
-    uint16_t val;
+    uint16_t val = 0;
     if (addr <= sizeof(s->mem) - sizeof(val)) {
         memcpy(&val, &s->mem[addr], sizeof(val));
     }
@@ -1348,7 +1356,7 @@ static uint16_t eepro100_read2(EEPRO100State * s, uint32_t addr)
 
 static uint32_t eepro100_read4(EEPRO100State * s, uint32_t addr)
 {
-    uint32_t val;
+    uint32_t val = 0;
     if (addr <= sizeof(s->mem) - sizeof(val)) {
         memcpy(&val, &s->mem[addr], sizeof(val));
     }
@@ -1647,12 +1655,6 @@ static ssize_t nic_receive(VLANClientState *nc, const uint8_t * buf, size_t size
     static const uint8_t broadcast_macaddr[6] =
         { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
-    /* TODO: check multiple IA bit. */
-    if (s->configuration[20] & BIT(6)) {
-        missing("Multiple IA bit");
-        return -1;
-    }
-
     if (s->configuration[8] & 0x80) {
         /* CSMA is disabled. */
         logout("%p received while CSMA is disabled\n", s);
@@ -1702,6 +1704,16 @@ static ssize_t nic_receive(VLANClientState *nc, const uint8_t * buf, size_t size
         /* Promiscuous: receive all. */
         TRACE(RXTX, logout("%p received frame in promiscuous mode, len=%zu\n", s, size));
         rfd_status |= 0x0004;
+    } else if (s->configuration[20] & BIT(6)) {
+        /* Multiple IA bit set. */
+        unsigned mcast_idx = compute_mcast_idx(buf);
+        assert(mcast_idx < 64);
+        if (s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))) {
+            TRACE(RXTX, logout("%p accepted, multiple IA bit set\n", s));
+        } else {
+            TRACE(RXTX, logout("%p frame ignored, multiple IA bit set\n", s));
+            return -1;
+        }
     } else {
         TRACE(RXTX, logout("%p received frame, ignored, len=%zu,%s\n", s, size,
               nic_dump(buf, size)));
diff --git a/hw/elf_ops.h b/hw/elf_ops.h
index 27d1ab9bc2..0bd72350b4 100644
--- a/hw/elf_ops.h
+++ b/hw/elf_ops.h
@@ -153,6 +153,11 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab,
         syms = qemu_realloc(syms, nsyms * sizeof(*syms));
 
         qsort(syms, nsyms, sizeof(*syms), glue(symcmp, SZ));
+        for (i = 0; i < nsyms - 1; i++) {
+            if (syms[i].st_size == 0) {
+                syms[i].st_size = syms[i + 1].st_value - syms[i].st_value;
+            }
+        }
     } else {
         qemu_free(syms);
         syms = NULL;
diff --git a/hw/escc.c b/hw/escc.c
index 6d2fd36b11..8714239780 100644
--- a/hw/escc.c
+++ b/hw/escc.c
@@ -65,6 +65,8 @@
  *  2006-Aug-10  Igor Kovalenko :   Renamed KBDQueue to SERIOQueue, implemented
  *                                  serial mouse queue.
  *                                  Implemented serial mouse protocol.
+ *
+ *  2010-May-23  Artyom Tarasenko:  Reworked IUS logic
  */
 
 #ifdef DEBUG_SERIAL
@@ -279,7 +281,7 @@ static uint32_t get_queue(void *opaque)
 
 static int escc_update_irq_chn(ChannelState *s)
 {
-    if ((((s->wregs[W_INTR] & INTR_TXINT) && s->txint == 1) ||
+    if ((((s->wregs[W_INTR] & INTR_TXINT) && (s->txint == 1)) ||
          // tx ints enabled, pending
          ((((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINT1ST) ||
            ((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINTALL)) &&
@@ -342,24 +344,22 @@ static void escc_reset(DeviceState *d)
 static inline void set_rxint(ChannelState *s)
 {
     s->rxint = 1;
-    if (!s->txint_under_svc) {
-        s->rxint_under_svc = 1;
-        if (s->chn == chn_a) {
-            if (s->wregs[W_MINTR] & MINTR_STATUSHI)
-                s->otherchn->rregs[R_IVEC] = IVEC_HIRXINTA;
-            else
-                s->otherchn->rregs[R_IVEC] = IVEC_LORXINTA;
-        } else {
-            if (s->wregs[W_MINTR] & MINTR_STATUSHI)
-                s->rregs[R_IVEC] = IVEC_HIRXINTB;
-            else
-                s->rregs[R_IVEC] = IVEC_LORXINTB;
-        }
-    }
-    if (s->chn == chn_a)
+    /* XXX: missing daisy chainnig: chn_b rx should have a lower priority
+       than chn_a rx/tx/special_condition service*/
+    s->rxint_under_svc = 1;
+    if (s->chn == chn_a) {
         s->rregs[R_INTR] |= INTR_RXINTA;
-    else
+        if (s->wregs[W_MINTR] & MINTR_STATUSHI)
+            s->otherchn->rregs[R_IVEC] = IVEC_HIRXINTA;
+        else
+            s->otherchn->rregs[R_IVEC] = IVEC_LORXINTA;
+    } else {
         s->otherchn->rregs[R_INTR] |= INTR_RXINTB;
+        if (s->wregs[W_MINTR] & MINTR_STATUSHI)
+            s->rregs[R_IVEC] = IVEC_HIRXINTB;
+        else
+            s->rregs[R_IVEC] = IVEC_LORXINTB;
+    }
     escc_update_irq(s);
 }
 
@@ -369,19 +369,17 @@ static inline void set_txint(ChannelState *s)
     if (!s->rxint_under_svc) {
         s->txint_under_svc = 1;
         if (s->chn == chn_a) {
+            s->rregs[R_INTR] |= INTR_TXINTA;
             if (s->wregs[W_MINTR] & MINTR_STATUSHI)
                 s->otherchn->rregs[R_IVEC] = IVEC_HITXINTA;
             else
                 s->otherchn->rregs[R_IVEC] = IVEC_LOTXINTA;
         } else {
             s->rregs[R_IVEC] = IVEC_TXINTB;
+            s->otherchn->rregs[R_INTR] |= INTR_TXINTB;
         }
-    }
-    if (s->chn == chn_a)
-        s->rregs[R_INTR] |= INTR_TXINTA;
-    else
-        s->otherchn->rregs[R_INTR] |= INTR_TXINTB;
     escc_update_irq(s);
+    }
 }
 
 static inline void clr_rxint(ChannelState *s)
@@ -417,6 +415,7 @@ static inline void clr_txint(ChannelState *s)
             s->otherchn->rregs[R_IVEC] = IVEC_LONOINT;
         s->rregs[R_INTR] &= ~INTR_TXINTA;
     } else {
+        s->otherchn->rregs[R_INTR] &= ~INTR_TXINTB;
         if (s->wregs[W_MINTR] & MINTR_STATUSHI)
             s->rregs[R_IVEC] = IVEC_HINOINT;
         else
@@ -515,10 +514,15 @@ static void escc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
                 clr_txint(s);
                 break;
             case CMD_CLR_IUS:
-                if (s->rxint_under_svc)
-                    clr_rxint(s);
-                else if (s->txint_under_svc)
-                    clr_txint(s);
+                if (s->rxint_under_svc) {
+                    s->rxint_under_svc = 0;
+                    if (s->txint) {
+                        set_txint(s);
+                    }
+                } else if (s->txint_under_svc) {
+                    s->txint_under_svc = 0;
+                }
+                escc_update_irq(s);
                 break;
             default:
                 break;
diff --git a/hw/esp.c b/hw/esp.c
index 349052a024..910fd31665 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -80,6 +80,8 @@ struct ESPState {
     ESPDMAMemoryReadWriteFunc dma_memory_read;
     ESPDMAMemoryReadWriteFunc dma_memory_write;
     void *dma_opaque;
+    int dma_enabled;
+    void (*dma_cb)(ESPState *s);
 };
 
 #define ESP_TCLO   0x0
@@ -167,6 +169,24 @@ static void esp_lower_irq(ESPState *s)
     }
 }
 
+static void esp_dma_enable(void *opaque, int irq, int level)
+{
+    DeviceState *d = opaque;
+    ESPState *s = container_of(d, ESPState, busdev.qdev);
+
+    if (level) {
+        s->dma_enabled = 1;
+        DPRINTF("Raise enable\n");
+        if (s->dma_cb) {
+            s->dma_cb(s);
+            s->dma_cb = NULL;
+        }
+    } else {
+        DPRINTF("Lower enable\n");
+        s->dma_enabled = 0;
+    }
+}
+
 static uint32_t get_cmd(ESPState *s, uint8_t *buf)
 {
     uint32_t dmalen;
@@ -243,6 +263,10 @@ static void handle_satn(ESPState *s)
     uint8_t buf[32];
     int len;
 
+    if (!s->dma_enabled) {
+        s->dma_cb = handle_satn;
+        return;
+    }
     len = get_cmd(s, buf);
     if (len)
         do_cmd(s, buf);
@@ -253,6 +277,10 @@ static void handle_s_without_atn(ESPState *s)
     uint8_t buf[32];
     int len;
 
+    if (!s->dma_enabled) {
+        s->dma_cb = handle_s_without_atn;
+        return;
+    }
     len = get_cmd(s, buf);
     if (len) {
         do_busid_cmd(s, buf, 0);
@@ -261,6 +289,10 @@ static void handle_s_without_atn(ESPState *s)
 
 static void handle_satn_stop(ESPState *s)
 {
+    if (!s->dma_enabled) {
+        s->dma_cb = handle_satn_stop;
+        return;
+    }
     s->cmdlen = get_cmd(s, s->cmdbuf);
     if (s->cmdlen) {
         DPRINTF("Set ATN & Stop: cmdlen %d\n", s->cmdlen);
@@ -431,6 +463,7 @@ static void esp_hard_reset(DeviceState *d)
     s->ti_wptr = 0;
     s->dma = 0;
     s->do_cmd = 0;
+    s->dma_cb = NULL;
 
     s->rregs[ESP_CFG1] = 7;
 }
@@ -450,6 +483,18 @@ static void parent_esp_reset(void *opaque, int irq, int level)
     }
 }
 
+static void esp_gpio_demux(void *opaque, int irq, int level)
+{
+    switch (irq) {
+    case 0:
+        parent_esp_reset(opaque, irq, level);
+        break;
+    case 1:
+        esp_dma_enable(opaque, irq, level);
+        break;
+    }
+}
+
 static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
 {
     ESPState *s = opaque;
@@ -646,7 +691,8 @@ static const VMStateDescription vmstate_esp = {
 void esp_init(target_phys_addr_t espaddr, int it_shift,
               ESPDMAMemoryReadWriteFunc dma_memory_read,
               ESPDMAMemoryReadWriteFunc dma_memory_write,
-              void *dma_opaque, qemu_irq irq, qemu_irq *reset)
+              void *dma_opaque, qemu_irq irq, qemu_irq *reset,
+              qemu_irq *dma_enable)
 {
     DeviceState *dev;
     SysBusDevice *s;
@@ -658,11 +704,14 @@ void esp_init(target_phys_addr_t espaddr, int it_shift,
     esp->dma_memory_write = dma_memory_write;
     esp->dma_opaque = dma_opaque;
     esp->it_shift = it_shift;
+    /* XXX for now until rc4030 has been changed to use DMA enable signal */
+    esp->dma_enabled = 1;
     qdev_init_nofail(dev);
     s = sysbus_from_qdev(dev);
     sysbus_connect_irq(s, 0, irq);
     sysbus_mmio_map(s, 0, espaddr);
     *reset = qdev_get_gpio_in(dev, 0);
+    *dma_enable = qdev_get_gpio_in(dev, 1);
 }
 
 static int esp_init1(SysBusDevice *dev)
@@ -676,7 +725,7 @@ static int esp_init1(SysBusDevice *dev)
     esp_io_memory = cpu_register_io_memory(esp_mem_read, esp_mem_write, s);
     sysbus_init_mmio(dev, ESP_REGS << s->it_shift, esp_io_memory);
 
-    qdev_init_gpio_in(&dev->qdev, parent_esp_reset, 1);
+    qdev_init_gpio_in(&dev->qdev, esp_gpio_demux, 2);
 
     scsi_bus_new(&s->bus, &dev->qdev, 0, ESP_MAX_DEVS, esp_command_complete);
     return scsi_bus_legacy_handle_cmdline(&s->bus);
diff --git a/hw/esp.h b/hw/esp.h
index 605f953754..62bfd4d129 100644
--- a/hw/esp.h
+++ b/hw/esp.h
@@ -7,6 +7,7 @@ typedef void (*ESPDMAMemoryReadWriteFunc)(void *opaque, uint8_t *buf, int len);
 void esp_init(target_phys_addr_t espaddr, int it_shift,
               ESPDMAMemoryReadWriteFunc dma_memory_read,
               ESPDMAMemoryReadWriteFunc dma_memory_write,
-              void *dma_opaque, qemu_irq irq, qemu_irq *reset);
+              void *dma_opaque, qemu_irq irq, qemu_irq *reset,
+              qemu_irq *dma_enable);
 
 #endif
diff --git a/hw/etraxfs.c b/hw/etraxfs.c
index 46e2920c23..5ee5f979aa 100644
--- a/hw/etraxfs.c
+++ b/hw/etraxfs.c
@@ -31,6 +31,7 @@
 #include "loader.h"
 #include "elf.h"
 #include "cris-boot.h"
+#include "blockdev.h"
 
 #define FLASH_SIZE 0x2000000
 #define INTMEM_SIZE (128 * 1024)
diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c
index 187ece19ea..ade96f14ac 100644
--- a/hw/etraxfs_eth.c
+++ b/hw/etraxfs_eth.c
@@ -437,6 +437,7 @@ eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
 				eth_validate_duplex(eth);
 			}
 			eth->mdio_bus.mdc = !!(value & 4);
+			eth->regs[addr] = value;
 			break;
 
 		case RW_REC_CTRL:
@@ -463,7 +464,7 @@ static int eth_match_groupaddr(struct fs_eth *eth, const unsigned char *sa)
 
 	/* First bit on the wire of a MAC address signals multicast or
 	   physical address.  */
-	if (!m_individual && !sa[0] & 1)
+	if (!m_individual && !(sa[0] & 1))
 		return 0;
 
 	/* Calculate the hash index for the GA registers. */
diff --git a/hw/fdc.c b/hw/fdc.c
index 2d50bd6a39..c159dcb630 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -34,6 +34,7 @@
 #include "isa.h"
 #include "sysbus.h"
 #include "qdev-addr.h"
+#include "blockdev.h"
 
 /********************************************************/
 /* debug Floppy devices */
diff --git a/hw/fdc.h b/hw/fdc.h
index b6b3772592..242730af8c 100644
--- a/hw/fdc.h
+++ b/hw/fdc.h
@@ -2,7 +2,6 @@
 #define HW_FDC_H
 
 /* fdc.c */
-#include "blockdev.h"
 #define MAX_FD 2
 
 typedef struct FDCtrl FDCtrl;
diff --git a/hw/file-op-9p.h b/hw/file-op-9p.h
index a741c93527..21d60b5855 100644
--- a/hw/file-op-9p.h
+++ b/hw/file-op-9p.h
@@ -24,8 +24,19 @@
 
 typedef enum
 {
-    SM_PASSTHROUGH = 1, /* uid/gid set on fileserver files */
-    SM_MAPPED,  /* uid/gid part of xattr */
+    /*
+     * Server will try to set uid/gid.
+     * On failure ignore the error.
+     */
+    SM_NONE = 0,
+    /*
+     * uid/gid set on fileserver files
+     */
+    SM_PASSTHROUGH = 1,
+    /*
+     * uid/gid part of xattr
+     */
+    SM_MAPPED,
 } SecModel;
 
 typedef struct FsCred
@@ -36,11 +47,14 @@ typedef struct FsCred
     dev_t   fc_rdev;
 } FsCred;
 
+struct xattr_operations;
+
 typedef struct FsContext
 {
     char *fs_root;
     SecModel fs_sm;
     uid_t uid;
+    struct xattr_operations **xops;
 } FsContext;
 
 extern void cred_init(FsCred *);
@@ -52,7 +66,7 @@ typedef struct FileOperations
     int (*chmod)(FsContext *, const char *, FsCred *);
     int (*chown)(FsContext *, const char *, FsCred *);
     int (*mknod)(FsContext *, const char *, FsCred *);
-    int (*utime)(FsContext *, const char *, const struct utimbuf *);
+    int (*utimensat)(FsContext *, const char *, const struct timespec *);
     int (*remove)(FsContext *, const char *);
     int (*symlink)(FsContext *, const char *, const char *, FsCred *);
     int (*link)(FsContext *, const char *, const char *);
@@ -66,14 +80,28 @@ typedef struct FileOperations
     off_t (*telldir)(FsContext *, DIR *);
     struct dirent *(*readdir)(FsContext *, DIR *);
     void (*seekdir)(FsContext *, DIR *, off_t);
-    ssize_t (*readv)(FsContext *, int, const struct iovec *, int);
-    ssize_t (*writev)(FsContext *, int, const struct iovec *, int);
-    off_t (*lseek)(FsContext *, int, off_t, int);
+    ssize_t (*preadv)(FsContext *, int, const struct iovec *, int, off_t);
+    ssize_t (*pwritev)(FsContext *, int, const struct iovec *, int, off_t);
     int (*mkdir)(FsContext *, const char *, FsCred *);
     int (*fstat)(FsContext *, int, struct stat *);
     int (*rename)(FsContext *, const char *, const char *);
     int (*truncate)(FsContext *, const char *, off_t);
     int (*fsync)(FsContext *, int);
+    int (*statfs)(FsContext *s, const char *path, struct statfs *stbuf);
+    ssize_t (*lgetxattr)(FsContext *, const char *,
+                         const char *, void *, size_t);
+    ssize_t (*llistxattr)(FsContext *, const char *, void *, size_t);
+    int (*lsetxattr)(FsContext *, const char *,
+                     const char *, void *, size_t, int);
+    int (*lremovexattr)(FsContext *, const char *, const char *);
     void *opaque;
 } FileOperations;
+
+static inline const char *rpath(FsContext *ctx, const char *path)
+{
+    /* FIXME: so wrong... */
+    static char buffer[4096];
+    snprintf(buffer, sizeof(buffer), "%s/%s", ctx->fs_root, path);
+    return buffer;
+}
 #endif
diff --git a/hw/fmopl.c b/hw/fmopl.c
index d1161f848f..3df1806a91 100644
--- a/hw/fmopl.c
+++ b/hw/fmopl.c
@@ -1342,8 +1342,9 @@ unsigned char OPLRead(FM_OPL *OPL,int a)
 		{
 			if(OPL->keyboardhandler_r)
 				return OPL->keyboardhandler_r(OPL->keyboard_param);
-			else
+			else {
 				LOG(LOG_WAR,("OPL:read unmapped KEYBOARD port\n"));
+			}
 		}
 		return 0;
 #if 0
@@ -1355,8 +1356,9 @@ unsigned char OPLRead(FM_OPL *OPL,int a)
 		{
 			if(OPL->porthandler_r)
 				return OPL->porthandler_r(OPL->port_param);
-			else
+			else {
 				LOG(LOG_WAR,("OPL:read unmapped I/O port\n"));
+			}
 		}
 		return 0;
 	case 0x1a: /* PCM-DATA    */
diff --git a/hw/gumstix.c b/hw/gumstix.c
index c343a166e8..af8b464b88 100644
--- a/hw/gumstix.c
+++ b/hw/gumstix.c
@@ -38,6 +38,7 @@
 #include "sysemu.h"
 #include "devices.h"
 #include "boards.h"
+#include "blockdev.h"
 
 static const int sector_len = 128 * 1024;
 
diff --git a/hw/hw.h b/hw/hw.h
index c2de6fe8c4..4405092b54 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -264,6 +264,8 @@ int register_savevm_live(DeviceState *dev,
                          void *opaque);
 
 void unregister_savevm(DeviceState *dev, const char *idstr, void *opaque);
+void register_device_unmigratable(DeviceState *dev, const char *idstr,
+                                                                void *opaque);
 
 typedef void QEMUResetHandler(void *opaque);
 
@@ -313,6 +315,11 @@ typedef struct {
     bool (*field_exists)(void *opaque, int version_id);
 } VMStateField;
 
+typedef struct VMStateSubsection {
+    const VMStateDescription *vmsd;
+    bool (*needed)(void *opaque);
+} VMStateSubsection;
+
 struct VMStateDescription {
     const char *name;
     int version_id;
@@ -323,6 +330,7 @@ struct VMStateDescription {
     int (*post_load)(void *opaque, int version_id);
     void (*pre_save)(void *opaque);
     VMStateField *fields;
+    const VMStateSubsection *subsections;
 };
 
 extern const VMStateInfo vmstate_info_int8;
diff --git a/hw/ide/core.c b/hw/ide/core.c
index af52c2cb2d..06b6e14e56 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -30,6 +30,7 @@
 #include "qemu-timer.h"
 #include "sysemu.h"
 #include "dma.h"
+#include "blockdev.h"
 
 #include <hw/ide/internal.h>
 
@@ -138,6 +139,7 @@ static void ide_identify(IDEState *s)
     put_le16(p + 61, s->nb_sectors >> 16);
     put_le16(p + 62, 0x07); /* single word dma0-2 supported */
     put_le16(p + 63, 0x07); /* mdma0-2 supported */
+    put_le16(p + 64, 0x03); /* pio3-4 supported */
     put_le16(p + 65, 120);
     put_le16(p + 66, 120);
     put_le16(p + 67, 120);
@@ -198,13 +200,12 @@ static void ide_atapi_identify(IDEState *s)
     put_le16(p + 53, 7); /* words 64-70, 54-58, 88 valid */
     put_le16(p + 62, 7);  /* single word dma0-2 supported */
     put_le16(p + 63, 7);  /* mdma0-2 supported */
-    put_le16(p + 64, 0x3f); /* PIO modes supported */
 #else
     put_le16(p + 49, 1 << 9); /* LBA supported, no DMA */
     put_le16(p + 53, 3); /* words 64-70, 54-58 valid */
     put_le16(p + 63, 0x103); /* DMA modes XXX: may be incorrect */
-    put_le16(p + 64, 1); /* PIO modes */
 #endif
+    put_le16(p + 64, 3); /* pio3-4 supported */
     put_le16(p + 65, 0xb4); /* minimum DMA multiword tx cycle time */
     put_le16(p + 66, 0xb4); /* recommended DMA multiword tx cycle time */
     put_le16(p + 67, 0x12c); /* minimum PIO cycle time without flow control */
@@ -1643,6 +1644,21 @@ static void ide_atapi_cmd(IDEState *s)
             ide_atapi_cmd_reply(s, len, max_len);
             break;
         }
+    case GPCMD_GET_EVENT_STATUS_NOTIFICATION:
+        max_len = ube16_to_cpu(packet + 7);
+
+        if (packet[1] & 0x01) { /* polling */
+            /* We don't support any event class (yet). */
+            cpu_to_ube16(buf, 0x00); /* No event descriptor returned */
+            buf[2] = 0x80;           /* No Event Available (NEA) */
+            buf[3] = 0x00;           /* Empty supported event classes */
+            ide_atapi_cmd_reply(s, 4, max_len);
+        } else { /* asynchronous mode */
+            /* Only polling is supported, asynchronous mode is not. */
+            ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+                                ASC_INV_FIELD_IN_CMD_PACKET);
+        }
+        break;
     default:
         ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
                             ASC_ILLEGAL_OPCODE);
@@ -2629,7 +2645,12 @@ int ide_init_drive(IDEState *s, BlockDriverState *bs,
     if (bdrv_get_type_hint(bs) == BDRV_TYPE_CDROM) {
         s->drive_kind = IDE_CD;
         bdrv_set_change_cb(bs, cdrom_change_cb, s);
+        bs->buffer_alignment = 2048;
     } else {
+        if (!bdrv_is_inserted(s->bs)) {
+            error_report("Device needs media, but drive is empty");
+            return -1;
+        }
         if (bdrv_is_read_only(bs)) {
             error_report("Can't use a read-only drive");
             return -1;
@@ -2659,7 +2680,8 @@ static void ide_init1(IDEBus *bus, int unit)
     s->bus = bus;
     s->unit = unit;
     s->drive_serial = drive_serial++;
-    s->io_buffer = qemu_blockalign(s->bs, IDE_DMA_BUF_SECTORS*512 + 4);
+    /* we need at least 2k alignment for accessing CDROMs using O_DIRECT */
+    s->io_buffer = qemu_memalign(2048, IDE_DMA_BUF_SECTORS*512 + 4);
     s->io_buffer_total_len = IDE_DMA_BUF_SECTORS*512 + 4;
     s->smart_selftest_data = qemu_blockalign(s->bs, 512);
     s->sector_write_timer = qemu_new_timer(vm_clock,
@@ -2729,6 +2751,7 @@ static EndTransferFunc* transfer_end_table[] = {
         ide_transfer_stop,
         ide_atapi_cmd_reply_end,
         ide_atapi_cmd,
+        ide_dummy_transfer_stop,
 };
 
 static int transfer_end_table_idx(EndTransferFunc *fn)
@@ -2752,26 +2775,28 @@ static int ide_drive_post_load(void *opaque, int version_id)
             s->cdrom_changed = 1;
         }
     }
+    return 0;
+}
+
+static int ide_drive_pio_post_load(void *opaque, int version_id)
+{
+    IDEState *s = opaque;
 
-    if (s->cur_io_buffer_len) {
-        s->end_transfer_func = transfer_end_table[s->end_transfer_fn_idx];
-        s->data_ptr = s->io_buffer + s->cur_io_buffer_offset;
-        s->data_end = s->data_ptr + s->cur_io_buffer_len;
+    if (s->end_transfer_fn_idx > ARRAY_SIZE(transfer_end_table)) {
+        return -EINVAL;
     }
-        
+    s->end_transfer_func = transfer_end_table[s->end_transfer_fn_idx];
+    s->data_ptr = s->io_buffer + s->cur_io_buffer_offset;
+    s->data_end = s->data_ptr + s->cur_io_buffer_len;
+
     return 0;
 }
 
-static void ide_drive_pre_save(void *opaque)
+static void ide_drive_pio_pre_save(void *opaque)
 {
     IDEState *s = opaque;
     int idx;
 
-    s->cur_io_buffer_len = 0;
-
-    if (!(s->status & DRQ_STAT))
-        return;
-
     s->cur_io_buffer_offset = s->data_ptr - s->io_buffer;
     s->cur_io_buffer_len = s->data_end - s->data_ptr;
 
@@ -2785,12 +2810,38 @@ static void ide_drive_pre_save(void *opaque)
     }
 }
 
+static bool ide_drive_pio_state_needed(void *opaque)
+{
+    IDEState *s = opaque;
+
+    return (s->status & DRQ_STAT) != 0;
+}
+
+const VMStateDescription vmstate_ide_drive_pio_state = {
+    .name = "ide_drive/pio_state",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_save = ide_drive_pio_pre_save,
+    .post_load = ide_drive_pio_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_INT32(req_nb_sectors, IDEState),
+        VMSTATE_VARRAY_INT32(io_buffer, IDEState, io_buffer_total_len, 1,
+			     vmstate_info_uint8, uint8_t),
+        VMSTATE_INT32(cur_io_buffer_offset, IDEState),
+        VMSTATE_INT32(cur_io_buffer_len, IDEState),
+        VMSTATE_UINT8(end_transfer_fn_idx, IDEState),
+        VMSTATE_INT32(elementary_transfer_size, IDEState),
+        VMSTATE_INT32(packet_transfer_size, IDEState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 const VMStateDescription vmstate_ide_drive = {
     .name = "ide_drive",
-    .version_id = 4,
+    .version_id = 3,
     .minimum_version_id = 0,
     .minimum_version_id_old = 0,
-    .pre_save = ide_drive_pre_save,
     .post_load = ide_drive_post_load,
     .fields      = (VMStateField []) {
         VMSTATE_INT32(mult_sectors, IDEState),
@@ -2813,15 +2864,15 @@ const VMStateDescription vmstate_ide_drive = {
         VMSTATE_UINT8(sense_key, IDEState),
         VMSTATE_UINT8(asc, IDEState),
         VMSTATE_UINT8_V(cdrom_changed, IDEState, 3),
-        VMSTATE_INT32_V(req_nb_sectors, IDEState, 4),
-        VMSTATE_VARRAY_INT32(io_buffer, IDEState, io_buffer_total_len, 4,
-			     vmstate_info_uint8, uint8_t),
-        VMSTATE_INT32_V(cur_io_buffer_offset, IDEState, 4),
-        VMSTATE_INT32_V(cur_io_buffer_len, IDEState, 4),
-        VMSTATE_UINT8_V(end_transfer_fn_idx, IDEState, 4),
-        VMSTATE_INT32_V(elementary_transfer_size, IDEState, 4),
-        VMSTATE_INT32_V(packet_transfer_size, IDEState, 4),
         VMSTATE_END_OF_LIST()
+    },
+    .subsections = (VMStateSubsection []) {
+        {
+            .vmsd = &vmstate_ide_drive_pio_state,
+            .needed = ide_drive_pio_state_needed,
+        }, {
+            /* empty */
+        }
     }
 };
 
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index 4d95cc5e22..ec90f266e9 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -40,8 +40,27 @@ void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
     printf("%s: 0x%08x\n", __func__, val);
 #endif
     if (!(val & BM_CMD_START)) {
-        /* XXX: do it better */
-        ide_dma_cancel(bm);
+        /*
+         * We can't cancel Scatter Gather DMA in the middle of the
+         * operation or a partial (not full) DMA transfer would reach
+         * the storage so we wait for completion instead (we beahve
+         * like if the DMA was completed by the time the guest trying
+         * to cancel dma with bmdma_cmd_writeb with BM_CMD_START not
+         * set).
+         *
+         * In the future we'll be able to safely cancel the I/O if the
+         * whole DMA operation will be submitted to disk with a single
+         * aio operation with preadv/pwritev.
+         */
+        if (bm->aiocb) {
+            qemu_aio_flush();
+#ifdef DEBUG_IDE
+            if (bm->aiocb)
+                printf("ide_dma_cancel: aiocb still pending");
+            if (bm->status & BM_STATUS_DMAING)
+                printf("ide_dma_cancel: BM_STATUS_DMAING still pending");
+#endif
+        }
         bm->cmd = val & 0x09;
     } else {
         if (!(bm->status & BM_STATUS_DMAING)) {
@@ -121,9 +140,31 @@ void bmdma_addr_writel(void *opaque, uint32_t addr, uint32_t val)
     bm->cur_addr = bm->addr;
 }
 
+static bool ide_bmdma_current_needed(void *opaque)
+{
+    BMDMAState *bm = opaque;
+
+    return (bm->cur_prd_len != 0);
+}
+
+static const VMStateDescription vmstate_bmdma_current = {
+    .name = "ide bmdma_current",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32(cur_addr, BMDMAState),
+        VMSTATE_UINT32(cur_prd_last, BMDMAState),
+        VMSTATE_UINT32(cur_prd_addr, BMDMAState),
+        VMSTATE_UINT32(cur_prd_len, BMDMAState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+
 static const VMStateDescription vmstate_bmdma = {
     .name = "ide bmdma",
-    .version_id = 4,
+    .version_id = 3,
     .minimum_version_id = 0,
     .minimum_version_id_old = 0,
     .fields      = (VMStateField []) {
@@ -133,11 +174,15 @@ static const VMStateDescription vmstate_bmdma = {
         VMSTATE_INT64(sector_num, BMDMAState),
         VMSTATE_UINT32(nsector, BMDMAState),
         VMSTATE_UINT8(unit, BMDMAState),
-        VMSTATE_UINT32_V(cur_addr, BMDMAState, 4),
-        VMSTATE_UINT32_V(cur_prd_last, BMDMAState, 4),
-        VMSTATE_UINT32_V(cur_prd_addr, BMDMAState, 4),
-        VMSTATE_UINT32_V(cur_prd_len, BMDMAState, 4),
         VMSTATE_END_OF_LIST()
+    },
+    .subsections = (VMStateSubsection []) {
+        {
+            .vmsd = &vmstate_bmdma_current,
+            .needed = ide_bmdma_current_needed,
+        }, {
+            /* empty */
+        }
     }
 };
 
@@ -156,7 +201,7 @@ static int ide_pci_post_load(void *opaque, int version_id)
 
 const VMStateDescription vmstate_ide_pci = {
     .name = "ide",
-    .version_id = 4,
+    .version_id = 3,
     .minimum_version_id = 0,
     .minimum_version_id_old = 0,
     .post_load = ide_pci_post_load,
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index 53468edcbc..080876035f 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -20,6 +20,7 @@
 #include "dma.h"
 #include "qemu-error.h"
 #include <hw/ide/internal.h>
+#include "blockdev.h"
 
 /* --------------------------------- */
 
diff --git a/hw/ide/via.c b/hw/ide/via.c
index a403e8cd98..b2c7cad622 100644
--- a/hw/ide/via.c
+++ b/hw/ide/via.c
@@ -150,7 +150,6 @@ static int vt82c686b_ide_initfn(PCIDevice *dev)
     pci_config_set_class(pci_conf, PCI_CLASS_STORAGE_IDE);
     pci_config_set_prog_interface(pci_conf, 0x8a); /* legacy ATA mode */
     pci_config_set_revision(pci_conf,0x06); /* Revision 0.6 */
-    pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; /* header_type */
     pci_set_long(pci_conf + PCI_CAPABILITY_LIST, 0x000000c0);
 
     qemu_register_reset(via_reset, d);
diff --git a/hw/ivshmem.c b/hw/ivshmem.c
new file mode 100644
index 0000000000..06dce70e78
--- /dev/null
+++ b/hw/ivshmem.c
@@ -0,0 +1,829 @@
+/*
+ * Inter-VM Shared Memory PCI device.
+ *
+ * Author:
+ *      Cam Macdonell <cam@cs.ualberta.ca>
+ *
+ * Based On: cirrus_vga.c
+ *          Copyright (c) 2004 Fabrice Bellard
+ *          Copyright (c) 2004 Makoto Suzuki (suzu)
+ *
+ *      and rtl8139.c
+ *          Copyright (c) 2006 Igor Kovalenko
+ *
+ * This code is licensed under the GNU GPL v2.
+ */
+#include "hw.h"
+#include "pc.h"
+#include "pci.h"
+#include "msix.h"
+#include "kvm.h"
+
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#define IVSHMEM_IOEVENTFD   0
+#define IVSHMEM_MSI     1
+
+#define IVSHMEM_PEER    0
+#define IVSHMEM_MASTER  1
+
+#define IVSHMEM_REG_BAR_SIZE 0x100
+
+//#define DEBUG_IVSHMEM
+#ifdef DEBUG_IVSHMEM
+#define IVSHMEM_DPRINTF(fmt, ...)        \
+    do {printf("IVSHMEM: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define IVSHMEM_DPRINTF(fmt, ...)
+#endif
+
+typedef struct Peer {
+    int nb_eventfds;
+    int *eventfds;
+} Peer;
+
+typedef struct EventfdEntry {
+    PCIDevice *pdev;
+    int vector;
+} EventfdEntry;
+
+typedef struct IVShmemState {
+    PCIDevice dev;
+    uint32_t intrmask;
+    uint32_t intrstatus;
+    uint32_t doorbell;
+
+    CharDriverState **eventfd_chr;
+    CharDriverState *server_chr;
+    int ivshmem_mmio_io_addr;
+
+    pcibus_t mmio_addr;
+    pcibus_t shm_pci_addr;
+    uint64_t ivshmem_offset;
+    uint64_t ivshmem_size; /* size of shared memory region */
+    int shm_fd; /* shared memory file descriptor */
+
+    Peer *peers;
+    int nb_peers; /* how many guests we have space for */
+    int max_peer; /* maximum numbered peer */
+
+    int vm_id;
+    uint32_t vectors;
+    uint32_t features;
+    EventfdEntry *eventfd_table;
+
+    char * shmobj;
+    char * sizearg;
+    char * role;
+    int role_val;   /* scalar to avoid multiple string comparisons */
+} IVShmemState;
+
+/* registers for the Inter-VM shared memory device */
+enum ivshmem_registers {
+    INTRMASK = 0,
+    INTRSTATUS = 4,
+    IVPOSITION = 8,
+    DOORBELL = 12,
+};
+
+static inline uint32_t ivshmem_has_feature(IVShmemState *ivs,
+                                                    unsigned int feature) {
+    return (ivs->features & (1 << feature));
+}
+
+static inline bool is_power_of_two(uint64_t x) {
+    return (x & (x - 1)) == 0;
+}
+
+static void ivshmem_map(PCIDevice *pci_dev, int region_num,
+                    pcibus_t addr, pcibus_t size, int type)
+{
+    IVShmemState *s = DO_UPCAST(IVShmemState, dev, pci_dev);
+
+    s->shm_pci_addr = addr;
+
+    if (s->ivshmem_offset > 0) {
+        cpu_register_physical_memory(s->shm_pci_addr, s->ivshmem_size,
+                                                            s->ivshmem_offset);
+    }
+
+    IVSHMEM_DPRINTF("guest pci addr = %" FMT_PCIBUS ", guest h/w addr = %"
+        PRIu64 ", size = %" FMT_PCIBUS "\n", addr, s->ivshmem_offset, size);
+
+}
+
+/* accessing registers - based on rtl8139 */
+static void ivshmem_update_irq(IVShmemState *s, int val)
+{
+    int isr;
+    isr = (s->intrstatus & s->intrmask) & 0xffffffff;
+
+    /* don't print ISR resets */
+    if (isr) {
+        IVSHMEM_DPRINTF("Set IRQ to %d (%04x %04x)\n",
+           isr ? 1 : 0, s->intrstatus, s->intrmask);
+    }
+
+    qemu_set_irq(s->dev.irq[0], (isr != 0));
+}
+
+static void ivshmem_IntrMask_write(IVShmemState *s, uint32_t val)
+{
+    IVSHMEM_DPRINTF("IntrMask write(w) val = 0x%04x\n", val);
+
+    s->intrmask = val;
+
+    ivshmem_update_irq(s, val);
+}
+
+static uint32_t ivshmem_IntrMask_read(IVShmemState *s)
+{
+    uint32_t ret = s->intrmask;
+
+    IVSHMEM_DPRINTF("intrmask read(w) val = 0x%04x\n", ret);
+
+    return ret;
+}
+
+static void ivshmem_IntrStatus_write(IVShmemState *s, uint32_t val)
+{
+    IVSHMEM_DPRINTF("IntrStatus write(w) val = 0x%04x\n", val);
+
+    s->intrstatus = val;
+
+    ivshmem_update_irq(s, val);
+    return;
+}
+
+static uint32_t ivshmem_IntrStatus_read(IVShmemState *s)
+{
+    uint32_t ret = s->intrstatus;
+
+    /* reading ISR clears all interrupts */
+    s->intrstatus = 0;
+
+    ivshmem_update_irq(s, 0);
+
+    return ret;
+}
+
+static void ivshmem_io_writew(void *opaque, target_phys_addr_t addr,
+                                                            uint32_t val)
+{
+
+    IVSHMEM_DPRINTF("We shouldn't be writing words\n");
+}
+
+static void ivshmem_io_writel(void *opaque, target_phys_addr_t addr,
+                                                            uint32_t val)
+{
+    IVShmemState *s = opaque;
+
+    uint64_t write_one = 1;
+    uint16_t dest = val >> 16;
+    uint16_t vector = val & 0xff;
+
+    addr &= 0xfc;
+
+    IVSHMEM_DPRINTF("writing to addr " TARGET_FMT_plx "\n", addr);
+    switch (addr)
+    {
+        case INTRMASK:
+            ivshmem_IntrMask_write(s, val);
+            break;
+
+        case INTRSTATUS:
+            ivshmem_IntrStatus_write(s, val);
+            break;
+
+        case DOORBELL:
+            /* check that dest VM ID is reasonable */
+            if (dest > s->max_peer) {
+                IVSHMEM_DPRINTF("Invalid destination VM ID (%d)\n", dest);
+                break;
+            }
+
+            /* check doorbell range */
+            if (vector < s->peers[dest].nb_eventfds) {
+                IVSHMEM_DPRINTF("Writing %" PRId64 " to VM %d on vector %d\n",
+                                                    write_one, dest, vector);
+                if (write(s->peers[dest].eventfds[vector],
+                                                    &(write_one), 8) != 8) {
+                    IVSHMEM_DPRINTF("error writing to eventfd\n");
+                }
+            }
+            break;
+        default:
+            IVSHMEM_DPRINTF("Invalid VM Doorbell VM %d\n", dest);
+    }
+}
+
+static void ivshmem_io_writeb(void *opaque, target_phys_addr_t addr,
+                                                                uint32_t val)
+{
+    IVSHMEM_DPRINTF("We shouldn't be writing bytes\n");
+}
+
+static uint32_t ivshmem_io_readw(void *opaque, target_phys_addr_t addr)
+{
+
+    IVSHMEM_DPRINTF("We shouldn't be reading words\n");
+    return 0;
+}
+
+static uint32_t ivshmem_io_readl(void *opaque, target_phys_addr_t addr)
+{
+
+    IVShmemState *s = opaque;
+    uint32_t ret;
+
+    switch (addr)
+    {
+        case INTRMASK:
+            ret = ivshmem_IntrMask_read(s);
+            break;
+
+        case INTRSTATUS:
+            ret = ivshmem_IntrStatus_read(s);
+            break;
+
+        case IVPOSITION:
+            /* return my VM ID if the memory is mapped */
+            if (s->shm_fd > 0) {
+                ret = s->vm_id;
+            } else {
+                ret = -1;
+            }
+            break;
+
+        default:
+            IVSHMEM_DPRINTF("why are we reading " TARGET_FMT_plx "\n", addr);
+            ret = 0;
+    }
+
+    return ret;
+}
+
+static uint32_t ivshmem_io_readb(void *opaque, target_phys_addr_t addr)
+{
+    IVSHMEM_DPRINTF("We shouldn't be reading bytes\n");
+
+    return 0;
+}
+
+static CPUReadMemoryFunc * const ivshmem_mmio_read[3] = {
+    ivshmem_io_readb,
+    ivshmem_io_readw,
+    ivshmem_io_readl,
+};
+
+static CPUWriteMemoryFunc * const ivshmem_mmio_write[3] = {
+    ivshmem_io_writeb,
+    ivshmem_io_writew,
+    ivshmem_io_writel,
+};
+
+static void ivshmem_receive(void *opaque, const uint8_t *buf, int size)
+{
+    IVShmemState *s = opaque;
+
+    ivshmem_IntrStatus_write(s, *buf);
+
+    IVSHMEM_DPRINTF("ivshmem_receive 0x%02x\n", *buf);
+}
+
+static int ivshmem_can_receive(void * opaque)
+{
+    return 8;
+}
+
+static void ivshmem_event(void *opaque, int event)
+{
+    IVSHMEM_DPRINTF("ivshmem_event %d\n", event);
+}
+
+static void fake_irqfd(void *opaque, const uint8_t *buf, int size) {
+
+    EventfdEntry *entry = opaque;
+    PCIDevice *pdev = entry->pdev;
+
+    IVSHMEM_DPRINTF("interrupt on vector %p %d\n", pdev, entry->vector);
+    msix_notify(pdev, entry->vector);
+}
+
+static CharDriverState* create_eventfd_chr_device(void * opaque, int eventfd,
+                                                                    int vector)
+{
+    /* create a event character device based on the passed eventfd */
+    IVShmemState *s = opaque;
+    CharDriverState * chr;
+
+    chr = qemu_chr_open_eventfd(eventfd);
+
+    if (chr == NULL) {
+        fprintf(stderr, "creating eventfd for eventfd %d failed\n", eventfd);
+        exit(-1);
+    }
+
+    /* if MSI is supported we need multiple interrupts */
+    if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
+        s->eventfd_table[vector].pdev = &s->dev;
+        s->eventfd_table[vector].vector = vector;
+
+        qemu_chr_add_handlers(chr, ivshmem_can_receive, fake_irqfd,
+                      ivshmem_event, &s->eventfd_table[vector]);
+    } else {
+        qemu_chr_add_handlers(chr, ivshmem_can_receive, ivshmem_receive,
+                      ivshmem_event, s);
+    }
+
+    return chr;
+
+}
+
+static int check_shm_size(IVShmemState *s, int fd) {
+    /* check that the guest isn't going to try and map more memory than the
+     * the object has allocated return -1 to indicate error */
+
+    struct stat buf;
+
+    fstat(fd, &buf);
+
+    if (s->ivshmem_size > buf.st_size) {
+        fprintf(stderr,
+                "IVSHMEM ERROR: Requested memory size greater"
+                " than shared object size (%" PRIu64 " > %" PRIu64")\n",
+                s->ivshmem_size, (uint64_t)buf.st_size);
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+/* create the shared memory BAR when we are not using the server, so we can
+ * create the BAR and map the memory immediately */
+static void create_shared_memory_BAR(IVShmemState *s, int fd) {
+
+    void * ptr;
+
+    s->shm_fd = fd;
+
+    ptr = mmap(0, s->ivshmem_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+
+    s->ivshmem_offset = qemu_ram_alloc_from_ptr(&s->dev.qdev, "ivshmem.bar2",
+                                                        s->ivshmem_size, ptr);
+
+    /* region for shared memory */
+    pci_register_bar(&s->dev, 2, s->ivshmem_size,
+                                PCI_BASE_ADDRESS_SPACE_MEMORY, ivshmem_map);
+}
+
+static void close_guest_eventfds(IVShmemState *s, int posn)
+{
+    int i, guest_curr_max;
+
+    guest_curr_max = s->peers[posn].nb_eventfds;
+
+    for (i = 0; i < guest_curr_max; i++) {
+        kvm_set_ioeventfd_mmio_long(s->peers[posn].eventfds[i],
+                    s->mmio_addr + DOORBELL, (posn << 16) | i, 0);
+        close(s->peers[posn].eventfds[i]);
+    }
+
+    qemu_free(s->peers[posn].eventfds);
+    s->peers[posn].nb_eventfds = 0;
+}
+
+static void setup_ioeventfds(IVShmemState *s) {
+
+    int i, j;
+
+    for (i = 0; i <= s->max_peer; i++) {
+        for (j = 0; j < s->peers[i].nb_eventfds; j++) {
+            kvm_set_ioeventfd_mmio_long(s->peers[i].eventfds[j],
+                    s->mmio_addr + DOORBELL, (i << 16) | j, 1);
+        }
+    }
+}
+
+/* this function increase the dynamic storage need to store data about other
+ * guests */
+static void increase_dynamic_storage(IVShmemState *s, int new_min_size) {
+
+    int j, old_nb_alloc;
+
+    old_nb_alloc = s->nb_peers;
+
+    while (new_min_size >= s->nb_peers)
+        s->nb_peers = s->nb_peers * 2;
+
+    IVSHMEM_DPRINTF("bumping storage to %d guests\n", s->nb_peers);
+    s->peers = qemu_realloc(s->peers, s->nb_peers * sizeof(Peer));
+
+    /* zero out new pointers */
+    for (j = old_nb_alloc; j < s->nb_peers; j++) {
+        s->peers[j].eventfds = NULL;
+        s->peers[j].nb_eventfds = 0;
+    }
+}
+
+static void ivshmem_read(void *opaque, const uint8_t * buf, int flags)
+{
+    IVShmemState *s = opaque;
+    int incoming_fd, tmp_fd;
+    int guest_max_eventfd;
+    long incoming_posn;
+
+    memcpy(&incoming_posn, buf, sizeof(long));
+    /* pick off s->server_chr->msgfd and store it, posn should accompany msg */
+    tmp_fd = qemu_chr_get_msgfd(s->server_chr);
+    IVSHMEM_DPRINTF("posn is %ld, fd is %d\n", incoming_posn, tmp_fd);
+
+    /* make sure we have enough space for this guest */
+    if (incoming_posn >= s->nb_peers) {
+        increase_dynamic_storage(s, incoming_posn);
+    }
+
+    if (tmp_fd == -1) {
+        /* if posn is positive and unseen before then this is our posn*/
+        if ((incoming_posn >= 0) &&
+                            (s->peers[incoming_posn].eventfds == NULL)) {
+            /* receive our posn */
+            s->vm_id = incoming_posn;
+            return;
+        } else {
+            /* otherwise an fd == -1 means an existing guest has gone away */
+            IVSHMEM_DPRINTF("posn %ld has gone away\n", incoming_posn);
+            close_guest_eventfds(s, incoming_posn);
+            return;
+        }
+    }
+
+    /* because of the implementation of get_msgfd, we need a dup */
+    incoming_fd = dup(tmp_fd);
+
+    if (incoming_fd == -1) {
+        fprintf(stderr, "could not allocate file descriptor %s\n",
+                                                            strerror(errno));
+        return;
+    }
+
+    /* if the position is -1, then it's shared memory region fd */
+    if (incoming_posn == -1) {
+
+        void * map_ptr;
+
+        s->max_peer = 0;
+
+        if (check_shm_size(s, incoming_fd) == -1) {
+            exit(-1);
+        }
+
+        /* mmap the region and map into the BAR2 */
+        map_ptr = mmap(0, s->ivshmem_size, PROT_READ|PROT_WRITE, MAP_SHARED,
+                                                            incoming_fd, 0);
+        s->ivshmem_offset = qemu_ram_alloc_from_ptr(&s->dev.qdev,
+                                    "ivshmem.bar2", s->ivshmem_size, map_ptr);
+
+        IVSHMEM_DPRINTF("guest pci addr = %" FMT_PCIBUS ", guest h/w addr = %"
+                         PRIu64 ", size = %" PRIu64 "\n", s->shm_pci_addr,
+                         s->ivshmem_offset, s->ivshmem_size);
+
+        if (s->shm_pci_addr > 0) {
+            /* map memory into BAR2 */
+            cpu_register_physical_memory(s->shm_pci_addr, s->ivshmem_size,
+                                                            s->ivshmem_offset);
+        }
+
+        /* only store the fd if it is successfully mapped */
+        s->shm_fd = incoming_fd;
+
+        return;
+    }
+
+    /* each guest has an array of eventfds, and we keep track of how many
+     * guests for each VM */
+    guest_max_eventfd = s->peers[incoming_posn].nb_eventfds;
+
+    if (guest_max_eventfd == 0) {
+        /* one eventfd per MSI vector */
+        s->peers[incoming_posn].eventfds = (int *) qemu_malloc(s->vectors *
+                                                                sizeof(int));
+    }
+
+    /* this is an eventfd for a particular guest VM */
+    IVSHMEM_DPRINTF("eventfds[%ld][%d] = %d\n", incoming_posn,
+                                            guest_max_eventfd, incoming_fd);
+    s->peers[incoming_posn].eventfds[guest_max_eventfd] = incoming_fd;
+
+    /* increment count for particular guest */
+    s->peers[incoming_posn].nb_eventfds++;
+
+    /* keep track of the maximum VM ID */
+    if (incoming_posn > s->max_peer) {
+        s->max_peer = incoming_posn;
+    }
+
+    if (incoming_posn == s->vm_id) {
+        s->eventfd_chr[guest_max_eventfd] = create_eventfd_chr_device(s,
+                   s->peers[s->vm_id].eventfds[guest_max_eventfd],
+                   guest_max_eventfd);
+    }
+
+    if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
+        if (kvm_set_ioeventfd_mmio_long(incoming_fd, s->mmio_addr + DOORBELL,
+                        (incoming_posn << 16) | guest_max_eventfd, 1) < 0) {
+            fprintf(stderr, "ivshmem: ioeventfd not available\n");
+        }
+    }
+
+    return;
+}
+
+static void ivshmem_reset(DeviceState *d)
+{
+    IVShmemState *s = DO_UPCAST(IVShmemState, dev.qdev, d);
+
+    s->intrstatus = 0;
+    return;
+}
+
+static void ivshmem_mmio_map(PCIDevice *pci_dev, int region_num,
+                       pcibus_t addr, pcibus_t size, int type)
+{
+    IVShmemState *s = DO_UPCAST(IVShmemState, dev, pci_dev);
+
+    s->mmio_addr = addr;
+    cpu_register_physical_memory(addr + 0, IVSHMEM_REG_BAR_SIZE,
+                                                s->ivshmem_mmio_io_addr);
+
+    if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
+        setup_ioeventfds(s);
+    }
+}
+
+static uint64_t ivshmem_get_size(IVShmemState * s) {
+
+    uint64_t value;
+    char *ptr;
+
+    value = strtoull(s->sizearg, &ptr, 10);
+    switch (*ptr) {
+        case 0: case 'M': case 'm':
+            value <<= 20;
+            break;
+        case 'G': case 'g':
+            value <<= 30;
+            break;
+        default:
+            fprintf(stderr, "qemu: invalid ram size: %s\n", s->sizearg);
+            exit(1);
+    }
+
+    /* BARs must be a power of 2 */
+    if (!is_power_of_two(value)) {
+        fprintf(stderr, "ivshmem: size must be power of 2\n");
+        exit(1);
+    }
+
+    return value;
+}
+
+static void ivshmem_setup_msi(IVShmemState * s) {
+
+    int i;
+
+    /* allocate the MSI-X vectors */
+
+    if (!msix_init(&s->dev, s->vectors, 1, 0)) {
+        pci_register_bar(&s->dev, 1,
+                         msix_bar_size(&s->dev),
+                         PCI_BASE_ADDRESS_SPACE_MEMORY,
+                         msix_mmio_map);
+        IVSHMEM_DPRINTF("msix initialized (%d vectors)\n", s->vectors);
+    } else {
+        IVSHMEM_DPRINTF("msix initialization failed\n");
+        exit(1);
+    }
+
+    /* 'activate' the vectors */
+    for (i = 0; i < s->vectors; i++) {
+        msix_vector_use(&s->dev, i);
+    }
+
+    /* allocate Qemu char devices for receiving interrupts */
+    s->eventfd_table = qemu_mallocz(s->vectors * sizeof(EventfdEntry));
+}
+
+static void ivshmem_save(QEMUFile* f, void *opaque)
+{
+    IVShmemState *proxy = opaque;
+
+    IVSHMEM_DPRINTF("ivshmem_save\n");
+    pci_device_save(&proxy->dev, f);
+
+    if (ivshmem_has_feature(proxy, IVSHMEM_MSI)) {
+        msix_save(&proxy->dev, f);
+    } else {
+        qemu_put_be32(f, proxy->intrstatus);
+        qemu_put_be32(f, proxy->intrmask);
+    }
+
+}
+
+static int ivshmem_load(QEMUFile* f, void *opaque, int version_id)
+{
+    IVSHMEM_DPRINTF("ivshmem_load\n");
+
+    IVShmemState *proxy = opaque;
+    int ret, i;
+
+    if (version_id > 0) {
+        return -EINVAL;
+    }
+
+    if (proxy->role_val == IVSHMEM_PEER) {
+        fprintf(stderr, "ivshmem: 'peer' devices are not migratable\n");
+        return -EINVAL;
+    }
+
+    ret = pci_device_load(&proxy->dev, f);
+    if (ret) {
+        return ret;
+    }
+
+    if (ivshmem_has_feature(proxy, IVSHMEM_MSI)) {
+        msix_load(&proxy->dev, f);
+        for (i = 0; i < proxy->vectors; i++) {
+            msix_vector_use(&proxy->dev, i);
+        }
+    } else {
+        proxy->intrstatus = qemu_get_be32(f);
+        proxy->intrmask = qemu_get_be32(f);
+    }
+
+    return 0;
+}
+
+static int pci_ivshmem_init(PCIDevice *dev)
+{
+    IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev);
+    uint8_t *pci_conf;
+
+    if (s->sizearg == NULL)
+        s->ivshmem_size = 4 << 20; /* 4 MB default */
+    else {
+        s->ivshmem_size = ivshmem_get_size(s);
+    }
+
+    register_savevm(&s->dev.qdev, "ivshmem", 0, 0, ivshmem_save, ivshmem_load,
+                                                                        dev);
+
+    /* IRQFD requires MSI */
+    if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD) &&
+        !ivshmem_has_feature(s, IVSHMEM_MSI)) {
+        fprintf(stderr, "ivshmem: ioeventfd/irqfd requires MSI\n");
+        exit(1);
+    }
+
+    /* check that role is reasonable */
+    if (s->role) {
+        if (strncmp(s->role, "peer", 5) == 0) {
+            s->role_val = IVSHMEM_PEER;
+        } else if (strncmp(s->role, "master", 7) == 0) {
+            s->role_val = IVSHMEM_MASTER;
+        } else {
+            fprintf(stderr, "ivshmem: 'role' must be 'peer' or 'master'\n");
+            exit(1);
+        }
+    } else {
+        s->role_val = IVSHMEM_MASTER; /* default */
+    }
+
+    if (s->role_val == IVSHMEM_PEER) {
+        register_device_unmigratable(&s->dev.qdev, "ivshmem", s);
+    }
+
+    pci_conf = s->dev.config;
+    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_REDHAT_QUMRANET);
+    pci_conf[0x02] = 0x10;
+    pci_conf[0x03] = 0x11;
+    pci_conf[PCI_COMMAND] = PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
+    pci_config_set_class(pci_conf, PCI_CLASS_MEMORY_RAM);
+    pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL;
+
+    pci_config_set_interrupt_pin(pci_conf, 1);
+
+    s->shm_pci_addr = 0;
+    s->ivshmem_offset = 0;
+    s->shm_fd = 0;
+
+    s->ivshmem_mmio_io_addr = cpu_register_io_memory(ivshmem_mmio_read,
+                                    ivshmem_mmio_write, s);
+    /* region for registers*/
+    pci_register_bar(&s->dev, 0, IVSHMEM_REG_BAR_SIZE,
+                           PCI_BASE_ADDRESS_SPACE_MEMORY, ivshmem_mmio_map);
+
+    if ((s->server_chr != NULL) &&
+                        (strncmp(s->server_chr->filename, "unix:", 5) == 0)) {
+        /* if we get a UNIX socket as the parameter we will talk
+         * to the ivshmem server to receive the memory region */
+
+        if (s->shmobj != NULL) {
+            fprintf(stderr, "WARNING: do not specify both 'chardev' "
+                                                "and 'shm' with ivshmem\n");
+        }
+
+        IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n",
+                                                    s->server_chr->filename);
+
+        if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
+            ivshmem_setup_msi(s);
+        }
+
+        /* we allocate enough space for 16 guests and grow as needed */
+        s->nb_peers = 16;
+        s->vm_id = -1;
+
+        /* allocate/initialize space for interrupt handling */
+        s->peers = qemu_mallocz(s->nb_peers * sizeof(Peer));
+
+        pci_register_bar(&s->dev, 2, s->ivshmem_size,
+                                PCI_BASE_ADDRESS_SPACE_MEMORY, ivshmem_map);
+
+        s->eventfd_chr = qemu_mallocz(s->vectors * sizeof(CharDriverState *));
+
+        qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive, ivshmem_read,
+                     ivshmem_event, s);
+    } else {
+        /* just map the file immediately, we're not using a server */
+        int fd;
+
+        if (s->shmobj == NULL) {
+            fprintf(stderr, "Must specify 'chardev' or 'shm' to ivshmem\n");
+        }
+
+        IVSHMEM_DPRINTF("using shm_open (shm object = %s)\n", s->shmobj);
+
+        /* try opening with O_EXCL and if it succeeds zero the memory
+         * by truncating to 0 */
+        if ((fd = shm_open(s->shmobj, O_CREAT|O_RDWR|O_EXCL,
+                        S_IRWXU|S_IRWXG|S_IRWXO)) > 0) {
+           /* truncate file to length PCI device's memory */
+            if (ftruncate(fd, s->ivshmem_size) != 0) {
+                fprintf(stderr, "ivshmem: could not truncate shared file\n");
+            }
+
+        } else if ((fd = shm_open(s->shmobj, O_CREAT|O_RDWR,
+                        S_IRWXU|S_IRWXG|S_IRWXO)) < 0) {
+            fprintf(stderr, "ivshmem: could not open shared file\n");
+            exit(-1);
+
+        }
+
+        if (check_shm_size(s, fd) == -1) {
+            exit(-1);
+        }
+
+        create_shared_memory_BAR(s, fd);
+
+    }
+
+    return 0;
+}
+
+static int pci_ivshmem_uninit(PCIDevice *dev)
+{
+    IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev);
+
+    cpu_unregister_io_memory(s->ivshmem_mmio_io_addr);
+    unregister_savevm(&dev->qdev, "ivshmem", s);
+
+    return 0;
+}
+
+static PCIDeviceInfo ivshmem_info = {
+    .qdev.name  = "ivshmem",
+    .qdev.size  = sizeof(IVShmemState),
+    .qdev.reset = ivshmem_reset,
+    .init       = pci_ivshmem_init,
+    .exit       = pci_ivshmem_uninit,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_CHR("chardev", IVShmemState, server_chr),
+        DEFINE_PROP_STRING("size", IVShmemState, sizearg),
+        DEFINE_PROP_UINT32("vectors", IVShmemState, vectors, 1),
+        DEFINE_PROP_BIT("ioeventfd", IVShmemState, features, IVSHMEM_IOEVENTFD, false),
+        DEFINE_PROP_BIT("msi", IVShmemState, features, IVSHMEM_MSI, true),
+        DEFINE_PROP_STRING("shm", IVShmemState, shmobj),
+        DEFINE_PROP_STRING("role", IVShmemState, role),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void ivshmem_register_devices(void)
+{
+    pci_qdev_register(&ivshmem_info);
+}
+
+device_init(ivshmem_register_devices)
diff --git a/hw/jazz_led.c b/hw/jazz_led.c
index 18780e9371..4cb680c3e4 100644
--- a/hw/jazz_led.c
+++ b/hw/jazz_led.c
@@ -29,6 +29,15 @@
 
 //#define DEBUG_LED
 
+#ifdef DEBUG_LED
+#define DPRINTF(fmt, ...) \
+do { printf("jazz led: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "jazz led ERROR: " fmt , ## __VA_ARGS__);} while (0)
+
 typedef enum {
     REDRAW_NONE = 0, REDRAW_SEGMENTS = 1, REDRAW_BACKGROUND = 2,
 } screen_state_t;
@@ -49,12 +58,12 @@ static uint32_t led_readb(void *opaque, target_phys_addr_t addr)
             val = s->segments;
             break;
         default:
-#ifdef DEBUG_LED
-            printf("jazz led: invalid read [0x%x]\n", relative_addr);
-#endif
+            BADF("invalid read at [" TARGET_FMT_plx "]\n", addr);
             val = 0;
     }
 
+    DPRINTF("read addr=" TARGET_FMT_plx " val=0x%02x\n", addr, val);
+
     return val;
 }
 
@@ -92,15 +101,15 @@ static void led_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
     LedState *s = opaque;
 
+    DPRINTF("write addr=" TARGET_FMT_plx " val=0x%02x\n", addr, val);
+
     switch (addr) {
         case 0:
             s->segments = val;
             s->state |= REDRAW_SEGMENTS;
             break;
         default:
-#ifdef DEBUG_LED
-            printf("jazz led: invalid write of 0x%02x at [0x%x]\n", val, relative_addr);
-#endif
+            BADF("invalid write of 0x%08x at [" TARGET_FMT_plx "]\n", val, addr);
             break;
     }
 }
diff --git a/hw/loader.c b/hw/loader.c
index 79a6f95186..49ac1fa1cc 100644
--- a/hw/loader.c
+++ b/hw/loader.c
@@ -733,11 +733,6 @@ int rom_copy(uint8_t *dest, target_phys_addr_t addr, size_t size)
         s = rom->data;
         l = rom->romsize;
 
-        if (rom->addr < addr) {
-            d = dest;
-            s += (addr - rom->addr);
-            l -= (addr - rom->addr);
-        }
         if ((d + l) > (dest + size)) {
             l = dest - d;
         }
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index bd7b661426..f97335eaa9 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -600,7 +600,7 @@ static void lsi_queue_command(LSIState *s)
 {
     lsi_request *p = s->current;
 
-    DPRINTF("Queueing tag=0x%x\n", s->current_tag);
+    DPRINTF("Queueing tag=0x%x\n", p->tag);
     assert(s->current != NULL);
     assert(s->current->dma_len == 0);
     QTAILQ_INSERT_TAIL(&s->queue, s->current, next);
@@ -864,6 +864,7 @@ static void lsi_do_msgout(LSIState *s)
         case 0x01:
             len = lsi_get_msgbyte(s);
             msg = lsi_get_msgbyte(s);
+            (void)len; /* avoid a warning about unused variable*/
             DPRINTF("Extended message 0x%x (len %d)\n", msg, len);
             switch (msg) {
             case 1:
@@ -880,7 +881,7 @@ static void lsi_do_msgout(LSIState *s)
             break;
         case 0x20: /* SIMPLE queue */
             s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
-            DPRINTF("SIMPLE queue tag=0x%x\n", s->current_tag & 0xff);
+            DPRINTF("SIMPLE queue tag=0x%x\n", s->select_tag & 0xff);
             break;
         case 0x21: /* HEAD of queue */
             BADF("HEAD queue not implemented\n");
diff --git a/hw/mainstone.c b/hw/mainstone.c
index cba7e63b3c..efa2959c72 100644
--- a/hw/mainstone.c
+++ b/hw/mainstone.c
@@ -17,6 +17,7 @@
 #include "mainstone.h"
 #include "sysemu.h"
 #include "flash.h"
+#include "blockdev.h"
 
 static struct keymap map[0xE0] = {
     [0 ... 0xDF] = { -1, -1 },
diff --git a/hw/mips_fulong2e.c b/hw/mips_fulong2e.c
index a9bbff64b3..07eb9eeba1 100644
--- a/hw/mips_fulong2e.c
+++ b/hw/mips_fulong2e.c
@@ -37,6 +37,7 @@
 #include "elf.h"
 #include "vt82c686.h"
 #include "mc146818rtc.h"
+#include "blockdev.h"
 
 #define DEBUG_FULONG2E_INIT
 
@@ -75,7 +76,8 @@ static struct _loaderparams {
     const char *initrd_filename;
 } loaderparams;
 
-static void prom_set(uint32_t* prom_buf, int index, const char *string, ...)
+static void GCC_FMT_ATTR(3, 4) prom_set(uint32_t* prom_buf, int index,
+                                        const char *string, ...)
 {
     va_list ap;
     int32_t table_addr;
@@ -140,13 +142,13 @@ static int64_t load_kernel (CPUState *env)
     prom_size = ENVP_NB_ENTRIES * (sizeof(int32_t) + ENVP_ENTRY_SIZE);
     prom_buf = qemu_malloc(prom_size);
 
-    prom_set(prom_buf, index++, loaderparams.kernel_filename);
+    prom_set(prom_buf, index++, "%s", loaderparams.kernel_filename);
     if (initrd_size > 0) {
-        prom_set(prom_buf, index++, "rd_start=0x" PRIx64 " rd_size=%li %s",
+        prom_set(prom_buf, index++, "rd_start=0x%" PRIx64 " rd_size=%li %s",
                  cpu_mips_phys_to_kseg0(NULL, initrd_offset), initrd_size,
                  loaderparams.kernel_cmdline);
     } else {
-        prom_set(prom_buf, index++, loaderparams.kernel_cmdline);
+        prom_set(prom_buf, index++, "%s", loaderparams.kernel_cmdline);
     }
 
     /* Setup minimum environment variables */
@@ -219,8 +221,8 @@ uint8_t eeprom_spd[0x80] = {
 #ifdef HAS_AUDIO
 static void audio_init (PCIBus *pci_bus)
 {
-    vt82c686b_ac97_init(pci_bus, (FULONG2E_VIA_SLOT << 3) + 5);
-    vt82c686b_mc97_init(pci_bus, (FULONG2E_VIA_SLOT << 3) + 6);
+    vt82c686b_ac97_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 5));
+    vt82c686b_mc97_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 6));
 }
 #endif
 
@@ -257,19 +259,17 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device,
 {
     char *filename;
     unsigned long ram_offset, bios_offset;
-    unsigned long bios_size;
+    long bios_size;
     int64_t kernel_entry;
     qemu_irq *i8259;
     qemu_irq *cpu_exit_irq;
     int via_devfn;
     PCIBus *pci_bus;
-    ISADevice *isa_dev;
     uint8_t *eeprom_buf;
     i2c_bus *smbus;
     int i;
     DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
     DeviceState *eeprom;
-    ISADevice *rtc_state;
     CPUState *env;
 
     /* init CPUs */
@@ -295,7 +295,7 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device,
     ram_offset = qemu_ram_alloc(NULL, "fulong2e.ram", ram_size);
     bios_offset = qemu_ram_alloc(NULL, "fulong2e.bios", bios_size);
 
-    cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
+    cpu_register_physical_memory(0, ram_size, ram_offset);
     cpu_register_physical_memory(0x1fc00000LL,
 					   bios_size, bios_offset | IO_MEM_ROM);
 
@@ -349,18 +349,18 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device,
         hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
     }
 
-    via_devfn = vt82c686b_init(pci_bus, FULONG2E_VIA_SLOT << 3);
+    via_devfn = vt82c686b_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 0));
     if (via_devfn < 0) {
         fprintf(stderr, "vt82c686b_init error \n");
         exit(1);
     }
 
     isa_bus_irqs(i8259);
-    vt82c686b_ide_init(pci_bus, hd, (FULONG2E_VIA_SLOT << 3) + 1);
-    usb_uhci_vt82c686b_init(pci_bus, (FULONG2E_VIA_SLOT << 3) + 2);
-    usb_uhci_vt82c686b_init(pci_bus, (FULONG2E_VIA_SLOT << 3) + 3);
+    vt82c686b_ide_init(pci_bus, hd, PCI_DEVFN(FULONG2E_VIA_SLOT, 1));
+    usb_uhci_vt82c686b_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 2));
+    usb_uhci_vt82c686b_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 3));
 
-    smbus = vt82c686b_pm_init(pci_bus, (FULONG2E_VIA_SLOT << 3) + 4,
+    smbus = vt82c686b_pm_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 4),
                               0xeee1, NULL);
     eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */
     memcpy(eeprom_buf, eeprom_spd, sizeof(eeprom_spd));
@@ -376,9 +376,9 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device,
     DMA_init(0, cpu_exit_irq);
 
     /* Super I/O */
-    isa_dev = isa_create_simple("i8042");
+    isa_create_simple("i8042");
 
-    rtc_state = rtc_init(2000, NULL);
+    rtc_init(2000, NULL);
 
     for(i = 0; i < MAX_SERIAL_PORTS; i++) {
         if (serial_hds[i]) {
diff --git a/hw/mips_int.c b/hw/mips_int.c
index c30954caaf..477f6abf95 100644
--- a/hw/mips_int.c
+++ b/hw/mips_int.c
@@ -24,22 +24,6 @@
 #include "mips_cpudevs.h"
 #include "cpu.h"
 
-/* Raise IRQ to CPU if necessary. It must be called every time the active
-   IRQ may change */
-void cpu_mips_update_irq(CPUState *env)
-{
-    if ((env->CP0_Status & (1 << CP0St_IE)) &&
-        !(env->CP0_Status & (1 << CP0St_EXL)) &&
-        !(env->CP0_Status & (1 << CP0St_ERL)) &&
-        !(env->hflags & MIPS_HFLAG_DM)) {
-        if ((env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
-            !(env->interrupt_request & CPU_INTERRUPT_HARD)) {
-            cpu_interrupt(env, CPU_INTERRUPT_HARD);
-	}
-    } else
-        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
-}
-
 static void cpu_mips_irq_request(void *opaque, int irq, int level)
 {
     CPUState *env = (CPUState *)opaque;
@@ -52,7 +36,12 @@ static void cpu_mips_irq_request(void *opaque, int irq, int level)
     } else {
         env->CP0_Cause &= ~(1 << (irq + CP0Ca_IP));
     }
-    cpu_mips_update_irq(env);
+
+    if (env->CP0_Cause & CP0Ca_IP_mask) {
+        cpu_interrupt(env, CPU_INTERRUPT_HARD);
+    } else {
+        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+    }
 }
 
 void cpu_mips_irq_init_cpu(CPUState *env)
@@ -65,3 +54,12 @@ void cpu_mips_irq_init_cpu(CPUState *env)
         env->irq[i] = qi[i];
     }
 }
+
+void cpu_mips_soft_irq(CPUState *env, int irq, int level)
+{
+    if (irq < 0 || irq > 2) {
+        return;
+    }
+
+    qemu_set_irq(env->irq[irq], level);
+}
diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c
index 71b05a203c..66397c0c9a 100644
--- a/hw/mips_jazz.c
+++ b/hw/mips_jazz.c
@@ -36,6 +36,7 @@
 #include "mips-bios.h"
 #include "loader.h"
 #include "mc146818rtc.h"
+#include "blockdev.h"
 
 enum jazz_model_e
 {
@@ -136,7 +137,7 @@ void mips_jazz_init (ram_addr_t ram_size,
     NICInfo *nd;
     PITState *pit;
     DriveInfo *fds[MAX_FD];
-    qemu_irq esp_reset;
+    qemu_irq esp_reset, dma_enable;
     qemu_irq *cpu_exit_irq;
     ram_addr_t ram_offset;
     ram_addr_t bios_offset;
@@ -244,7 +245,7 @@ void mips_jazz_init (ram_addr_t ram_size,
     /* SCSI adapter */
     esp_init(0x80002000, 0,
              rc4030_dma_read, rc4030_dma_write, dmas[0],
-             rc4030[5], &esp_reset);
+             rc4030[5], &esp_reset, &dma_enable);
 
     /* Floppy */
     if (drive_get_max_bus(IF_FLOPPY) >= MAX_FD) {
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index 11e220a944..80260714ec 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -45,6 +45,7 @@
 #include "loader.h"
 #include "elf.h"
 #include "mc146818rtc.h"
+#include "blockdev.h"
 
 //#define DEBUG_BOARD_INIT
 
@@ -653,7 +654,8 @@ static void write_bootloader (CPUState *env, uint8_t *base,
 
 }
 
-static void prom_set(uint32_t* prom_buf, int index, const char *string, ...)
+static void GCC_FMT_ATTR(3, 4) prom_set(uint32_t* prom_buf, int index,
+                                        const char *string, ...)
 {
     va_list ap;
     int32_t table_addr;
@@ -727,13 +729,13 @@ static int64_t load_kernel (void)
     prom_size = ENVP_NB_ENTRIES * (sizeof(int32_t) + ENVP_ENTRY_SIZE);
     prom_buf = qemu_malloc(prom_size);
 
-    prom_set(prom_buf, prom_index++, loaderparams.kernel_filename);
+    prom_set(prom_buf, prom_index++, "%s", loaderparams.kernel_filename);
     if (initrd_size > 0) {
         prom_set(prom_buf, prom_index++, "rd_start=0x%" PRIx64 " rd_size=%li %s",
                  cpu_mips_phys_to_kseg0(NULL, initrd_offset), initrd_size,
                  loaderparams.kernel_cmdline);
     } else {
-        prom_set(prom_buf, prom_index++, loaderparams.kernel_cmdline);
+        prom_set(prom_buf, prom_index++, "%s", loaderparams.kernel_cmdline);
     }
 
     prom_set(prom_buf, prom_index++, "memsize");
@@ -782,11 +784,7 @@ void mips_malta_init (ram_addr_t ram_size,
     target_long bios_size;
     int64_t kernel_entry;
     PCIBus *pci_bus;
-    ISADevice *isa_dev;
     CPUState *env;
-    ISADevice *rtc_state;
-    FDCtrl *floppy_controller;
-    MaltaFPGAState *malta_fpga;
     qemu_irq *i8259;
     qemu_irq *cpu_exit_irq;
     int piix4_devfn;
@@ -849,7 +847,7 @@ void mips_malta_init (ram_addr_t ram_size,
     be = 0;
 #endif
     /* FPGA */
-    malta_fpga = malta_fpga_init(0x1f000000LL, env->irq[2], serial_hds[2]);
+    malta_fpga_init(0x1f000000LL, env->irq[2], serial_hds[2]);
 
     /* Load firmware in flash / BIOS unless we boot directly into a kernel. */
     if (kernel_filename) {
@@ -955,9 +953,9 @@ void mips_malta_init (ram_addr_t ram_size,
     DMA_init(0, cpu_exit_irq);
 
     /* Super I/O */
-    isa_dev = isa_create_simple("i8042");
- 
-    rtc_state = rtc_init(2000, NULL);
+    isa_create_simple("i8042");
+
+    rtc_init(2000, NULL);
     serial_isa_init(0, serial_hds[0]);
     serial_isa_init(1, serial_hds[1]);
     if (parallel_hds[0])
@@ -965,7 +963,7 @@ void mips_malta_init (ram_addr_t ram_size,
     for(i = 0; i < MAX_FD; i++) {
         fd[i] = drive_get(IF_FLOPPY, 0, i);
     }
-    floppy_controller = fdctrl_init_isa(fd);
+    fdctrl_init_isa(fd);
 
     /* Sound card */
     audio_init(pci_bus);
diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c
index 61cd33a93c..aa348904ad 100644
--- a/hw/mips_r4k.c
+++ b/hw/mips_r4k.c
@@ -22,6 +22,7 @@
 #include "loader.h"
 #include "elf.h"
 #include "mc146818rtc.h"
+#include "blockdev.h"
 
 #define MAX_IDE_BUS 2
 
@@ -166,7 +167,6 @@ void mips_r4k_init (ram_addr_t ram_size,
     int bios_size;
     CPUState *env;
     ResetData *reset_info;
-    ISADevice *rtc_state;
     int i;
     qemu_irq *i8259;
     DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
@@ -267,7 +267,7 @@ void mips_r4k_init (ram_addr_t ram_size,
     isa_bus_new(NULL);
     isa_bus_irqs(i8259);
 
-    rtc_state = rtc_init(2000, NULL);
+    rtc_init(2000, NULL);
 
     /* Register 64 KB of ISA IO space at 0x14000000 */
 #ifdef TARGET_WORDS_BIGENDIAN
diff --git a/hw/mipsnet.c b/hw/mipsnet.c
index a95b3ce07b..c5e54ffc35 100644
--- a/hw/mipsnet.c
+++ b/hw/mipsnet.c
@@ -81,7 +81,7 @@ static ssize_t mipsnet_receive(VLANClientState *nc, const uint8_t *buf, size_t s
     MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
 
 #ifdef DEBUG_MIPSNET_RECEIVE
-    printf("mipsnet: receiving len=%d\n", size);
+    printf("mipsnet: receiving len=%zu\n", size);
 #endif
     if (!mipsnet_can_receive(nc))
         return -1;
diff --git a/hw/msix.c b/hw/msix.c
index b202ff7d85..f66d2550a7 100644
--- a/hw/msix.c
+++ b/hw/msix.c
@@ -14,6 +14,7 @@
 #include "hw.h"
 #include "msix.h"
 #include "pci.h"
+#include "range.h"
 
 /* MSI-X capability structure */
 #define MSIX_TABLE_OFFSET 4
diff --git a/hw/multiboot.c b/hw/multiboot.c
index dc980e6498..f9097a2f60 100644
--- a/hw/multiboot.c
+++ b/hw/multiboot.c
@@ -252,7 +252,7 @@ int load_multiboot(void *fw_cfg,
 
         do {
             char *next_space;
-            uint32_t mb_mod_length;
+            int mb_mod_length;
             uint32_t offs = mbs.mb_buf_size;
 
             next_initrd = strchr(initrd_filename, ',');
diff --git a/hw/musicpal.c b/hw/musicpal.c
index 33180a2656..56f27669d2 100644
--- a/hw/musicpal.c
+++ b/hw/musicpal.c
@@ -18,6 +18,7 @@
 #include "flash.h"
 #include "console.h"
 #include "i2c.h"
+#include "blockdev.h"
 
 #define MP_MISC_BASE            0x80002000
 #define MP_MISC_SIZE            0x00001000
diff --git a/hw/omap.h b/hw/omap.h
index 18eb72b82f..fe32ca5c4c 100644
--- a/hw/omap.h
+++ b/hw/omap.h
@@ -664,10 +664,12 @@ void omap_synctimer_reset(struct omap_synctimer_s *s);
 struct omap_uart_s;
 struct omap_uart_s *omap_uart_init(target_phys_addr_t base,
                 qemu_irq irq, omap_clk fclk, omap_clk iclk,
-                qemu_irq txdma, qemu_irq rxdma, CharDriverState *chr);
+                qemu_irq txdma, qemu_irq rxdma,
+                const char *label, CharDriverState *chr);
 struct omap_uart_s *omap2_uart_init(struct omap_target_agent_s *ta,
                 qemu_irq irq, omap_clk fclk, omap_clk iclk,
-                qemu_irq txdma, qemu_irq rxdma, CharDriverState *chr);
+                qemu_irq txdma, qemu_irq rxdma,
+                const char *label, CharDriverState *chr);
 void omap_uart_reset(struct omap_uart_s *s);
 void omap_uart_attach(struct omap_uart_s *s, CharDriverState *chr);
 
diff --git a/hw/omap1.c b/hw/omap1.c
index cf0d428692..f4966f74b6 100644
--- a/hw/omap1.c
+++ b/hw/omap1.c
@@ -25,6 +25,8 @@
 #include "soc_dma.h"
 /* We use pc-style serial ports.  */
 #include "pc.h"
+#include "blockdev.h"
+#include "range.h"
 
 /* Should signal the TCMI/GPMC */
 uint32_t omap_badwidth_read8(void *opaque, target_phys_addr_t addr)
@@ -3668,37 +3670,38 @@ static const struct dma_irq_map omap1_dma_irq_map[] = {
 static int omap_validate_emiff_addr(struct omap_mpu_state_s *s,
                 target_phys_addr_t addr)
 {
-    return addr >= OMAP_EMIFF_BASE && addr < OMAP_EMIFF_BASE + s->sdram_size;
+    return range_covers_byte(OMAP_EMIFF_BASE, s->sdram_size, addr);
 }
 
 static int omap_validate_emifs_addr(struct omap_mpu_state_s *s,
                 target_phys_addr_t addr)
 {
-    return addr >= OMAP_EMIFS_BASE && addr < OMAP_EMIFF_BASE;
+    return range_covers_byte(OMAP_EMIFS_BASE, OMAP_EMIFF_BASE - OMAP_EMIFS_BASE,
+                             addr);
 }
 
 static int omap_validate_imif_addr(struct omap_mpu_state_s *s,
                 target_phys_addr_t addr)
 {
-    return addr >= OMAP_IMIF_BASE && addr < OMAP_IMIF_BASE + s->sram_size;
+    return range_covers_byte(OMAP_IMIF_BASE, s->sram_size, addr);
 }
 
 static int omap_validate_tipb_addr(struct omap_mpu_state_s *s,
                 target_phys_addr_t addr)
 {
-    return addr >= 0xfffb0000 && addr < 0xffff0000;
+    return range_covers_byte(0xfffb0000, 0xffff0000 - 0xfffb0000, addr);
 }
 
 static int omap_validate_local_addr(struct omap_mpu_state_s *s,
                 target_phys_addr_t addr)
 {
-    return addr >= OMAP_LOCALBUS_BASE && addr < OMAP_LOCALBUS_BASE + 0x1000000;
+    return range_covers_byte(OMAP_LOCALBUS_BASE, 0x1000000, addr);
 }
 
 static int omap_validate_tipb_mpui_addr(struct omap_mpu_state_s *s,
                 target_phys_addr_t addr)
 {
-    return addr >= 0xe1010000 && addr < 0xe1020004;
+    return range_covers_byte(0xe1010000, 0xe1020004 - 0xe1010000, addr);
 }
 
 struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
@@ -3808,16 +3811,19 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
                     omap_findclk(s, "uart1_ck"),
                     omap_findclk(s, "uart1_ck"),
                     s->drq[OMAP_DMA_UART1_TX], s->drq[OMAP_DMA_UART1_RX],
+                    "uart1",
                     serial_hds[0]);
     s->uart[1] = omap_uart_init(0xfffb0800, s->irq[1][OMAP_INT_UART2],
                     omap_findclk(s, "uart2_ck"),
                     omap_findclk(s, "uart2_ck"),
                     s->drq[OMAP_DMA_UART2_TX], s->drq[OMAP_DMA_UART2_RX],
+                    "uart2",
                     serial_hds[0] ? serial_hds[1] : NULL);
     s->uart[2] = omap_uart_init(0xfffb9800, s->irq[0][OMAP_INT_UART3],
                     omap_findclk(s, "uart3_ck"),
                     omap_findclk(s, "uart3_ck"),
                     s->drq[OMAP_DMA_UART3_TX], s->drq[OMAP_DMA_UART3_RX],
+                    "uart3",
                     serial_hds[0] && serial_hds[1] ? serial_hds[2] : NULL);
 
     omap_dpll_init(&s->dpll[0], 0xfffecf00, omap_findclk(s, "dpll1"));
diff --git a/hw/omap2.c b/hw/omap2.c
index 179075e996..e35a56e043 100644
--- a/hw/omap2.c
+++ b/hw/omap2.c
@@ -2291,13 +2291,16 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
                     omap_findclk(s, "uart1_fclk"),
                     omap_findclk(s, "uart1_iclk"),
                     s->drq[OMAP24XX_DMA_UART1_TX],
-                    s->drq[OMAP24XX_DMA_UART1_RX], serial_hds[0]);
+                    s->drq[OMAP24XX_DMA_UART1_RX],
+                    "uart1",
+                    serial_hds[0]);
     s->uart[1] = omap2_uart_init(omap_l4ta(s->l4, 20),
                     s->irq[0][OMAP_INT_24XX_UART2_IRQ],
                     omap_findclk(s, "uart2_fclk"),
                     omap_findclk(s, "uart2_iclk"),
                     s->drq[OMAP24XX_DMA_UART2_TX],
                     s->drq[OMAP24XX_DMA_UART2_RX],
+                    "uart2",
                     serial_hds[0] ? serial_hds[1] : NULL);
     s->uart[2] = omap2_uart_init(omap_l4ta(s->l4, 21),
                     s->irq[0][OMAP_INT_24XX_UART3_IRQ],
@@ -2305,6 +2308,7 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
                     omap_findclk(s, "uart3_iclk"),
                     s->drq[OMAP24XX_DMA_UART3_TX],
                     s->drq[OMAP24XX_DMA_UART3_RX],
+                    "uart3",
                     serial_hds[0] && serial_hds[1] ? serial_hds[2] : NULL);
 
     s->gptimer[0] = omap_gp_timer_init(omap_l4ta(s->l4, 7),
diff --git a/hw/omap_clk.c b/hw/omap_clk.c
index 6bcabef8ac..10c9c4308c 100644
--- a/hw/omap_clk.c
+++ b/hw/omap_clk.c
@@ -20,6 +20,7 @@
  */
 #include "hw.h"
 #include "omap.h"
+#include "qemu-timer.h" /* for muldiv64() */
 
 struct clk {
     const char *name;
diff --git a/hw/omap_i2c.c b/hw/omap_i2c.c
index d7c18882da..d133977e7f 100644
--- a/hw/omap_i2c.c
+++ b/hw/omap_i2c.c
@@ -190,8 +190,9 @@ static uint32_t omap_i2c_read(void *opaque, target_phys_addr_t addr)
             if (s->rxlen > 2)
                 s->fifo >>= 16;
             s->rxlen -= 2;
-        } else
-            /* XXX: remote access (qualifier) error - what's that?  */;
+        } else {
+            /* XXX: remote access (qualifier) error - what's that?  */
+        }
         if (!s->rxlen) {
             s->stat &= ~(1 << 3);				/* RRDY */
             if (((s->control >> 10) & 1) &&			/* MST */
diff --git a/hw/omap_mmc.c b/hw/omap_mmc.c
index 15cbf06c87..9d167ff535 100644
--- a/hw/omap_mmc.c
+++ b/hw/omap_mmc.c
@@ -559,8 +559,9 @@ static void omap_mmc_cover_cb(void *opaque, int line, int level)
     if (!host->cdet_state && level) {
         host->status |= 0x0002;
         omap_mmc_interrupts_update(host);
-        if (host->cdet_wakeup)
-            /* TODO: Assert wake-up */;
+        if (host->cdet_wakeup) {
+            /* TODO: Assert wake-up */
+        }
     }
 
     if (host->cdet_state != level) {
diff --git a/hw/omap_sx1.c b/hw/omap_sx1.c
index c3f197393d..44dc514f3f 100644
--- a/hw/omap_sx1.c
+++ b/hw/omap_sx1.c
@@ -32,6 +32,7 @@
 #include "boards.h"
 #include "arm-misc.h"
 #include "flash.h"
+#include "blockdev.h"
 
 /*****************************************************************************/
 /* Siemens SX1 Cellphone V1 */
diff --git a/hw/omap_uart.c b/hw/omap_uart.c
index 395bf0ccbb..cc66cd9d94 100644
--- a/hw/omap_uart.c
+++ b/hw/omap_uart.c
@@ -51,7 +51,8 @@ void omap_uart_reset(struct omap_uart_s *s)
 
 struct omap_uart_s *omap_uart_init(target_phys_addr_t base,
                 qemu_irq irq, omap_clk fclk, omap_clk iclk,
-                qemu_irq txdma, qemu_irq rxdma, CharDriverState *chr)
+                qemu_irq txdma, qemu_irq rxdma,
+                const char *label, CharDriverState *chr)
 {
     struct omap_uart_s *s = (struct omap_uart_s *)
             qemu_mallocz(sizeof(struct omap_uart_s));
@@ -61,11 +62,11 @@ struct omap_uart_s *omap_uart_init(target_phys_addr_t base,
     s->irq = irq;
 #ifdef TARGET_WORDS_BIGENDIAN
     s->serial = serial_mm_init(base, 2, irq, omap_clk_getrate(fclk)/16,
-                               chr ?: qemu_chr_open("null", "null", NULL), 1,
+                               chr ?: qemu_chr_open(label, "null", NULL), 1,
                                1);
 #else
     s->serial = serial_mm_init(base, 2, irq, omap_clk_getrate(fclk)/16,
-                               chr ?: qemu_chr_open("null", "null", NULL), 1,
+                               chr ?: qemu_chr_open(label, "null", NULL), 1,
                                0);
 #endif
     return s;
@@ -162,11 +163,12 @@ static CPUWriteMemoryFunc * const omap_uart_writefn[] = {
 
 struct omap_uart_s *omap2_uart_init(struct omap_target_agent_s *ta,
                 qemu_irq irq, omap_clk fclk, omap_clk iclk,
-                qemu_irq txdma, qemu_irq rxdma, CharDriverState *chr)
+                qemu_irq txdma, qemu_irq rxdma,
+                const char *label, CharDriverState *chr)
 {
     target_phys_addr_t base = omap_l4_attach(ta, 0, 0);
     struct omap_uart_s *s = omap_uart_init(base, irq,
-                    fclk, iclk, txdma, rxdma, chr);
+                    fclk, iclk, txdma, rxdma, label, chr);
     int iomemtype = cpu_register_io_memory(omap_uart_readfn,
                     omap_uart_writefn, s);
 
diff --git a/hw/pc.c b/hw/pc.c
index a96187f5b5..69b13bf62c 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -39,6 +39,7 @@
 #include "msix.h"
 #include "sysbus.h"
 #include "sysemu.h"
+#include "blockdev.h"
 
 /* output Bochs bios info messages */
 //#define DEBUG_BIOS
@@ -916,8 +917,10 @@ void pc_memory_init(ram_addr_t ram_size,
                  below_4g_mem_size - 0x100000,
                  ram_addr + 0x100000);
 #if TARGET_PHYS_ADDR_BITS > 32
-    cpu_register_physical_memory(0x100000000ULL, above_4g_mem_size,
-                                 ram_addr + below_4g_mem_size);
+    if (above_4g_mem_size > 0) {
+        cpu_register_physical_memory(0x100000000ULL, above_4g_mem_size,
+                                     ram_addr + below_4g_mem_size);
+    }
 #endif
 
     /* BIOS load */
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 519e8a5ccb..12359a75c9 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -34,6 +34,7 @@
 #include "kvm.h"
 #include "sysemu.h"
 #include "sysbus.h"
+#include "blockdev.h"
 
 #define MAX_IDE_BUS 2
 
@@ -103,6 +104,7 @@ static void pc_init1(ram_addr_t ram_size,
         pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq, ram_size);
     } else {
         pci_bus = NULL;
+        i440fx_state = NULL;
         isa_bus_new(NULL);
     }
     isa_bus_irqs(isa_irq);
@@ -226,7 +228,7 @@ static QEMUMachine pc_machine_v0_12 = {
     .compat_props = (GlobalProperty[]) {
         {
             .driver   = "virtio-serial-pci",
-            .property = "max_nr_ports",
+            .property = "max_ports",
             .value    = stringify(1),
         },{
             .driver   = "virtio-serial-pci",
@@ -249,7 +251,7 @@ static QEMUMachine pc_machine_v0_11 = {
             .value    = stringify(0),
         },{
             .driver   = "virtio-serial-pci",
-            .property = "max_nr_ports",
+            .property = "max_ports",
             .value    = stringify(1),
         },{
             .driver   = "virtio-serial-pci",
@@ -288,7 +290,7 @@ static QEMUMachine pc_machine_v0_10 = {
             .value    = stringify(PCI_CLASS_DISPLAY_OTHER),
         },{
             .driver   = "virtio-serial-pci",
-            .property = "max_nr_ports",
+            .property = "max_ports",
             .value    = stringify(1),
         },{
             .driver   = "virtio-serial-pci",
diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c
index c38f47fbf1..716133c376 100644
--- a/hw/pci-hotplug.c
+++ b/hw/pci-hotplug.c
@@ -31,6 +31,7 @@
 #include "scsi.h"
 #include "virtio-blk.h"
 #include "qemu-config.h"
+#include "blockdev.h"
 
 #if defined(TARGET_I386)
 static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon,
@@ -51,7 +52,7 @@ static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon,
         return NULL;
     }
 
-    opts = qemu_opts_parse(&qemu_net_opts, opts_str ? opts_str : "", 0);
+    opts = qemu_opts_parse(qemu_find_opts("net"), opts_str ? opts_str : "", 0);
     if (!opts) {
         return NULL;
     }
diff --git a/hw/pci.c b/hw/pci.c
index 5386f5a083..962886e767 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -32,6 +32,7 @@
 #include "sysemu.h"
 #include "loader.h"
 #include "qemu-objects.h"
+#include "range.h"
 
 //#define DEBUG_PCI
 #ifdef DEBUG_PCI
@@ -585,7 +586,7 @@ static int pci_init_multifunction(PCIBus *bus, PCIDevice *dev)
     }
 
     /*
-     * multifuction bit is interpreted in two ways as follows.
+     * multifunction bit is interpreted in two ways as follows.
      *   - all functions must set the bit to 1.
      *     Example: Intel X53
      *   - function 0 must set the bit, but the rest function (> 0)
diff --git a/hw/pci.h b/hw/pci.h
index d6c522b8dd..7100804e7c 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -448,33 +448,4 @@ static inline uint32_t pci_config_size(const PCIDevice *d)
     return pci_is_express(d) ? PCIE_CONFIG_SPACE_SIZE : PCI_CONFIG_SPACE_SIZE;
 }
 
-/* These are not pci specific. Should move into a separate header.
- * Only pci.c uses them, so keep them here for now.
- */
-
-/* Get last byte of a range from offset + length.
- * Undefined for ranges that wrap around 0. */
-static inline uint64_t range_get_last(uint64_t offset, uint64_t len)
-{
-    return offset + len - 1;
-}
-
-/* Check whether a given range covers a given byte. */
-static inline int range_covers_byte(uint64_t offset, uint64_t len,
-                                    uint64_t byte)
-{
-    return offset <= byte && byte <= range_get_last(offset, len);
-}
-
-/* Check whether 2 given ranges overlap.
- * Undefined if ranges that wrap around 0. */
-static inline int ranges_overlap(uint64_t first1, uint64_t len1,
-                                 uint64_t first2, uint64_t len2)
-{
-    uint64_t last1 = range_get_last(first1, len1);
-    uint64_t last2 = range_get_last(first2, len2);
-
-    return !(last2 < first1 || last1 < first2);
-}
-
 #endif
diff --git a/hw/pckbd.c b/hw/pckbd.c
index 0533b1d9e3..6e4e4062ad 100644
--- a/hw/pckbd.c
+++ b/hw/pckbd.c
@@ -56,7 +56,9 @@
 #define KBD_CCMD_WRITE_MOUSE	0xD4	/* Write the following byte to the mouse */
 #define KBD_CCMD_DISABLE_A20    0xDD    /* HP vectra only ? */
 #define KBD_CCMD_ENABLE_A20     0xDF    /* HP vectra only ? */
-#define KBD_CCMD_RESET	        0xFE
+#define KBD_CCMD_PULSE_BITS_3_0 0xF0    /* Pulse bits 3-0 of the output port P2. */
+#define KBD_CCMD_RESET          0xFE    /* Pulse bit 0 of the output port P2 = CPU reset. */
+#define KBD_CCMD_NO_OP          0xFF    /* Pulse no bits of the output port P2. */
 
 /* Keyboard Commands */
 #define KBD_CMD_SET_LEDS	0xED	/* Set keyboard leds */
@@ -238,6 +240,21 @@ static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
     KBDState *s = opaque;
 
     DPRINTF("kbd: write cmd=0x%02x\n", val);
+
+    /* Bits 3-0 of the output port P2 of the keyboard controller may be pulsed
+     * low for approximately 6 micro seconds. Bits 3-0 of the KBD_CCMD_PULSE
+     * command specify the output port bits to be pulsed.
+     * 0: Bit should be pulsed. 1: Bit should not be modified.
+     * The only useful version of this command is pulsing bit 0,
+     * which does a CPU reset.
+     */
+    if((val & KBD_CCMD_PULSE_BITS_3_0) == KBD_CCMD_PULSE_BITS_3_0) {
+        if(!(val & 1))
+            val = KBD_CCMD_RESET;
+        else
+            val = KBD_CCMD_NO_OP;
+    }
+
     switch(val) {
     case KBD_CCMD_READ_MODE:
         kbd_queue(s, s->mode, 0);
@@ -294,8 +311,8 @@ static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
     case KBD_CCMD_RESET:
         qemu_system_reset_request();
         break;
-    case 0xff:
-        /* ignore that - I don't know what is its use */
+    case KBD_CCMD_NO_OP:
+        /* ignore that */
         break;
     default:
         fprintf(stderr, "qemu: unsupported keyboard cmd=0x%02x\n", val);
diff --git a/hw/pcmcia.h b/hw/pcmcia.h
index 360292395b..50648c973f 100644
--- a/hw/pcmcia.h
+++ b/hw/pcmcia.h
@@ -1,7 +1,6 @@
 /* PCMCIA/Cardbus */
 
 #include "qemu-common.h"
-#include "blockdev.h"
 
 typedef struct {
     qemu_irq irq;
diff --git a/hw/petalogix_s3adsp1800_mmu.c b/hw/petalogix_s3adsp1800_mmu.c
index 70b6a36e1e..42de45963b 100644
--- a/hw/petalogix_s3adsp1800_mmu.c
+++ b/hw/petalogix_s3adsp1800_mmu.c
@@ -34,6 +34,7 @@
 #include "xilinx.h"
 #include "loader.h"
 #include "elf.h"
+#include "blockdev.h"
 
 #define LMB_BRAM_SIZE  (128 * 1024)
 #define FLASH_SIZE     (16 * 1024 * 1024)
@@ -179,11 +180,22 @@ petalogix_s3adsp1800_init(ram_addr_t ram_size,
         }
         /* Always boot into physical ram.  */
         boot_info.bootstrap_pc = ddr_base + (entry & 0x0fffffff);
+
+        /* If it wasn't an ELF image, try an u-boot image.  */
+        if (kernel_size < 0) {
+            target_phys_addr_t uentry, loadaddr;
+
+            kernel_size = load_uimage(kernel_filename, &uentry, &loadaddr, 0);
+            boot_info.bootstrap_pc = uentry;
+            high = (loadaddr + kernel_size + 3) & ~3;
+        }
+
+        /* Not an ELF image nor an u-boot image, try a RAW image.  */
         if (kernel_size < 0) {
-            /* If we failed loading ELF's try a raw image.  */
             kernel_size = load_image_targphys(kernel_filename, ddr_base,
                                               ram_size);
             boot_info.bootstrap_pc = ddr_base;
+            high = (ddr_base + kernel_size + 3) & ~3;
         }
 
         boot_info.cmdline = high + 4096;
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index f152a0ff06..b5589b9035 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -28,6 +28,7 @@
 #include "pci_host.h"
 #include "isa.h"
 #include "sysbus.h"
+#include "range.h"
 
 /*
  * I440FX chipset data sheet.
diff --git a/hw/ppc.c b/hw/ppc.c
index 2a77eb9bff..968aec1b16 100644
--- a/hw/ppc.c
+++ b/hw/ppc.c
@@ -28,6 +28,8 @@
 #include "nvram.h"
 #include "qemu-log.h"
 #include "loader.h"
+#include "kvm.h"
+#include "kvm_ppc.h"
 
 //#define PPC_DEBUG_IRQ
 //#define PPC_DEBUG_TB
@@ -50,6 +52,8 @@ static void cpu_ppc_tb_start (CPUState *env);
 
 static void ppc_set_irq (CPUState *env, int n_IRQ, int level)
 {
+    unsigned int old_pending = env->pending_interrupts;
+
     if (level) {
         env->pending_interrupts |= 1 << n_IRQ;
         cpu_interrupt(env, CPU_INTERRUPT_HARD);
@@ -58,6 +62,13 @@ static void ppc_set_irq (CPUState *env, int n_IRQ, int level)
         if (env->pending_interrupts == 0)
             cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
     }
+
+    if (old_pending != env->pending_interrupts) {
+#ifdef CONFIG_KVM
+        kvmppc_set_interrupt(env, n_IRQ, level);
+#endif
+    }
+
     LOG_IRQ("%s: %p n_IRQ %d level %d => pending %08" PRIx32
                 "req %08x\n", __func__, env, n_IRQ, level,
                 env->pending_interrupts, env->interrupt_request);
@@ -758,6 +769,9 @@ struct ppcemb_timer_t {
     struct QEMUTimer *fit_timer;
     uint64_t wdt_next;    /* Tick for next WDT interrupt  */
     struct QEMUTimer *wdt_timer;
+
+    /* 405 have the PIT, 440 have a DECR.  */
+    unsigned int decr_excp;
 };
 
 /* Fixed interval timer */
@@ -840,7 +854,7 @@ static void cpu_4xx_pit_cb (void *opaque)
     ppcemb_timer = tb_env->opaque;
     env->spr[SPR_40x_TSR] |= 1 << 27;
     if ((env->spr[SPR_40x_TCR] >> 26) & 0x1)
-        ppc_set_irq(env, PPC_INTERRUPT_PIT, 1);
+        ppc_set_irq(env, ppcemb_timer->decr_excp, 1);
     start_stop_pit(env, tb_env, 1);
     LOG_TB("%s: ar %d ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx " "
            "%016" PRIx64 "\n", __func__,
@@ -937,10 +951,15 @@ target_ulong load_40x_pit (CPUState *env)
 
 void store_booke_tsr (CPUState *env, target_ulong val)
 {
+    ppc_tb_t *tb_env = env->tb_env;
+    ppcemb_timer_t *ppcemb_timer;
+
+    ppcemb_timer = tb_env->opaque;
+
     LOG_TB("%s: val " TARGET_FMT_lx "\n", __func__, val);
     env->spr[SPR_40x_TSR] &= ~(val & 0xFC000000);
     if (val & 0x80000000)
-        ppc_set_irq(env, PPC_INTERRUPT_PIT, 0);
+        ppc_set_irq(env, ppcemb_timer->decr_excp, 0);
 }
 
 void store_booke_tcr (CPUState *env, target_ulong val)
@@ -966,7 +985,8 @@ static void ppc_emb_set_tb_clk (void *opaque, uint32_t freq)
     /* XXX: we should also update all timers */
 }
 
-clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq)
+clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq,
+                                  unsigned int decr_excp)
 {
     ppc_tb_t *tb_env;
     ppcemb_timer_t *ppcemb_timer;
@@ -985,6 +1005,7 @@ clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq)
             qemu_new_timer(vm_clock, &cpu_4xx_fit_cb, env);
         ppcemb_timer->wdt_timer =
             qemu_new_timer(vm_clock, &cpu_4xx_wdt_cb, env);
+        ppcemb_timer->decr_excp = decr_excp;
     }
 
     return &ppc_emb_set_tb_clk;
diff --git a/hw/ppc.h b/hw/ppc.h
index de13092ae4..34f54cf5da 100644
--- a/hw/ppc.h
+++ b/hw/ppc.h
@@ -19,7 +19,9 @@ int ppc_dcr_init (CPUState *env, int (*dcr_read_error)(int dcrn),
                   int (*dcr_write_error)(int dcrn));
 int ppc_dcr_register (CPUState *env, int dcrn, void *opaque,
                       dcr_read_cb drc_read, dcr_write_cb dcr_write);
-clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq);
+clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq,
+                                  unsigned int decr_excp);
+
 /* Embedded PowerPC reset */
 void ppc40x_core_reset (CPUState *env);
 void ppc40x_chip_reset (CPUState *env);
@@ -47,5 +49,8 @@ enum {
 #define FW_CFG_PPC_HEIGHT	(FW_CFG_ARCH_LOCAL + 0x01)
 #define FW_CFG_PPC_DEPTH	(FW_CFG_ARCH_LOCAL + 0x02)
 #define FW_CFG_PPC_TBFREQ	(FW_CFG_ARCH_LOCAL + 0x03)
+#define FW_CFG_PPC_IS_KVM       (FW_CFG_ARCH_LOCAL + 0x05)
+#define FW_CFG_PPC_KVM_HC       (FW_CFG_ARCH_LOCAL + 0x06)
+#define FW_CFG_PPC_KVM_PID      (FW_CFG_ARCH_LOCAL + 0x07)
 
 #define PPC_SERIAL_MM_BAUDBASE 399193
diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c
index 40ff1b34ea..c5897a9d4d 100644
--- a/hw/ppc405_boards.c
+++ b/hw/ppc405_boards.c
@@ -31,6 +31,7 @@
 #include "boards.h"
 #include "qemu-log.h"
 #include "loader.h"
+#include "blockdev.h"
 
 #define BIOS_FILENAME "ppc405_rom.bin"
 #define BIOS_SIZE (2048 * 1024)
@@ -181,10 +182,12 @@ static void ref405ep_init (ram_addr_t ram_size,
     qemu_irq *pic;
     ram_addr_t sram_offset, bios_offset, bdloc;
     target_phys_addr_t ram_bases[2], ram_sizes[2];
-    target_ulong sram_size, bios_size;
+    target_ulong sram_size;
+    long bios_size;
     //int phy_addr = 0;
     //static int phy_addr = 1;
-    target_ulong kernel_base, kernel_size, initrd_base, initrd_size;
+    target_ulong kernel_base, initrd_base;
+    long kernel_size, initrd_size;
     int linux_boot;
     int fl_idx, fl_sectors, len;
     DriveInfo *dinfo;
@@ -220,8 +223,8 @@ static void ref405ep_init (ram_addr_t ram_size,
         bios_offset = qemu_ram_alloc(NULL, "ef405ep.bios", bios_size);
         fl_sectors = (bios_size + 65535) >> 16;
 #ifdef DEBUG_BOARD_INIT
-        printf("Register parallel flash %d size " TARGET_FMT_lx
-               " at offset %08lx addr " TARGET_FMT_lx " '%s' %d\n",
+        printf("Register parallel flash %d size %lx"
+               " at offset %08lx addr %lx '%s' %d\n",
                fl_idx, bios_size, bios_offset, -bios_size,
                bdrv_get_device_name(dinfo->bdrv), fl_sectors);
 #endif
@@ -307,7 +310,7 @@ static void ref405ep_init (ram_addr_t ram_size,
                     kernel_filename);
             exit(1);
         }
-        printf("Load kernel size " TARGET_FMT_ld " at " TARGET_FMT_lx,
+        printf("Load kernel size %ld at " TARGET_FMT_lx,
                kernel_size, kernel_base);
         /* load initrd */
         if (initrd_filename) {
@@ -498,12 +501,12 @@ static void taihu_405ep_init(ram_addr_t ram_size,
                              const char *cpu_model)
 {
     char *filename;
-    CPUPPCState *env;
     qemu_irq *pic;
     ram_addr_t bios_offset;
     target_phys_addr_t ram_bases[2], ram_sizes[2];
-    target_ulong bios_size;
-    target_ulong kernel_base, kernel_size, initrd_base, initrd_size;
+    long bios_size;
+    target_ulong kernel_base, initrd_base;
+    long kernel_size, initrd_size;
     int linux_boot;
     int fl_idx, fl_sectors;
     DriveInfo *dinfo;
@@ -517,8 +520,8 @@ static void taihu_405ep_init(ram_addr_t ram_size,
 #ifdef DEBUG_BOARD_INIT
     printf("%s: register cpu\n", __func__);
 #endif
-    env = ppc405ep_init(ram_bases, ram_sizes, 33333333, &pic,
-                        kernel_filename == NULL ? 0 : 1);
+    ppc405ep_init(ram_bases, ram_sizes, 33333333, &pic,
+                  kernel_filename == NULL ? 0 : 1);
     /* allocate and load BIOS */
 #ifdef DEBUG_BOARD_INIT
     printf("%s: register BIOS\n", __func__);
@@ -533,8 +536,8 @@ static void taihu_405ep_init(ram_addr_t ram_size,
         fl_sectors = (bios_size + 65535) >> 16;
         bios_offset = qemu_ram_alloc(NULL, "taihu_405ep.bios", bios_size);
 #ifdef DEBUG_BOARD_INIT
-        printf("Register parallel flash %d size " TARGET_FMT_lx
-               " at offset %08lx addr " TARGET_FMT_lx " '%s' %d\n",
+        printf("Register parallel flash %d size %lx"
+               " at offset %08lx addr %lx '%s' %d\n",
                fl_idx, bios_size, bios_offset, -bios_size,
                bdrv_get_device_name(dinfo->bdrv), fl_sectors);
 #endif
@@ -575,7 +578,7 @@ static void taihu_405ep_init(ram_addr_t ram_size,
         bios_size = 32 * 1024 * 1024;
         fl_sectors = (bios_size + 65535) >> 16;
 #ifdef DEBUG_BOARD_INIT
-        printf("Register parallel flash %d size " TARGET_FMT_lx
+        printf("Register parallel flash %d size %lx"
                " at offset %08lx  addr " TARGET_FMT_lx " '%s'\n",
                fl_idx, bios_size, bios_offset, (target_ulong)0xfc000000,
                bdrv_get_device_name(dinfo->bdrv));
diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c
index b884ea5fbd..3600737412 100644
--- a/hw/ppc405_uc.c
+++ b/hw/ppc405_uc.c
@@ -630,18 +630,11 @@ struct ppc405_dma_t {
 
 static uint32_t dcr_read_dma (void *opaque, int dcrn)
 {
-    ppc405_dma_t *dma;
-
-    dma = opaque;
-
     return 0;
 }
 
 static void dcr_write_dma (void *opaque, int dcrn, uint32_t val)
 {
-    ppc405_dma_t *dma;
-
-    dma = opaque;
 }
 
 static void ppc405_dma_reset (void *opaque)
@@ -739,9 +732,6 @@ struct ppc405_gpio_t {
 
 static uint32_t ppc405_gpio_readb (void *opaque, target_phys_addr_t addr)
 {
-    ppc405_gpio_t *gpio;
-
-    gpio = opaque;
 #ifdef DEBUG_GPIO
     printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
 #endif
@@ -752,9 +742,6 @@ static uint32_t ppc405_gpio_readb (void *opaque, target_phys_addr_t addr)
 static void ppc405_gpio_writeb (void *opaque,
                                 target_phys_addr_t addr, uint32_t value)
 {
-    ppc405_gpio_t *gpio;
-
-    gpio = opaque;
 #ifdef DEBUG_GPIO
     printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
            value);
@@ -763,9 +750,6 @@ static void ppc405_gpio_writeb (void *opaque,
 
 static uint32_t ppc405_gpio_readw (void *opaque, target_phys_addr_t addr)
 {
-    ppc405_gpio_t *gpio;
-
-    gpio = opaque;
 #ifdef DEBUG_GPIO
     printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
 #endif
@@ -776,9 +760,6 @@ static uint32_t ppc405_gpio_readw (void *opaque, target_phys_addr_t addr)
 static void ppc405_gpio_writew (void *opaque,
                                 target_phys_addr_t addr, uint32_t value)
 {
-    ppc405_gpio_t *gpio;
-
-    gpio = opaque;
 #ifdef DEBUG_GPIO
     printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
            value);
@@ -787,9 +768,6 @@ static void ppc405_gpio_writew (void *opaque,
 
 static uint32_t ppc405_gpio_readl (void *opaque, target_phys_addr_t addr)
 {
-    ppc405_gpio_t *gpio;
-
-    gpio = opaque;
 #ifdef DEBUG_GPIO
     printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
 #endif
@@ -800,9 +778,6 @@ static uint32_t ppc405_gpio_readl (void *opaque, target_phys_addr_t addr)
 static void ppc405_gpio_writel (void *opaque,
                                 target_phys_addr_t addr, uint32_t value)
 {
-    ppc405_gpio_t *gpio;
-
-    gpio = opaque;
 #ifdef DEBUG_GPIO
     printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
            value);
@@ -823,9 +798,6 @@ static CPUWriteMemoryFunc * const ppc405_gpio_write[] = {
 
 static void ppc405_gpio_reset (void *opaque)
 {
-    ppc405_gpio_t *gpio;
-
-    gpio = opaque;
 }
 
 static void ppc405_gpio_init(target_phys_addr_t base)
diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c
index 6ca873ee7e..34ddf45477 100644
--- a/hw/ppc440_bamboo.c
+++ b/hw/ppc440_bamboo.c
@@ -27,6 +27,11 @@
 
 #define BINARY_DEVICE_TREE_FILE "bamboo.dtb"
 
+/* from u-boot */
+#define KERNEL_ADDR  0x1000000
+#define FDT_ADDR     0x1800000
+#define RAMDISK_ADDR 0x1900000
+
 static int bamboo_load_device_tree(target_phys_addr_t addr,
                                      uint32_t ramsize,
                                      target_phys_addr_t initrd_base,
@@ -98,10 +103,8 @@ static void bamboo_init(ram_addr_t ram_size,
     uint64_t elf_lowaddr;
     target_phys_addr_t entry = 0;
     target_phys_addr_t loadaddr = 0;
-    target_long kernel_size = 0;
-    target_ulong initrd_base = 0;
     target_long initrd_size = 0;
-    target_ulong dt_base = 0;
+    int success;
     int i;
 
     /* Setup CPU. */
@@ -118,15 +121,15 @@ static void bamboo_init(ram_addr_t ram_size,
 
     /* Load kernel. */
     if (kernel_filename) {
-        kernel_size = load_uimage(kernel_filename, &entry, &loadaddr, NULL);
-        if (kernel_size < 0) {
-            kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
-                                   &elf_lowaddr, NULL, 1, ELF_MACHINE, 0);
+        success = load_uimage(kernel_filename, &entry, &loadaddr, NULL);
+        if (success < 0) {
+            success = load_elf(kernel_filename, NULL, NULL, &elf_entry,
+                               &elf_lowaddr, NULL, 1, ELF_MACHINE, 0);
             entry = elf_entry;
             loadaddr = elf_lowaddr;
         }
         /* XXX try again as binary */
-        if (kernel_size < 0) {
+        if (success < 0) {
             fprintf(stderr, "qemu: could not load kernel '%s'\n",
                     kernel_filename);
             exit(1);
@@ -135,26 +138,20 @@ static void bamboo_init(ram_addr_t ram_size,
 
     /* Load initrd. */
     if (initrd_filename) {
-        initrd_base = kernel_size + loadaddr;
-        initrd_size = load_image_targphys(initrd_filename, initrd_base,
-                                          ram_size - initrd_base);
+        initrd_size = load_image_targphys(initrd_filename, RAMDISK_ADDR,
+                                          ram_size - RAMDISK_ADDR);
 
         if (initrd_size < 0) {
-            fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
-                    initrd_filename);
+            fprintf(stderr, "qemu: could not load ram disk '%s' at %x\n",
+                    initrd_filename, RAMDISK_ADDR);
             exit(1);
         }
     }
 
     /* If we're loading a kernel directly, we must load the device tree too. */
     if (kernel_filename) {
-        if (initrd_base)
-            dt_base = initrd_base + initrd_size;
-        else
-            dt_base = kernel_size + loadaddr;
-
-        if (bamboo_load_device_tree(dt_base, ram_size,
-                        initrd_base, initrd_size, kernel_cmdline) < 0) {
+        if (bamboo_load_device_tree(FDT_ADDR, ram_size, RAMDISK_ADDR,
+                                    initrd_size, kernel_cmdline) < 0) {
             fprintf(stderr, "couldn't load device tree\n");
             exit(1);
         }
@@ -163,7 +160,7 @@ static void bamboo_init(ram_addr_t ram_size,
 
         /* Set initial guest state. */
         env->gpr[1] = (16<<20) - 8;
-        env->gpr[3] = dt_base;
+        env->gpr[3] = FDT_ADDR;
         env->nip = entry;
         /* XXX we currently depend on KVM to create some initial TLB entries. */
     }
@@ -186,7 +183,7 @@ static QEMUMachine bamboo_machine_v0_12 = {
     .compat_props = (GlobalProperty[]) {
         {
             .driver   = "virtio-serial-pci",
-            .property = "max_nr_ports",
+            .property = "max_ports",
             .value    = stringify(1),
         },{
             .driver   = "virtio-serial-pci",
diff --git a/hw/ppc4xx_devs.c b/hw/ppc4xx_devs.c
index b15db81b6a..5f581fe2c4 100644
--- a/hw/ppc4xx_devs.c
+++ b/hw/ppc4xx_devs.c
@@ -56,7 +56,7 @@ CPUState *ppc4xx_init (const char *cpu_model,
     cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */
     cpu_clk->opaque = env;
     /* Set time-base frequency to sysclk */
-    tb_clk->cb = ppc_emb_timers_init(env, sysclk);
+    tb_clk->cb = ppc_emb_timers_init(env, sysclk, PPC_INTERRUPT_PIT);
     tb_clk->opaque = env;
     ppc_dcr_init(env, NULL, NULL);
     /* Register qemu callbacks */
@@ -619,7 +619,6 @@ static void sdram_reset (void *opaque)
     /* We pre-initialize RAM banks */
     sdram->status = 0x00000000;
     sdram->cfg = 0x00800000;
-    sdram_unmap_bcr(sdram);
 }
 
 void ppc4xx_sdram_init (CPUState *env, qemu_irq irq, int nbanks,
@@ -684,7 +683,7 @@ ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks,
     }
 
     ram_size -= size_left;
-    if (ram_size)
+    if (size_left)
         printf("Truncating memory to %d MiB to fit SDRAM controller limits.\n",
                (int)(ram_size >> 20));
 
diff --git a/hw/ppc_mac.h b/hw/ppc_mac.h
index 89f96bbc34..ea8759324c 100644
--- a/hw/ppc_mac.h
+++ b/hw/ppc_mac.h
@@ -30,7 +30,6 @@
 
 #define BIOS_SIZE     (1024 * 1024)
 #define BIOS_FILENAME "ppc_rom.bin"
-#define VGABIOS_FILENAME "video.x"
 #define NVRAM_SIZE        0x2000
 #define PROM_FILENAME    "openbios-ppc"
 #define PROM_ADDR         0xfff00000
diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c
index fbba9b6fb2..4369337b21 100644
--- a/hw/ppc_newworld.c
+++ b/hw/ppc_newworld.c
@@ -66,9 +66,9 @@
 #include "kvm.h"
 #include "kvm_ppc.h"
 #include "hw/usb.h"
+#include "blockdev.h"
 
 #define MAX_IDE_BUS 2
-#define VGA_BIOS_SIZE 65536
 #define CFG_ADDR 0xf0000510
 
 /* debug UniNorth */
@@ -128,24 +128,24 @@ static void ppc_core99_init (ram_addr_t ram_size,
                              const char *initrd_filename,
                              const char *cpu_model)
 {
-    CPUState *env = NULL, *envs[MAX_CPUS];
+    CPUState *env = NULL;
     char *filename;
     qemu_irq *pic, **openpic_irqs;
     int unin_memory;
     int linux_boot, i;
-    ram_addr_t ram_offset, bios_offset, vga_bios_offset;
-    uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
+    ram_addr_t ram_offset, bios_offset;
+    uint32_t kernel_base, initrd_base;
+    long kernel_size, initrd_size;
     PCIBus *pci_bus;
     MacIONVRAMState *nvr;
     int nvram_mem_index;
-    int vga_bios_size, bios_size;
+    int bios_size;
     int pic_mem_index, dbdma_mem_index, cuda_mem_index, escc_mem_index;
     int ide_mem_index[3];
     int ppc_boot_device;
     DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
     void *fw_cfg;
     void *dbdma;
-    uint8_t *vga_bios_ptr;
     int machine_arch;
 
     linux_boot = (kernel_filename != NULL);
@@ -165,11 +165,7 @@ static void ppc_core99_init (ram_addr_t ram_size,
         }
         /* Set time-base frequency to 100 Mhz */
         cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
-#if 0
-        env->osi_call = vga_osi_call;
-#endif
         qemu_register_reset((QEMUResetHandler*)&cpu_reset, env);
-        envs[i] = env;
     }
 
     /* allocate RAM */
@@ -197,36 +193,6 @@ static void ppc_core99_init (ram_addr_t ram_size,
         exit(1);
     }
 
-    /* allocate and load VGA BIOS */
-    vga_bios_offset = qemu_ram_alloc(NULL, "ppc_core99.vbios", VGA_BIOS_SIZE);
-    vga_bios_ptr = qemu_get_ram_ptr(vga_bios_offset);
-    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, VGABIOS_FILENAME);
-    if (filename) {
-        vga_bios_size = load_image(filename, vga_bios_ptr + 8);
-        qemu_free(filename);
-    } else {
-        vga_bios_size = -1;
-    }
-    if (vga_bios_size < 0) {
-        /* if no bios is present, we can still work */
-        fprintf(stderr, "qemu: warning: could not load VGA bios '%s'\n",
-                VGABIOS_FILENAME);
-        vga_bios_size = 0;
-    } else {
-        /* set a specific header (XXX: find real Apple format for NDRV
-           drivers) */
-        vga_bios_ptr[0] = 'N';
-        vga_bios_ptr[1] = 'D';
-        vga_bios_ptr[2] = 'R';
-        vga_bios_ptr[3] = 'V';
-        cpu_to_be32w((uint32_t *)(vga_bios_ptr + 4), vga_bios_size);
-        vga_bios_size += 8;
-
-        /* Round to page boundary */
-        vga_bios_size = (vga_bios_size + TARGET_PAGE_SIZE - 1) &
-            TARGET_PAGE_MASK;
-    }
-
     if (linux_boot) {
         uint64_t lowaddr = 0;
         int bswap_needed;
@@ -350,7 +316,7 @@ static void ppc_core99_init (ram_addr_t ram_size,
         machine_arch = ARCH_MAC99;
     }
     /* init basic PC hardware */
-    pci_vga_init(pci_bus, vga_bios_offset, vga_bios_size);
+    pci_vga_init(pci_bus, 0, 0);
 
     escc_mem_index = escc_init(0x80013000, pic[0x25], pic[0x24],
                                serial_hds[0], serial_hds[1], ESCC_CLOCK, 4);
@@ -426,9 +392,16 @@ static void ppc_core99_init (ram_addr_t ram_size,
     fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_HEIGHT, graphic_height);
     fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_DEPTH, graphic_depth);
 
+    fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_IS_KVM, kvm_enabled());
     if (kvm_enabled()) {
 #ifdef CONFIG_KVM
+        uint8_t *hypercall;
+
         fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, kvmppc_get_tbfreq());
+        hypercall = qemu_malloc(16);
+        kvmppc_get_hypercall(env, hypercall, 16);
+        fw_cfg_add_bytes(fw_cfg, FW_CFG_PPC_KVM_HC, hypercall, 16);
+        fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_KVM_PID, getpid());
 #endif
     } else {
         fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, get_ticks_per_sec());
diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c
index 6b3ab89611..a2f9ddf738 100644
--- a/hw/ppc_oldworld.c
+++ b/hw/ppc_oldworld.c
@@ -1,3 +1,4 @@
+
 /*
  * QEMU OldWorld PowerMac (currently ~G3 Beige) hardware System Emulator
  *
@@ -41,81 +42,11 @@
 #include "elf.h"
 #include "kvm.h"
 #include "kvm_ppc.h"
+#include "blockdev.h"
 
 #define MAX_IDE_BUS 2
-#define VGA_BIOS_SIZE 65536
 #define CFG_ADDR 0xf0000510
 
-/* temporary frame buffer OSI calls for the video.x driver. The right
-   solution is to modify the driver to use VGA PCI I/Os */
-/* XXX: to be removed. This is no way related to emulation */
-static int vga_osi_call (CPUState *env)
-{
-    static int vga_vbl_enabled;
-    int linesize;
-
-#if 0
-    printf("osi_call R5=%016" PRIx64 "\n", ppc_dump_gpr(env, 5));
-#endif
-
-    /* same handler as PearPC, coming from the original MOL video
-       driver. */
-    switch(env->gpr[5]) {
-    case 4:
-        break;
-    case 28: /* set_vmode */
-        if (env->gpr[6] != 1 || env->gpr[7] != 0)
-            env->gpr[3] = 1;
-        else
-            env->gpr[3] = 0;
-        break;
-    case 29: /* get_vmode_info */
-        if (env->gpr[6] != 0) {
-            if (env->gpr[6] != 1 || env->gpr[7] != 0) {
-                env->gpr[3] = 1;
-                break;
-            }
-        }
-        env->gpr[3] = 0;
-        env->gpr[4] = (1 << 16) | 1; /* num_vmodes, cur_vmode */
-        env->gpr[5] = (1 << 16) | 0; /* num_depths, cur_depth_mode */
-        env->gpr[6] = (graphic_width << 16) | graphic_height; /* w, h */
-        env->gpr[7] = 85 << 16; /* refresh rate */
-        env->gpr[8] = (graphic_depth + 7) & ~7; /* depth (round to byte) */
-        linesize = ((graphic_depth + 7) >> 3) * graphic_width;
-        linesize = (linesize + 3) & ~3;
-        env->gpr[9] = (linesize << 16) | 0; /* row_bytes, offset */
-        break;
-    case 31: /* set_video power */
-        env->gpr[3] = 0;
-        break;
-    case 39: /* video_ctrl */
-        if (env->gpr[6] == 0 || env->gpr[6] == 1)
-            vga_vbl_enabled = env->gpr[6];
-        env->gpr[3] = 0;
-        break;
-    case 47:
-        break;
-    case 59: /* set_color */
-        /* R6 = index, R7 = RGB */
-        env->gpr[3] = 0;
-        break;
-    case 64: /* get color */
-        /* R6 = index */
-        env->gpr[3] = 0;
-        break;
-    case 116: /* set hwcursor */
-        /* R6 = x, R7 = y, R8 = visible, R9 = data */
-        break;
-    default:
-        fprintf(stderr, "unsupported OSI call R5=%016" PRIx64 "\n",
-                ppc_dump_gpr(env, 5));
-        break;
-    }
-
-    return 1; /* osi_call handled */
-}
-
 static int fw_cfg_boot_set(void *opaque, const char *boot_device)
 {
     fw_cfg_add_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
@@ -135,23 +66,22 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
                                const char *initrd_filename,
                                const char *cpu_model)
 {
-    CPUState *env = NULL, *envs[MAX_CPUS];
+    CPUState *env = NULL;
     char *filename;
     qemu_irq *pic, **heathrow_irqs;
     int linux_boot, i;
-    ram_addr_t ram_offset, bios_offset, vga_bios_offset;
+    ram_addr_t ram_offset, bios_offset;
     uint32_t kernel_base, initrd_base;
     int32_t kernel_size, initrd_size;
     PCIBus *pci_bus;
     MacIONVRAMState *nvr;
-    int vga_bios_size, bios_size;
+    int bios_size;
     int pic_mem_index, nvram_mem_index, dbdma_mem_index, cuda_mem_index;
     int escc_mem_index, ide_mem_index[2];
     uint16_t ppc_boot_device;
     DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
     void *fw_cfg;
     void *dbdma;
-    uint8_t *vga_bios_ptr;
 
     linux_boot = (kernel_filename != NULL);
 
@@ -166,9 +96,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
         }
         /* Set time-base frequency to 16.6 Mhz */
         cpu_ppc_tb_init(env,  16600000UL);
-        env->osi_call = vga_osi_call;
         qemu_register_reset((QEMUResetHandler*)&cpu_reset, env);
-        envs[i] = env;
     }
 
     /* allocate RAM */
@@ -202,36 +130,6 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
         exit(1);
     }
 
-    /* allocate and load VGA BIOS */
-    vga_bios_offset = qemu_ram_alloc(NULL, "ppc_heathrow.vbios", VGA_BIOS_SIZE);
-    vga_bios_ptr = qemu_get_ram_ptr(vga_bios_offset);
-    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, VGABIOS_FILENAME);
-    if (filename) {
-        vga_bios_size = load_image(filename, vga_bios_ptr + 8);
-        qemu_free(filename);
-    } else {
-        vga_bios_size = -1;
-    }
-    if (vga_bios_size < 0) {
-        /* if no bios is present, we can still work */
-        fprintf(stderr, "qemu: warning: could not load VGA bios '%s'\n",
-                VGABIOS_FILENAME);
-        vga_bios_size = 0;
-    } else {
-        /* set a specific header (XXX: find real Apple format for NDRV
-           drivers) */
-        vga_bios_ptr[0] = 'N';
-        vga_bios_ptr[1] = 'D';
-        vga_bios_ptr[2] = 'R';
-        vga_bios_ptr[3] = 'V';
-        cpu_to_be32w((uint32_t *)(vga_bios_ptr + 4), vga_bios_size);
-        vga_bios_size += 8;
-
-        /* Round to page boundary */
-        vga_bios_size = (vga_bios_size + TARGET_PAGE_SIZE - 1) &
-            TARGET_PAGE_MASK;
-    }
-
     if (linux_boot) {
         uint64_t lowaddr = 0;
         int bswap_needed;
@@ -329,7 +227,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
     }
     pic = heathrow_pic_init(&pic_mem_index, 1, heathrow_irqs);
     pci_bus = pci_grackle_init(0xfec00000, pic);
-    pci_vga_init(pci_bus, vga_bios_offset, vga_bios_size);
+    pci_vga_init(pci_bus, 0, 0);
 
     escc_mem_index = escc_init(0x80013000, pic[0x0f], pic[0x10], serial_hds[0],
                                serial_hds[1], ESCC_CLOCK, 4);
@@ -398,9 +296,16 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
     fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_HEIGHT, graphic_height);
     fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_DEPTH, graphic_depth);
 
+    fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_IS_KVM, kvm_enabled());
     if (kvm_enabled()) {
 #ifdef CONFIG_KVM
+        uint8_t *hypercall;
+
         fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, kvmppc_get_tbfreq());
+        hypercall = qemu_malloc(16);
+        kvmppc_get_hypercall(env, hypercall, 16);
+        fw_cfg_add_bytes(fw_cfg, FW_CFG_PPC_KVM_HC, hypercall, 16);
+        fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_KVM_PID, getpid());
 #endif
     } else {
         fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, get_ticks_per_sec());
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index fc3e17a0c3..a6915f7e68 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -37,6 +37,7 @@
 #include "ide.h"
 #include "loader.h"
 #include "mc146818rtc.h"
+#include "blockdev.h"
 
 //#define HARD_DEBUG_PPC_IO
 //#define DEBUG_PPC_IO
@@ -564,14 +565,15 @@ static void ppc_prep_init (ram_addr_t ram_size,
                            const char *initrd_filename,
                            const char *cpu_model)
 {
-    CPUState *env = NULL, *envs[MAX_CPUS];
+    CPUState *env = NULL;
     char *filename;
     nvram_t nvram;
     M48t59State *m48t59;
     int PPC_io_memory;
     int linux_boot, i, nb_nics1, bios_size;
     ram_addr_t ram_offset, bios_offset;
-    uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
+    uint32_t kernel_base, initrd_base;
+    long kernel_size, initrd_size;
     PCIBus *pci_bus;
     qemu_irq *i8259;
     qemu_irq *cpu_exit_irq;
@@ -600,7 +602,6 @@ static void ppc_prep_init (ram_addr_t ram_size,
             cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
         }
         qemu_register_reset((QEMUResetHandler*)&cpu_reset, env);
-        envs[i] = env;
     }
 
     /* allocate RAM */
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 1422fad072..59d20d30ae 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -176,7 +176,6 @@ static void mpc8544ds_init(ram_addr_t ram_size,
     int i=0;
     unsigned int pci_irq_nrs[4] = {1, 2, 3, 4};
     qemu_irq *irqs, *mpic, *pci_irqs;
-    SerialState * serial[2];
 
     /* Setup CPU */
     env = cpu_ppc_init("e500v2_v30");
@@ -200,15 +199,15 @@ static void mpc8544ds_init(ram_addr_t ram_size,
 
     /* Serial */
     if (serial_hds[0]) {
-        serial[0] = serial_mm_init(MPC8544_SERIAL0_REGS_BASE,
-                                   0, mpic[12+26], 399193,
-                                   serial_hds[0], 1, 1);
+        serial_mm_init(MPC8544_SERIAL0_REGS_BASE,
+                       0, mpic[12+26], 399193,
+                       serial_hds[0], 1, 1);
     }
 
     if (serial_hds[1]) {
-        serial[0] = serial_mm_init(MPC8544_SERIAL1_REGS_BASE,
-                                   0, mpic[12+26], 399193,
-                                   serial_hds[0], 1, 1);
+        serial_mm_init(MPC8544_SERIAL1_REGS_BASE,
+                       0, mpic[12+26], 399193,
+                       serial_hds[0], 1, 1);
     }
 
     /* PCI */
diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c
index 953e9ee1d1..6e046450df 100644
--- a/hw/pxa2xx.c
+++ b/hw/pxa2xx.c
@@ -15,6 +15,7 @@
 #include "ssi.h"
 #include "qemu-timer.h"
 #include "qemu-char.h"
+#include "blockdev.h"
 
 static struct {
     target_phys_addr_t io_base;
@@ -124,7 +125,7 @@ static void pxa2xx_pm_write(void *opaque, target_phys_addr_t addr,
         break;
 
     default:	/* Read-write registers */
-        if (addr >= PMCR && addr <= PCMD31 && !(addr & 3)) {
+        if (!(addr & 3)) {
             s->pm_regs[addr >> 2] = value;
             break;
         }
@@ -635,6 +636,7 @@ static void pxa2xx_ssp_fifo_update(PXA2xxSSPState *s)
 {
     s->sssr &= ~(0xf << 12);	/* Clear RFL */
     s->sssr &= ~(0xf << 8);	/* Clear TFL */
+    s->sssr &= ~SSSR_TFS;
     s->sssr &= ~SSSR_TNF;
     if (s->enable) {
         s->sssr |= ((s->rx_level - 1) & 0xf) << 12;
@@ -642,14 +644,13 @@ static void pxa2xx_ssp_fifo_update(PXA2xxSSPState *s)
             s->sssr |= SSSR_RFS;
         else
             s->sssr &= ~SSSR_RFS;
-        if (0 <= SSCR1_TFT(s->sscr[1]))
-            s->sssr |= SSSR_TFS;
-        else
-            s->sssr &= ~SSSR_TFS;
         if (s->rx_level)
             s->sssr |= SSSR_RNE;
         else
             s->sssr &= ~SSSR_RNE;
+        /* TX FIFO is never filled, so it is always in underrun
+           condition if SSP is enabled */
+        s->sssr |= SSSR_TFS;
         s->sssr |= SSSR_TNF;
     }
 
@@ -1876,8 +1877,9 @@ static void pxa2xx_fir_write(void *opaque, target_phys_addr_t addr,
         s->control[0] = value;
         if (!(value & (1 << 4)))			/* RXE */
             s->rx_len = s->rx_start = 0;
-        if (!(value & (1 << 3)))			/* TXE */
-            /* Nop */;
+        if (!(value & (1 << 3))) {                      /* TXE */
+            /* Nop */
+        }
         s->enable = value & 1;				/* ITR */
         if (!s->enable)
             s->status[0] = 0;
diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index 9219cd7a60..a493087a52 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -1,6 +1,7 @@
 #include "net.h"
 #include "qdev.h"
 #include "qerror.h"
+#include "blockdev.h"
 
 void *qdev_get_prop_ptr(DeviceState *dev, Property *prop)
 {
@@ -772,5 +773,5 @@ static int qdev_add_one_global(QemuOpts *opts, void *opaque)
 
 void qemu_add_globals(void)
 {
-    qemu_opts_foreach(&qemu_global_opts, qdev_add_one_global, NULL, 0);
+    qemu_opts_foreach(qemu_find_opts("global"), qdev_add_one_global, NULL, 0);
 }
diff --git a/hw/qdev.c b/hw/qdev.c
index e99c73f0d9..35858cb81b 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -29,6 +29,7 @@
 #include "qdev.h"
 #include "sysemu.h"
 #include "monitor.h"
+#include "blockdev.h"
 
 static int qdev_hotplug = 0;
 
@@ -792,7 +793,7 @@ int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     QemuOpts *opts;
 
-    opts = qemu_opts_from_qdict(&qemu_device_opts, qdict);
+    opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict);
     if (!opts) {
         return -1;
     }
diff --git a/hw/qdev.h b/hw/qdev.h
index 678f8b7d1d..579328afc2 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -2,7 +2,6 @@
 #define QDEV_H
 
 #include "hw.h"
-#include "blockdev.h"
 #include "qemu-queue.h"
 #include "qemu-char.h"
 #include "qemu-option.h"
diff --git a/hw/r2d.c b/hw/r2d.c
index 8c1fbad4ba..a58f653e52 100644
--- a/hw/r2d.c
+++ b/hw/r2d.c
@@ -36,6 +36,7 @@
 #include "loader.h"
 #include "usb.h"
 #include "flash.h"
+#include "blockdev.h"
 
 #define FLASH_BASE 0x00000000
 #define FLASH_SIZE 0x02000000
diff --git a/hw/rc4030.c b/hw/rc4030.c
index 223137323b..abbc3eb4e2 100644
--- a/hw/rc4030.c
+++ b/hw/rc4030.c
@@ -749,7 +749,10 @@ static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_wri
         printf("rc4030 dma: Copying %d bytes %s host %p\n",
             len, is_write ? "from" : "to", buf);
         for (i = 0; i < len; i += 16) {
-            int n = min(16, len - i);
+            int n = 16;
+            if (n > len - i) {
+                n = len - i;
+            }
             for (j = 0; j < n; j++)
                 printf("%02x ", buf[i + j]);
             while (j++ < 16)
diff --git a/hw/realview.c b/hw/realview.c
index 70bcdb846d..e9fcbc9a6d 100644
--- a/hw/realview.c
+++ b/hw/realview.c
@@ -18,6 +18,7 @@
 #include "boards.h"
 #include "bitbang_i2c.h"
 #include "sysbus.h"
+#include "blockdev.h"
 
 #define SMP_BOOT_ADDR 0xe0000000
 
diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c
index fe6884d47d..784dc01b97 100644
--- a/hw/s390-virtio-bus.c
+++ b/hw/s390-virtio-bus.c
@@ -27,6 +27,7 @@
 #include "elf.h"
 #include "hw/virtio.h"
 #include "hw/virtio-serial.h"
+#include "hw/virtio-net.h"
 #include "hw/sysbus.h"
 #include "kvm.h"
 
@@ -110,7 +111,7 @@ static int s390_virtio_net_init(VirtIOS390Device *dev)
 {
     VirtIODevice *vdev;
 
-    vdev = virtio_net_init((DeviceState *)dev, &dev->nic);
+    vdev = virtio_net_init((DeviceState *)dev, &dev->nic, &dev->net);
     if (!vdev) {
         return -1;
     }
@@ -327,6 +328,11 @@ static VirtIOS390DeviceInfo s390_virtio_net = {
     .qdev.size = sizeof(VirtIOS390Device),
     .qdev.props = (Property[]) {
         DEFINE_NIC_PROPERTIES(VirtIOS390Device, nic),
+        DEFINE_PROP_UINT32("x-txtimer", VirtIOS390Device,
+                           net.txtimer, TX_TIMER_INTERVAL),
+        DEFINE_PROP_INT32("x-txburst", VirtIOS390Device,
+                          net.txburst, TX_BURST),
+        DEFINE_PROP_STRING("tx", VirtIOS390Device, net.tx),
         DEFINE_PROP_END_OF_LIST(),
     },
 };
diff --git a/hw/s390-virtio-bus.h b/hw/s390-virtio-bus.h
index 333fea8963..41558c9c67 100644
--- a/hw/s390-virtio-bus.h
+++ b/hw/s390-virtio-bus.h
@@ -43,6 +43,7 @@ typedef struct VirtIOS390Device {
     uint32_t host_features;
     /* Max. number of ports we can have for a the virtio-serial device */
     uint32_t max_virtserial_ports;
+    virtio_net_conf net;
 } VirtIOS390Device;
 
 typedef struct VirtIOS390Bus {
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index d69c74c4ef..5a3fd4b7ac 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -3,6 +3,7 @@
 #include "scsi.h"
 #include "scsi-defs.h"
 #include "qdev.h"
+#include "blockdev.h"
 
 static struct BusInfo scsi_bus_info = {
     .name  = "SCSI",
@@ -142,6 +143,7 @@ SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t l
     req->tag = tag;
     req->lun = lun;
     req->status = -1;
+    req->enqueued = true;
     QTAILQ_INSERT_TAIL(&d->requests, req, next);
     return req;
 }
@@ -158,9 +160,17 @@ SCSIRequest *scsi_req_find(SCSIDevice *d, uint32_t tag)
     return NULL;
 }
 
+static void scsi_req_dequeue(SCSIRequest *req)
+{
+    if (req->enqueued) {
+        QTAILQ_REMOVE(&req->dev->requests, req, next);
+        req->enqueued = false;
+    }
+}
+
 void scsi_req_free(SCSIRequest *req)
 {
-    QTAILQ_REMOVE(&req->dev->requests, req, next);
+    scsi_req_dequeue(req);
     qemu_free(req);
 }
 
@@ -198,6 +208,8 @@ static int scsi_req_length(SCSIRequest *req, uint8_t *cmd)
     case SEEK_6:
     case WRITE_FILEMARKS:
     case SPACE:
+    case RESERVE:
+    case RELEASE:
     case ERASE:
     case ALLOW_MEDIUM_REMOVAL:
     case VERIFY:
@@ -309,7 +321,6 @@ static void scsi_req_xfer_mode(SCSIRequest *req)
     case WRITE_BUFFER:
     case FORMAT_UNIT:
     case REASSIGN_BLOCKS:
-    case RESERVE:
     case SEARCH_EQUAL:
     case SEARCH_HIGH:
     case SEARCH_LOW:
@@ -512,6 +523,7 @@ void scsi_req_print(SCSIRequest *req)
 void scsi_req_complete(SCSIRequest *req)
 {
     assert(req->status != -1);
+    scsi_req_dequeue(req);
     req->bus->complete(req->bus, SCSI_REASON_DONE,
                        req->tag,
                        req->status);
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index c30709c550..9628b39a21 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -36,6 +36,7 @@ do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
 #include "scsi.h"
 #include "scsi-defs.h"
 #include "sysemu.h"
+#include "blockdev.h"
 
 #define SCSI_DMA_BUF_SIZE    131072
 #define SCSI_MAX_INQUIRY_LEN 256
@@ -69,14 +70,15 @@ struct SCSIDiskState
     char *serial;
 };
 
-static SCSIDiskReq *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun)
+static SCSIDiskReq *scsi_new_request(SCSIDiskState *s, uint32_t tag,
+        uint32_t lun)
 {
     SCSIRequest *req;
     SCSIDiskReq *r;
 
-    req = scsi_req_alloc(sizeof(SCSIDiskReq), d, tag, lun);
+    req = scsi_req_alloc(sizeof(SCSIDiskReq), &s->qdev, tag, lun);
     r = DO_UPCAST(SCSIDiskReq, req, req);
-    r->iov.iov_base = qemu_memalign(512, SCSI_DMA_BUF_SIZE);
+    r->iov.iov_base = qemu_blockalign(s->bs, SCSI_DMA_BUF_SIZE);
     return r;
 }
 
@@ -134,7 +136,7 @@ static void scsi_read_complete(void * opaque, int ret)
         scsi_command_complete(r, CHECK_CONDITION, NO_SENSE);
         return;
     }
-    DPRINTF("Data ready tag=0x%x len=%" PRId64 "\n", r->req.tag, r->iov.iov_len);
+    DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->iov.iov_len);
 
     r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, r->iov.iov_len);
 }
@@ -154,7 +156,7 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag)
         return;
     }
     if (r->sector_count == (uint32_t)-1) {
-        DPRINTF("Read buf_len=%" PRId64 "\n", r->iov.iov_len);
+        DPRINTF("Read buf_len=%zd\n", r->iov.iov_len);
         r->sector_count = 0;
         r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, r->iov.iov_len);
         return;
@@ -485,16 +487,26 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
     return buflen;
 }
 
-static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p)
+static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p,
+                           int page_control)
 {
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
     BlockDriverState *bdrv = s->bs;
     int cylinders, heads, secs;
 
+    /*
+     * If Changeable Values are requested, a mask denoting those mode parameters
+     * that are changeable shall be returned. As we currently don't support
+     * parameter changes via MODE_SELECT all bits are returned set to zero.
+     * The buffer was already menset to zero by the caller of this function.
+     */
     switch (page) {
     case 4: /* Rigid disk device geometry page. */
         p[0] = 4;
         p[1] = 0x16;
+        if (page_control == 1) { /* Changeable Values */
+            return p[1] + 2;
+        }
         /* if a geometry hint is available, use it */
         bdrv_get_geometry_hint(bdrv, &cylinders, &heads, &secs);
         p[2] = (cylinders >> 16) & 0xff;
@@ -519,11 +531,14 @@ static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p)
         /* Medium rotation rate [rpm], 5400 rpm */
         p[20] = (5400 >> 8) & 0xff;
         p[21] = 5400 & 0xff;
-        return 0x16;
+        return p[1] + 2;
 
     case 5: /* Flexible disk device geometry page. */
         p[0] = 5;
         p[1] = 0x1e;
+        if (page_control == 1) { /* Changeable Values */
+            return p[1] + 2;
+        }
         /* Transfer rate [kbit/s], 5Mbit/s */
         p[2] = 5000 >> 8;
         p[3] = 5000 & 0xff;
@@ -555,21 +570,27 @@ static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p)
         /* Medium rotation rate [rpm], 5400 rpm */
         p[28] = (5400 >> 8) & 0xff;
         p[29] = 5400 & 0xff;
-        return 0x1e;
+        return p[1] + 2;
 
     case 8: /* Caching page.  */
         p[0] = 8;
         p[1] = 0x12;
+        if (page_control == 1) { /* Changeable Values */
+            return p[1] + 2;
+        }
         if (bdrv_enable_write_cache(s->bs)) {
             p[2] = 4; /* WCE */
         }
-        return 20;
+        return p[1] + 2;
 
     case 0x2a: /* CD Capabilities and Mechanical Status page. */
         if (bdrv_get_type_hint(bdrv) != BDRV_TYPE_CDROM)
             return 0;
         p[0] = 0x2a;
         p[1] = 0x14;
+        if (page_control == 1) { /* Changeable Values */
+            return p[1] + 2;
+        }
         p[2] = 3; // CD-R & CD-RW read
         p[3] = 0; // Writing not supported
         p[4] = 0x7f; /* Audio, composite, digital out,
@@ -593,7 +614,7 @@ static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p)
         p[19] = (16 * 176) & 0xff;
         p[20] = (16 * 176) >> 8; // 16x write speed current
         p[21] = (16 * 176) & 0xff;
-        return 22;
+        return p[1] + 2;
 
     default:
         return 0;
@@ -604,29 +625,46 @@ static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf)
 {
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
     uint64_t nb_sectors;
-    int page, dbd, buflen;
+    int page, dbd, buflen, page_control;
     uint8_t *p;
+    uint8_t dev_specific_param;
 
     dbd = req->cmd.buf[1]  & 0x8;
     page = req->cmd.buf[2] & 0x3f;
-    DPRINTF("Mode Sense (page %d, len %zd)\n", page, req->cmd.xfer);
+    page_control = (req->cmd.buf[2] & 0xc0) >> 6;
+    DPRINTF("Mode Sense(%d) (page %d, xfer %zd, page_control %d)\n",
+        (req->cmd.buf[0] == MODE_SENSE) ? 6 : 10, page, req->cmd.xfer, page_control);
     memset(outbuf, 0, req->cmd.xfer);
     p = outbuf;
 
-    p[1] = 0; /* Default media type.  */
-    p[3] = 0; /* Block descriptor length.  */
     if (bdrv_is_read_only(s->bs)) {
-        p[2] = 0x80; /* Readonly.  */
+        dev_specific_param = 0x80; /* Readonly.  */
+    } else {
+        dev_specific_param = 0x00;
+    }
+
+    if (req->cmd.buf[0] == MODE_SENSE) {
+        p[1] = 0; /* Default media type.  */
+        p[2] = dev_specific_param;
+        p[3] = 0; /* Block descriptor length.  */
+        p += 4;
+    } else { /* MODE_SENSE_10 */
+        p[2] = 0; /* Default media type.  */
+        p[3] = dev_specific_param;
+        p[6] = p[7] = 0; /* Block descriptor length.  */
+        p += 8;
     }
-    p += 4;
 
     bdrv_get_geometry(s->bs, &nb_sectors);
-    if ((~dbd) & nb_sectors) {
-        outbuf[3] = 8; /* Block descriptor length  */
+    if (!dbd && nb_sectors) {
+        if (req->cmd.buf[0] == MODE_SENSE) {
+            outbuf[3] = 8; /* Block descriptor length  */
+        } else { /* MODE_SENSE_10 */
+            outbuf[7] = 8; /* Block descriptor length  */
+        }
         nb_sectors /= s->cluster_size;
-        nb_sectors--;
         if (nb_sectors > 0xffffff)
-            nb_sectors = 0xffffff;
+            nb_sectors = 0;
         p[0] = 0; /* media density code */
         p[1] = (nb_sectors >> 16) & 0xff;
         p[2] = (nb_sectors >> 8) & 0xff;
@@ -638,21 +676,37 @@ static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf)
         p += 8;
     }
 
+    if (page_control == 3) { /* Saved Values */
+        return -1; /* ILLEGAL_REQUEST */
+    }
+
     switch (page) {
     case 0x04:
     case 0x05:
     case 0x08:
     case 0x2a:
-        p += mode_sense_page(req, page, p);
+        p += mode_sense_page(req, page, p, page_control);
         break;
     case 0x3f:
-        p += mode_sense_page(req, 0x08, p);
-        p += mode_sense_page(req, 0x2a, p);
+        p += mode_sense_page(req, 0x08, p, page_control);
+        p += mode_sense_page(req, 0x2a, p, page_control);
         break;
+    default:
+        return -1; /* ILLEGAL_REQUEST */
     }
 
     buflen = p - outbuf;
-    outbuf[0] = buflen - 4;
+    /*
+     * The mode data length field specifies the length in bytes of the
+     * following data that is available to be transferred. The mode data
+     * length does not include itself.
+     */
+    if (req->cmd.buf[0] == MODE_SENSE) {
+        outbuf[0] = buflen - 1;
+    } else { /* MODE_SENSE_10 */
+        outbuf[0] = ((buflen - 2) >> 8) & 0xff;
+        outbuf[1] = (buflen - 2) & 0xff;
+    }
     if (buflen > req->cmd.xfer)
         buflen = req->cmd.xfer;
     return buflen;
@@ -839,6 +893,12 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf)
         break;
     case VERIFY:
         break;
+    case REZERO_UNIT:
+        DPRINTF("Rezero Unit\n");
+        if (!bdrv_is_inserted(s->bs)) {
+            goto not_ready;
+        }
+        break;
     default:
         goto illegal_request;
     }
@@ -880,7 +940,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
     }
     /* ??? Tags are not unique for different luns.  We only implement a
        single lun, so this should not matter.  */
-    r = scsi_new_request(d, tag, lun);
+    r = scsi_new_request(s, tag, lun);
     outbuf = (uint8_t *)r->iov.iov_base;
     is_write = 0;
     DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]);
@@ -958,6 +1018,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
     case SERVICE_ACTION_IN:
     case REPORT_LUNS:
     case VERIFY:
+    case REZERO_UNIT:
         rc = scsi_disk_emulate_command(&r->req, outbuf);
         if (rc > 0) {
             r->iov.iov_len = rc;
@@ -981,13 +1042,40 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
     case WRITE_10:
     case WRITE_12:
     case WRITE_16:
-        DPRINTF("Write (sector %" PRId64 ", count %d)\n", lba, len);
+    case WRITE_VERIFY:
+    case WRITE_VERIFY_12:
+    case WRITE_VERIFY_16:
+        DPRINTF("Write %s(sector %" PRId64 ", count %d)\n",
+                (command & 0xe) == 0xe ? "And Verify " : "", lba, len);
         if (lba > s->max_lba)
             goto illegal_lba;
         r->sector = lba * s->cluster_size;
         r->sector_count = len * s->cluster_size;
         is_write = 1;
         break;
+    case MODE_SELECT:
+        DPRINTF("Mode Select(6) (len %d)\n", len);
+        /* We don't support mode parameter changes.
+           Allow the mode parameter header + block descriptors only. */
+        if (len > 12) {
+            goto fail;
+        }
+        break;
+    case MODE_SELECT_10:
+        DPRINTF("Mode Select(10) (len %d)\n", len);
+        /* We don't support mode parameter changes.
+           Allow the mode parameter header + block descriptors only. */
+        if (len > 16) {
+            goto fail;
+        }
+        break;
+    case SEEK_6:
+    case SEEK_10:
+        DPRINTF("Seek(%d) (sector %" PRId64 ")\n", command == SEEK_6 ? 6 : 10, lba);
+        if (lba > s->max_lba) {
+            goto illegal_lba;
+        }
+        break;
     default:
 	DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
     fail:
@@ -1059,6 +1147,11 @@ static int scsi_disk_initfn(SCSIDevice *dev)
     s->bs = s->qdev.conf.bs;
     is_cd = bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM;
 
+    if (!is_cd && !bdrv_is_inserted(s->bs)) {
+        error_report("Device needs media, but drive is empty");
+        return -1;
+    }
+
     if (bdrv_get_on_error(s->bs, 1) != BLOCK_ERR_REPORT) {
         error_report("Device doesn't support drive option rerror");
         return -1;
@@ -1085,6 +1178,7 @@ static int scsi_disk_initfn(SCSIDevice *dev)
         s->qdev.blocksize = s->qdev.conf.logical_block_size;
     }
     s->cluster_size = s->qdev.blocksize / 512;
+    s->bs->buffer_alignment = s->qdev.blocksize;
 
     s->qdev.type = TYPE_DISK;
     qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index a8b4176d80..7212091695 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -14,6 +14,7 @@
 #include "qemu-common.h"
 #include "qemu-error.h"
 #include "scsi.h"
+#include "blockdev.h"
 
 #ifdef __linux__
 
@@ -163,7 +164,7 @@ static void scsi_read_complete(void * opaque, int ret)
     int len;
 
     if (ret) {
-        DPRINTF("IO error\n");
+        DPRINTF("IO error ret %d\n", ret);
         scsi_command_complete(r, ret);
         return;
     }
@@ -235,7 +236,7 @@ static void scsi_write_complete(void * opaque, int ret)
     if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
         s->qdev.type == TYPE_TAPE) {
         s->qdev.blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
-        DPRINTF("block size %d\n", s->blocksize);
+        DPRINTF("block size %d\n", s->qdev.blocksize);
     }
 
     scsi_command_complete(r, ret);
@@ -350,8 +351,18 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
     }
     scsi_req_fixup(&r->req);
 
-    DPRINTF("Command: lun=%d tag=0x%x data=0x%02x len %d\n", lun, tag,
-            cmd[0], r->req.cmd.xfer);
+    DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x", lun, tag,
+            r->req.cmd.xfer, cmd[0]);
+
+#ifdef DEBUG_SCSI
+    {
+        int i;
+        for (i = 1; i < r->req.cmd.len; i++) {
+            printf(" 0x%02x", cmd[i]);
+        }
+        printf("\n");
+    }
+#endif
 
     if (r->req.cmd.xfer == 0) {
         if (r->buf != NULL)
@@ -444,15 +455,31 @@ static int get_stream_blocksize(BlockDriverState *bdrv)
     return (buf[9] << 16) | (buf[10] << 8) | buf[11];
 }
 
-static void scsi_destroy(SCSIDevice *d)
+static void scsi_generic_purge_requests(SCSIGenericState *s)
 {
-    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
     SCSIGenericReq *r;
 
     while (!QTAILQ_EMPTY(&s->qdev.requests)) {
         r = DO_UPCAST(SCSIGenericReq, req, QTAILQ_FIRST(&s->qdev.requests));
+        if (r->req.aiocb) {
+            bdrv_aio_cancel(r->req.aiocb);
+        }
         scsi_remove_request(r);
     }
+}
+
+static void scsi_generic_reset(DeviceState *dev)
+{
+    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev.qdev, dev);
+
+    scsi_generic_purge_requests(s);
+}
+
+static void scsi_destroy(SCSIDevice *d)
+{
+    SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
+
+    scsi_generic_purge_requests(s);
     blockdev_mark_auto_del(s->qdev.conf.bs);
 }
 
@@ -526,6 +553,7 @@ static SCSIDeviceInfo scsi_generic_info = {
     .qdev.name    = "scsi-generic",
     .qdev.desc    = "pass through generic scsi device (/dev/sg*)",
     .qdev.size    = sizeof(SCSIGenericState),
+    .qdev.reset   = scsi_generic_reset,
     .init         = scsi_generic_initfn,
     .destroy      = scsi_destroy,
     .send_command = scsi_send_command,
diff --git a/hw/scsi.h b/hw/scsi.h
index 4fbf1d5dfd..cb06d6d824 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -43,6 +43,7 @@ typedef struct SCSIRequest {
         enum SCSIXferMode mode;
     } cmd;
     BlockDriverAIOCB  *aiocb;
+    bool enqueued;
     QTAILQ_ENTRY(SCSIRequest) next;
 } SCSIRequest;
 
diff --git a/hw/sd.c b/hw/sd.c
index c928120abd..601545b2d9 100644
--- a/hw/sd.c
+++ b/hw/sd.c
@@ -31,6 +31,7 @@
 
 #include "hw.h"
 #include "block.h"
+#include "block_int.h"
 #include "sd.h"
 
 //#define DEBUG_SD 1
@@ -440,7 +441,7 @@ SDState *sd_init(BlockDriverState *bs, int is_spi)
     SDState *sd;
 
     sd = (SDState *) qemu_mallocz(sizeof(SDState));
-    sd->buf = qemu_memalign(512, 512);
+    sd->buf = qemu_blockalign(bs, 512);
     sd->spi = is_spi;
     sd->enable = 1;
     sd_reset(sd, bs);
diff --git a/hw/serial.c b/hw/serial.c
index b66d13ad41..9ebc452aea 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -99,6 +99,14 @@
 #define RECV_FIFO           1
 #define MAX_XMIT_RETRY      4
 
+#ifdef DEBUG_SERIAL
+#define DPRINTF(fmt, ...) \
+do { fprintf(stderr, "serial: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+do {} while (0)
+#endif
+
 typedef struct SerialFIFO {
     uint8_t data[UART_FIFO_LENGTH];
     uint8_t count;
@@ -267,10 +275,9 @@ static void serial_update_parameters(SerialState *s)
     ssp.stop_bits = stop_bits;
     s->char_transmit_time =  (get_ticks_per_sec() / speed) * frame_size;
     qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
-#if 0
-    printf("speed=%d parity=%c data=%d stop=%d\n",
+
+    DPRINTF("speed=%d parity=%c data=%d stop=%d\n",
            speed, parity, data_bits, stop_bits);
-#endif
 }
 
 static void serial_update_msl(SerialState *s)
@@ -360,9 +367,7 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
     SerialState *s = opaque;
 
     addr &= 7;
-#ifdef DEBUG_SERIAL
-    printf("serial: write addr=0x%02x val=0x%02x\n", addr, val);
-#endif
+    DPRINTF("write addr=0x%02x val=0x%02x\n", addr, val);
     switch(addr) {
     default:
     case 0:
@@ -583,9 +588,7 @@ static uint32_t serial_ioport_read(void *opaque, uint32_t addr)
         ret = s->scr;
         break;
     }
-#ifdef DEBUG_SERIAL
-    printf("serial: read addr=0x%02x val=0x%02x\n", addr, ret);
-#endif
+    DPRINTF("read addr=0x%02x val=0x%02x\n", addr, ret);
     return ret;
 }
 
@@ -651,9 +654,7 @@ static void serial_receive1(void *opaque, const uint8_t *buf, int size)
 static void serial_event(void *opaque, int event)
 {
     SerialState *s = opaque;
-#ifdef DEBUG_SERIAL
-    printf("serial: event %x\n", event);
-#endif
+    DPRINTF("event %x\n", event);
     if (event == CHR_EVENT_BREAK)
         serial_receive_break(s);
 }
@@ -673,6 +674,7 @@ static int serial_post_load(void *opaque, int version_id)
     }
     /* Initialize fcr via setter to perform essential side-effects */
     serial_ioport_write(s, 0x02, s->fcr_vmstate);
+    serial_update_parameters(s);
     return 0;
 }
 
diff --git a/hw/sh_intc.c b/hw/sh_intc.c
index da36d32b1d..d3f5ea57d5 100644
--- a/hw/sh_intc.c
+++ b/hw/sh_intc.c
@@ -431,9 +431,8 @@ int sh_intc_init(struct intc_desc *desc,
     desc->nr_prio_regs = nr_prio_regs;
 
     i = sizeof(struct intc_source) * nr_sources;
-    desc->sources = qemu_malloc(i);
+    desc->sources = qemu_mallocz(i);
 
-    memset(desc->sources, 0, i);
     for (i = 0; i < desc->nr_sources; i++) {
         struct intc_source *source = desc->sources + i;
 
diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c
index d7875536b6..c125de4b62 100644
--- a/hw/slavio_timer.c
+++ b/hw/slavio_timer.c
@@ -377,12 +377,12 @@ static void slavio_timer_reset(DeviceState *d)
         curr_timer->limit = 0;
         curr_timer->count = 0;
         curr_timer->reached = 0;
-        if (i < s->num_cpus) {
+        if (i <= s->num_cpus) {
             ptimer_set_limit(curr_timer->timer,
                              LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
             ptimer_run(curr_timer->timer, 0);
+            curr_timer->running = 1;
         }
-        curr_timer->running = 1;
     }
     s->cputimer_mode = 0;
 }
diff --git a/hw/sm501.c b/hw/sm501.c
index 8e6932d747..705e0a5c76 100644
--- a/hw/sm501.c
+++ b/hw/sm501.c
@@ -29,6 +29,7 @@
 #include "devices.h"
 #include "sysbus.h"
 #include "qdev-addr.h"
+#include "range.h"
 
 /*
  * Status: 2010/05/07
@@ -814,7 +815,7 @@ static uint32_t sm501_palette_read(void *opaque, target_phys_addr_t addr)
     /* TODO : consider BYTE/WORD access */
     /* TODO : consider endian */
 
-    assert(0 <= addr && addr < 0x400 * 3);
+    assert(range_covers_byte(0, 0x400 * 3, addr));
     return *(uint32_t*)&s->dc_palette[addr];
 }
 
@@ -828,7 +829,7 @@ static void sm501_palette_write(void *opaque,
     /* TODO : consider BYTE/WORD access */
     /* TODO : consider endian */
 
-    assert(0 <= addr && addr < 0x400 * 3);
+    assert(range_covers_byte(0, 0x400 * 3, addr));
     *(uint32_t*)&s->dc_palette[addr] = value;
 }
 
diff --git a/hw/soc_dma.c b/hw/soc_dma.c
index e116e6373a..23ec51695a 100644
--- a/hw/soc_dma.c
+++ b/hw/soc_dma.c
@@ -192,12 +192,13 @@ static void soc_dma_ch_freq_update(struct dma_s *s)
     if (s->enabled_count)
         /* We completely ignore channel priorities and stuff */
         s->channel_freq = s->soc.freq / s->enabled_count;
-    else
+    else {
         /* TODO: Signal that we want to disable the functional clock and let
          * the platform code decide what to do with it, i.e. check that
          * auto-idle is enabled in the clock controller and if we are stopping
          * the clock, do the same with any parent clocks that had only one
-         * user keeping them on and auto-idle enabled.  */;
+         * user keeping them on and auto-idle enabled.  */
+    }
 }
 
 void soc_dma_set_request(struct soc_dma_ch_s *ch, int level)
diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c
index b52170787b..984ffc3e53 100644
--- a/hw/sparc32_dma.c
+++ b/hw/sparc32_dma.c
@@ -58,6 +58,7 @@
 #define DMA_INTR 1
 #define DMA_INTREN 0x10
 #define DMA_WRITE_MEM 0x100
+#define DMA_EN 0x200
 #define DMA_LOADED 0x04000000
 #define DMA_DRAIN_FIFO 0x40
 #define DMA_RESET 0x80
@@ -72,7 +73,12 @@ struct DMAState {
     uint32_t dmaregs[DMA_REGS];
     qemu_irq irq;
     void *iommu;
-    qemu_irq dev_reset;
+    qemu_irq gpio[2];
+};
+
+enum {
+    GPIO_RESET = 0,
+    GPIO_DMA,
 };
 
 /* Note: on sparc, the lance 16 bit bus is swapped */
@@ -201,12 +207,21 @@ static void dma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
             }
         }
         if (val & DMA_RESET) {
-            qemu_irq_raise(s->dev_reset);
-            qemu_irq_lower(s->dev_reset);
+            qemu_irq_raise(s->gpio[GPIO_RESET]);
+            qemu_irq_lower(s->gpio[GPIO_RESET]);
         } else if (val & DMA_DRAIN_FIFO) {
             val &= ~DMA_DRAIN_FIFO;
         } else if (val == 0)
             val = DMA_DRAIN_FIFO;
+
+        if (val & DMA_EN && !(s->dmaregs[0] & DMA_EN)) {
+            DPRINTF("Raise DMA enable\n");
+            qemu_irq_raise(s->gpio[GPIO_DMA]);
+        } else if (!(val & DMA_EN) && !!(s->dmaregs[0] & DMA_EN)) {
+            DPRINTF("Lower DMA enable\n");
+            qemu_irq_lower(s->gpio[GPIO_DMA]);
+        }
+
         val &= ~DMA_CSR_RO_MASK;
         val |= DMA_VER;
         s->dmaregs[0] = (s->dmaregs[0] & DMA_CSR_RO_MASK) | val;
@@ -262,7 +277,7 @@ static int sparc32_dma_init1(SysBusDevice *dev)
     sysbus_init_mmio(dev, DMA_SIZE, dma_io_memory);
 
     qdev_init_gpio_in(&dev->qdev, dma_set_irq, 1);
-    qdev_init_gpio_out(&dev->qdev, &s->dev_reset, 1);
+    qdev_init_gpio_out(&dev->qdev, s->gpio, 2);
 
     return 0;
 }
diff --git a/hw/spitz.c b/hw/spitz.c
index ccf2a091fb..a064460936 100644
--- a/hw/spitz.c
+++ b/hw/spitz.c
@@ -22,6 +22,7 @@
 #include "block.h"
 #include "audio/audio.h"
 #include "boards.h"
+#include "blockdev.h"
 
 #undef REG_FMT
 #define REG_FMT			"0x%02lx"
diff --git a/hw/sun4m.c b/hw/sun4m.c
index 208c8a86df..0392109230 100644
--- a/hw/sun4m.c
+++ b/hw/sun4m.c
@@ -40,6 +40,7 @@
 #include "qdev-addr.h"
 #include "loader.h"
 #include "elf.h"
+#include "blockdev.h"
 
 //#define DEBUG_IRQ
 
@@ -89,6 +90,7 @@
 
 #define MAX_CPUS 16
 #define MAX_PILS 16
+#define MAX_VSIMMS 4
 
 #define ESCC_CLOCK 4915200
 
@@ -98,6 +100,10 @@ struct sun4m_hwdef {
     target_phys_addr_t serial_base, fd_base;
     target_phys_addr_t afx_base, idreg_base, dma_base, esp_base, le_base;
     target_phys_addr_t tcx_base, cs_base, apc_base, aux1_base, aux2_base;
+    target_phys_addr_t bpp_base, dbri_base, sx_base;
+    struct {
+        target_phys_addr_t reg_base, vram_base;
+    } vsimm[MAX_VSIMMS];
     target_phys_addr_t ecc_base;
     uint32_t ecc_version;
     uint8_t nvram_machine_id;
@@ -804,12 +810,13 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size,
     void *iommu, *espdma, *ledma, *nvram;
     qemu_irq *cpu_irqs[MAX_CPUS], slavio_irq[32], slavio_cpu_irq[MAX_CPUS],
         espdma_irq, ledma_irq;
-    qemu_irq esp_reset;
+    qemu_irq esp_reset, dma_enable;
     qemu_irq fdc_tc;
     qemu_irq *cpu_halt;
     unsigned long kernel_size;
     DriveInfo *fd[MAX_FD];
     void *fw_cfg;
+    unsigned int num_vsimms;
 
     /* init CPUs */
     if (!cpu_model)
@@ -872,8 +879,22 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size,
         fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth);
         exit (1);
     }
-    tcx_init(hwdef->tcx_base, 0x00100000, graphic_width, graphic_height,
-             graphic_depth);
+    num_vsimms = 0;
+    if (num_vsimms == 0) {
+        tcx_init(hwdef->tcx_base, 0x00100000, graphic_width, graphic_height,
+                 graphic_depth);
+    }
+
+    for (i = num_vsimms; i < MAX_VSIMMS; i++) {
+        /* vsimm registers probed by OBP */
+        if (hwdef->vsimm[i].reg_base) {
+            empty_slot_init(hwdef->vsimm[i].reg_base, 0x2000);
+        }
+    }
+
+    if (hwdef->sx_base) {
+        empty_slot_init(hwdef->sx_base, 0x2000);
+    }
 
     lance_init(&nd_table[0], hwdef->le_base, ledma, ledma_irq);
 
@@ -909,17 +930,31 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size,
         exit(1);
     }
 
-    esp_reset = qdev_get_gpio_in(espdma, 0);
     esp_init(hwdef->esp_base, 2,
              espdma_memory_read, espdma_memory_write,
-             espdma, espdma_irq, &esp_reset);
+             espdma, espdma_irq, &esp_reset, &dma_enable);
 
+    qdev_connect_gpio_out(espdma, 0, esp_reset);
+    qdev_connect_gpio_out(espdma, 1, dma_enable);
 
     if (hwdef->cs_base) {
         sysbus_create_simple("SUNW,CS4231", hwdef->cs_base,
                              slavio_irq[5]);
     }
 
+    if (hwdef->dbri_base) {
+        /* ISDN chip with attached CS4215 audio codec */
+        /* prom space */
+        empty_slot_init(hwdef->dbri_base+0x1000, 0x30);
+        /* reg space */
+        empty_slot_init(hwdef->dbri_base+0x10000, 0x100);
+    }
+
+    if (hwdef->bpp_base) {
+        /* parallel port */
+        empty_slot_init(hwdef->bpp_base, 0x20);
+    }
+
     kernel_size = sun4m_load_kernel(kernel_filename, initrd_filename,
                                     RAM_size);
 
@@ -945,8 +980,11 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size,
         fw_cfg_add_bytes(fw_cfg, FW_CFG_CMDLINE_DATA,
                          (uint8_t*)strdup(kernel_cmdline),
                          strlen(kernel_cmdline) + 1);
+        fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
+                       strlen(kernel_cmdline) + 1);
     } else {
         fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0);
+        fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, 0);
     }
     fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, INITRD_LOAD_ADDR);
     fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, 0); // not used
@@ -1063,9 +1101,25 @@ static const struct sun4m_hwdef sun4m_hwdefs[] = {
         .dma_base     = 0xef0400000ULL,
         .esp_base     = 0xef0800000ULL,
         .le_base      = 0xef0c00000ULL,
+        .bpp_base     = 0xef4800000ULL,
         .apc_base     = 0xefa000000ULL, // XXX should not exist
         .aux1_base    = 0xff1800000ULL,
         .aux2_base    = 0xff1a01000ULL,
+        .dbri_base    = 0xee0000000ULL,
+        .sx_base      = 0xf80000000ULL,
+        .vsimm        = {
+            {
+                .reg_base  = 0x9c000000ULL,
+                .vram_base = 0xfc000000ULL
+            }, {
+                .reg_base  = 0x90000000ULL,
+                .vram_base = 0xf0000000ULL
+            }, {
+                .reg_base  = 0x94000000ULL
+            }, {
+                .reg_base  = 0x98000000ULL
+            }
+        },
         .ecc_base     = 0xf00000000ULL,
         .ecc_version  = 0x20000000, // version 0, implementation 2
         .nvram_machine_id = 0x72,
@@ -1441,7 +1495,7 @@ static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, ram_addr_t RAM_size,
     void *iounits[MAX_IOUNITS], *espdma, *ledma, *nvram;
     qemu_irq *cpu_irqs[MAX_CPUS], sbi_irq[32], sbi_cpu_irq[MAX_CPUS],
         espdma_irq, ledma_irq;
-    qemu_irq esp_reset;
+    qemu_irq esp_reset, dma_enable;
     unsigned long kernel_size;
     void *fw_cfg;
     DeviceState *dev;
@@ -1508,10 +1562,12 @@ static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, ram_addr_t RAM_size,
         exit(1);
     }
 
-    esp_reset = qdev_get_gpio_in(espdma, 0);
     esp_init(hwdef->esp_base, 2,
              espdma_memory_read, espdma_memory_write,
-             espdma, espdma_irq, &esp_reset);
+             espdma, espdma_irq, &esp_reset, &dma_enable);
+
+    qdev_connect_gpio_out(espdma, 0, esp_reset);
+    qdev_connect_gpio_out(espdma, 1, dma_enable);
 
     kernel_size = sun4m_load_kernel(kernel_filename, initrd_filename,
                                     RAM_size);
@@ -1630,7 +1686,7 @@ static void sun4c_hw_init(const struct sun4c_hwdef *hwdef, ram_addr_t RAM_size,
 {
     void *iommu, *espdma, *ledma, *nvram;
     qemu_irq *cpu_irqs, slavio_irq[8], espdma_irq, ledma_irq;
-    qemu_irq esp_reset;
+    qemu_irq esp_reset, dma_enable;
     qemu_irq fdc_tc;
     unsigned long kernel_size;
     DriveInfo *fd[MAX_FD];
@@ -1698,10 +1754,12 @@ static void sun4c_hw_init(const struct sun4c_hwdef *hwdef, ram_addr_t RAM_size,
         exit(1);
     }
 
-    esp_reset = qdev_get_gpio_in(espdma, 0);
     esp_init(hwdef->esp_base, 2,
              espdma_memory_read, espdma_memory_write,
-             espdma, espdma_irq, &esp_reset);
+             espdma, espdma_irq, &esp_reset, &dma_enable);
+
+    qdev_connect_gpio_out(espdma, 0, esp_reset);
+    qdev_connect_gpio_out(espdma, 1, dma_enable);
 
     kernel_size = sun4m_load_kernel(kernel_filename, initrd_filename,
                                     RAM_size);
diff --git a/hw/sun4u.c b/hw/sun4u.c
index 31c0c4c482..45a46d673c 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -37,6 +37,7 @@
 #include "ide.h"
 #include "loader.h"
 #include "elf.h"
+#include "blockdev.h"
 
 //#define DEBUG_IRQ
 //#define DEBUG_EBUS
diff --git a/hw/syborg_virtio.c b/hw/syborg_virtio.c
index abf0370107..4dfd1a87b9 100644
--- a/hw/syborg_virtio.c
+++ b/hw/syborg_virtio.c
@@ -68,6 +68,7 @@ typedef struct {
     uint32_t id;
     NICConf nic;
     uint32_t host_features;
+    virtio_net_conf net;
 } SyborgVirtIOProxy;
 
 static uint32_t syborg_virtio_readl(void *opaque, target_phys_addr_t offset)
@@ -284,7 +285,7 @@ static int syborg_virtio_net_init(SysBusDevice *dev)
     VirtIODevice *vdev;
     SyborgVirtIOProxy *proxy = FROM_SYSBUS(SyborgVirtIOProxy, dev);
 
-    vdev = virtio_net_init(&dev->qdev, &proxy->nic);
+    vdev = virtio_net_init(&dev->qdev, &proxy->nic, &proxy->net);
     return syborg_virtio_init(proxy, vdev);
 }
 
@@ -295,6 +296,11 @@ static SysBusDeviceInfo syborg_virtio_net_info = {
     .qdev.props = (Property[]) {
         DEFINE_NIC_PROPERTIES(SyborgVirtIOProxy, nic),
         DEFINE_VIRTIO_NET_FEATURES(SyborgVirtIOProxy, host_features),
+        DEFINE_PROP_UINT32("x-txtimer", SyborgVirtIOProxy,
+                           net.txtimer, TX_TIMER_INTERVAL),
+        DEFINE_PROP_INT32("x-txburst", SyborgVirtIOProxy,
+                          net.txburst, TX_BURST),
+        DEFINE_PROP_STRING("tx", SyborgVirtIOProxy, net.tx),
         DEFINE_PROP_END_OF_LIST(),
     }
 };
diff --git a/hw/sysbus.c b/hw/sysbus.c
index 1f7f138416..d817721420 100644
--- a/hw/sysbus.c
+++ b/hw/sysbus.c
@@ -82,7 +82,8 @@ void sysbus_pass_irq(SysBusDevice *dev, SysBusDevice *target)
     }
 }
 
-void sysbus_init_mmio(SysBusDevice *dev, target_phys_addr_t size, int iofunc)
+void sysbus_init_mmio(SysBusDevice *dev, target_phys_addr_t size,
+                      ram_addr_t iofunc)
 {
     int n;
 
diff --git a/hw/sysbus.h b/hw/sysbus.h
index 1a8f289c75..5980901845 100644
--- a/hw/sysbus.h
+++ b/hw/sysbus.h
@@ -21,7 +21,7 @@ struct SysBusDevice {
         target_phys_addr_t addr;
         target_phys_addr_t size;
         mmio_mapfunc cb;
-        int iofunc;
+        ram_addr_t iofunc;
     } mmio[QDEV_MAX_MMIO];
 };
 
@@ -39,7 +39,8 @@ typedef struct {
 void sysbus_register_dev(const char *name, size_t size, sysbus_initfn init);
 void sysbus_register_withprop(SysBusDeviceInfo *info);
 void *sysbus_new(void);
-void sysbus_init_mmio(SysBusDevice *dev, target_phys_addr_t size, int iofunc);
+void sysbus_init_mmio(SysBusDevice *dev, target_phys_addr_t size,
+                      ram_addr_t iofunc);
 void sysbus_init_mmio_cb(SysBusDevice *dev, target_phys_addr_t size,
                             mmio_mapfunc cb);
 void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p);
diff --git a/hw/tc6393xb_template.h b/hw/tc6393xb_template.h
index 37bf8336be..1ccf6e8dfe 100644
--- a/hw/tc6393xb_template.h
+++ b/hw/tc6393xb_template.h
@@ -38,12 +38,10 @@
 static void glue(tc6393xb_draw_graphic, BITS)(TC6393xbState *s)
 {
     int i;
-    int w_display;
     uint16_t *data_buffer;
     uint8_t *data_display;
 
     data_buffer = s->vram_ptr;
-    w_display = s->scr_width * BITS / 8;
     data_display = ds_get_data(s->ds);
     for(i = 0; i < s->scr_height; i++) {
 #if (BITS == 16)
diff --git a/hw/tosa.c b/hw/tosa.c
index ba6d9e73bf..cc8ce6d641 100644
--- a/hw/tosa.c
+++ b/hw/tosa.c
@@ -19,6 +19,7 @@
 #include "boards.h"
 #include "i2c.h"
 #include "ssi.h"
+#include "blockdev.h"
 
 #define TOSA_RAM    0x04000000
 #define TOSA_ROM	0x00800000
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index 65e9624e54..0a95d8d506 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -15,6 +15,7 @@
 #include "console.h"
 #include "monitor.h"
 #include "sysemu.h"
+#include "blockdev.h"
 
 //#define DEBUG_MSD
 
@@ -575,7 +576,7 @@ static USBDevice *usb_msd_init(const char *filename)
 
     /* parse -usbdevice disk: syntax into drive opts */
     snprintf(id, sizeof(id), "usb%d", nr++);
-    opts = qemu_opts_create(&qemu_drive_opts, id, 0);
+    opts = qemu_opts_create(qemu_find_opts("drive"), id, 0);
 
     p1 = strchr(filename, ':');
     if (p1++) {
diff --git a/hw/usb-net.c b/hw/usb-net.c
index a43bd17636..70f9263291 100644
--- a/hw/usb-net.c
+++ b/hw/usb-net.c
@@ -1472,7 +1472,7 @@ static USBDevice *usb_net_init(const char *cmdline)
     QemuOpts *opts;
     int idx;
 
-    opts = qemu_opts_parse(&qemu_net_opts, cmdline, 0);
+    opts = qemu_opts_parse(qemu_find_opts("net"), cmdline, 0);
     if (!opts) {
         return NULL;
     }
diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c
index fe052eb756..47f26cd0a3 100644
--- a/hw/usb-wacom.c
+++ b/hw/usb-wacom.c
@@ -160,6 +160,7 @@ static int usb_mouse_poll(USBWacomState *s, uint8_t *buf, int len)
     if (!s->mouse_grabbed) {
         s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, s, 0,
                         "QEMU PenPartner tablet");
+        qemu_activate_mouse_event_handler(s->eh_entry);
         s->mouse_grabbed = 1;
     }
 
@@ -197,6 +198,7 @@ static int usb_wacom_poll(USBWacomState *s, uint8_t *buf, int len)
     if (!s->mouse_grabbed) {
         s->eh_entry = qemu_add_mouse_event_handler(usb_wacom_event, s, 1,
                         "QEMU PenPartner tablet");
+        qemu_activate_mouse_event_handler(s->eh_entry);
         s->mouse_grabbed = 1;
     }
 
@@ -334,8 +336,10 @@ static int usb_wacom_handle_control(USBDevice *dev, int request, int value,
         ret = 0;
         break;
     case WACOM_SET_REPORT:
-        qemu_remove_mouse_event_handler(s->eh_entry);
-        s->mouse_grabbed = 0;
+        if (s->mouse_grabbed) {
+            qemu_remove_mouse_event_handler(s->eh_entry);
+            s->mouse_grabbed = 0;
+        }
         s->mode = data[0];
         ret = 0;
         break;
@@ -397,7 +401,10 @@ static void usb_wacom_handle_destroy(USBDevice *dev)
 {
     USBWacomState *s = (USBWacomState *) dev;
 
-    qemu_remove_mouse_event_handler(s->eh_entry);
+    if (s->mouse_grabbed) {
+        qemu_remove_mouse_event_handler(s->eh_entry);
+        s->mouse_grabbed = 0;
+    }
 }
 
 static int usb_wacom_initfn(USBDevice *dev)
diff --git a/hw/versatilepb.c b/hw/versatilepb.c
index 1d049f2342..c51ee02c4d 100644
--- a/hw/versatilepb.c
+++ b/hw/versatilepb.c
@@ -16,6 +16,7 @@
 #include "pci.h"
 #include "usb-ohci.h"
 #include "boards.h"
+#include "blockdev.h"
 
 /* Primary interrupt controller.  */
 
diff --git a/hw/vga.c b/hw/vga.c
index b5c7ee7fe3..966185e03b 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -2313,13 +2313,6 @@ void vga_init(VGACommonState *s)
 
     register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
     register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
-
-    /* old Bochs IO ports */
-    register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
-    register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
-
-    register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
-    register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s);
 #else
     register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
     register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
diff --git a/hw/vhost.c b/hw/vhost.c
index 65709d005d..8586f66bac 100644
--- a/hw/vhost.c
+++ b/hw/vhost.c
@@ -11,11 +11,9 @@
  */
 
 #include <sys/ioctl.h>
-#include <sys/eventfd.h>
 #include "vhost.h"
 #include "hw/hw.h"
-/* For range_get_last */
-#include "pci.h"
+#include "range.h"
 #include <linux/vhost.h>
 
 static void vhost_dev_sync_region(struct vhost_dev *dev,
@@ -456,11 +454,6 @@ static int vhost_virtqueue_init(struct vhost_dev *dev,
     };
     struct VirtQueue *vvq = virtio_get_queue(vdev, idx);
 
-    if (!vdev->binding->set_guest_notifier) {
-        fprintf(stderr, "binding does not support guest notifiers\n");
-        return -ENOSYS;
-    }
-
     if (!vdev->binding->set_host_notifier) {
         fprintf(stderr, "binding does not support host notifiers\n");
         return -ENOSYS;
@@ -513,12 +506,6 @@ static int vhost_virtqueue_init(struct vhost_dev *dev,
         r = -errno;
         goto fail_alloc;
     }
-    r = vdev->binding->set_guest_notifier(vdev->binding_opaque, idx, true);
-    if (r < 0) {
-        fprintf(stderr, "Error binding guest notifier: %d\n", -r);
-        goto fail_guest_notifier;
-    }
-
     r = vdev->binding->set_host_notifier(vdev->binding_opaque, idx, true);
     if (r < 0) {
         fprintf(stderr, "Error binding host notifier: %d\n", -r);
@@ -528,12 +515,14 @@ static int vhost_virtqueue_init(struct vhost_dev *dev,
     file.fd = event_notifier_get_fd(virtio_queue_get_host_notifier(vvq));
     r = ioctl(dev->control, VHOST_SET_VRING_KICK, &file);
     if (r) {
+        r = -errno;
         goto fail_kick;
     }
 
     file.fd = event_notifier_get_fd(virtio_queue_get_guest_notifier(vvq));
     r = ioctl(dev->control, VHOST_SET_VRING_CALL, &file);
     if (r) {
+        r = -errno;
         goto fail_call;
     }
 
@@ -543,8 +532,6 @@ fail_call:
 fail_kick:
     vdev->binding->set_host_notifier(vdev->binding_opaque, idx, false);
 fail_host_notifier:
-    vdev->binding->set_guest_notifier(vdev->binding_opaque, idx, false);
-fail_guest_notifier:
 fail_alloc:
     cpu_physical_memory_unmap(vq->ring, virtio_queue_get_ring_size(vdev, idx),
                               0, 0);
@@ -570,13 +557,6 @@ static void vhost_virtqueue_cleanup(struct vhost_dev *dev,
         .index = idx,
     };
     int r;
-    r = vdev->binding->set_guest_notifier(vdev->binding_opaque, idx, false);
-    if (r < 0) {
-        fprintf(stderr, "vhost VQ %d guest cleanup failed: %d\n", idx, r);
-        fflush(stderr);
-    }
-    assert (r >= 0);
-
     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);
@@ -649,15 +629,26 @@ void vhost_dev_cleanup(struct vhost_dev *hdev)
 int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
 {
     int i, r;
+    if (!vdev->binding->set_guest_notifiers) {
+        fprintf(stderr, "binding does not support guest notifiers\n");
+        r = -ENOSYS;
+        goto fail;
+    }
+
+    r = vdev->binding->set_guest_notifiers(vdev->binding_opaque, true);
+    if (r < 0) {
+        fprintf(stderr, "Error binding guest notifier: %d\n", -r);
+        goto fail_notifiers;
+    }
 
     r = vhost_dev_set_features(hdev, hdev->log_enabled);
     if (r < 0) {
-        goto fail;
+        goto fail_features;
     }
     r = ioctl(hdev->control, VHOST_SET_MEM_TABLE, hdev->mem);
     if (r < 0) {
         r = -errno;
-        goto fail;
+        goto fail_mem;
     }
     for (i = 0; i < hdev->nvqs; ++i) {
         r = vhost_virtqueue_init(hdev,
@@ -677,13 +668,14 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
                   (uint64_t)(unsigned long)hdev->log);
         if (r < 0) {
             r = -errno;
-            goto fail_vq;
+            goto fail_log;
         }
     }
 
     hdev->started = true;
 
     return 0;
+fail_log:
 fail_vq:
     while (--i >= 0) {
         vhost_virtqueue_cleanup(hdev,
@@ -691,13 +683,18 @@ fail_vq:
                                 hdev->vqs + i,
                                 i);
     }
+fail_mem:
+fail_features:
+    vdev->binding->set_guest_notifiers(vdev->binding_opaque, false);
+fail_notifiers:
 fail:
     return r;
 }
 
 void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev)
 {
-    int i;
+    int i, r;
+
     for (i = 0; i < hdev->nvqs; ++i) {
         vhost_virtqueue_cleanup(hdev,
                                 vdev,
@@ -706,6 +703,13 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev)
     }
     vhost_client_sync_dirty_bitmap(&hdev->client, 0,
                                    (target_phys_addr_t)~0x0ull);
+    r = vdev->binding->set_guest_notifiers(vdev->binding_opaque, false);
+    if (r < 0) {
+        fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", r);
+        fflush(stderr);
+    }
+    assert (r >= 0);
+
     hdev->started = false;
     qemu_free(hdev->log);
     hdev->log_size = 0;
diff --git a/hw/vhost_net.c b/hw/vhost_net.c
index 606aa0c1c9..c068be1f54 100644
--- a/hw/vhost_net.c
+++ b/hw/vhost_net.c
@@ -20,7 +20,6 @@
 
 #ifdef CONFIG_VHOST_NET
 #include <linux/vhost.h>
-#include <sys/eventfd.h>
 #include <sys/socket.h>
 #include <linux/kvm.h>
 #include <fcntl.h>
@@ -51,7 +50,9 @@ unsigned vhost_net_get_features(struct vhost_net *net, unsigned features)
     if (!(net->dev.features & (1 << VIRTIO_RING_F_INDIRECT_DESC))) {
         features &= ~(1 << VIRTIO_RING_F_INDIRECT_DESC);
     }
-    features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
+    if (!(net->dev.features & (1 << VIRTIO_NET_F_MRG_RXBUF))) {
+        features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
+    }
     return features;
 }
 
@@ -64,6 +65,9 @@ void vhost_net_ack_features(struct vhost_net *net, unsigned features)
     if (features & (1 << VIRTIO_RING_F_INDIRECT_DESC)) {
         net->dev.acked_features |= (1 << VIRTIO_RING_F_INDIRECT_DESC);
     }
+    if (features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
+        net->dev.acked_features |= (1 << VIRTIO_NET_F_MRG_RXBUF);
+    }
 }
 
 static int vhost_net_get_fd(VLANClientState *backend)
@@ -98,6 +102,10 @@ struct vhost_net *vhost_net_init(VLANClientState *backend, int devfd)
     if (r < 0) {
         goto fail;
     }
+    if (!tap_has_vnet_hdr_len(backend,
+                              sizeof(struct virtio_net_hdr_mrg_rxbuf))) {
+        net->dev.features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
+    }
     if (~net->dev.features & net->dev.backend_features) {
         fprintf(stderr, "vhost lacks feature mask %" PRIu64 " for backend\n",
                 (uint64_t)(~net->dev.features & net->dev.backend_features));
@@ -118,6 +126,10 @@ int vhost_net_start(struct vhost_net *net,
 {
     struct vhost_vring_file file = { };
     int r;
+    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;
@@ -139,12 +151,15 @@ int vhost_net_start(struct vhost_net *net,
     return 0;
 fail:
     file.fd = -1;
-    while (--file.index >= 0) {
+    while (file.index-- > 0) {
         int r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file);
         assert(r >= 0);
     }
     net->vc->info->poll(net->vc, true);
     vhost_dev_stop(&net->dev, dev);
+    if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
+        tap_set_vnet_hdr_len(net->vc, sizeof(struct virtio_net_hdr));
+    }
     return r;
 }
 
@@ -159,11 +174,17 @@ void vhost_net_stop(struct vhost_net *net,
     }
     net->vc->info->poll(net->vc, true);
     vhost_dev_stop(&net->dev, dev);
+    if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
+        tap_set_vnet_hdr_len(net->vc, sizeof(struct virtio_net_hdr));
+    }
 }
 
 void vhost_net_cleanup(struct vhost_net *net)
 {
     vhost_dev_cleanup(&net->dev);
+    if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
+        tap_set_vnet_hdr_len(net->vc, sizeof(struct virtio_net_hdr));
+    }
     qemu_free(net);
 }
 #else
diff --git a/hw/virtex_ml507.c b/hw/virtex_ml507.c
new file mode 100644
index 0000000000..fa605158e7
--- /dev/null
+++ b/hw/virtex_ml507.c
@@ -0,0 +1,276 @@
+/*
+ * Model of Xilinx Virtex5 ML507 PPC-440 refdesign.
+ *
+ * Copyright (c) 2010 Edgar E. Iglesias.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "sysbus.h"
+#include "hw.h"
+#include "pc.h"
+#include "net.h"
+#include "flash.h"
+#include "sysemu.h"
+#include "devices.h"
+#include "boards.h"
+#include "device_tree.h"
+#include "loader.h"
+#include "elf.h"
+#include "qemu-log.h"
+
+#include "ppc.h"
+#include "ppc4xx.h"
+#include "ppc440.h"
+#include "ppc405.h"
+
+#include "blockdev.h"
+#include "xilinx.h"
+
+#define EPAPR_MAGIC    (0x45504150)
+#define FLASH_SIZE     (16 * 1024 * 1024)
+
+static struct boot_info
+{
+    uint32_t bootstrap_pc;
+    uint32_t cmdline;
+    uint32_t fdt;
+    uint32_t ima_size;
+    void *vfdt;
+} boot_info;
+
+/* Create reset TLB entries for BookE, spanning the 32bit addr space.  */
+static void mmubooke_create_initial_mapping(CPUState *env,
+                                     target_ulong va,
+                                     target_phys_addr_t pa)
+{
+    ppcemb_tlb_t *tlb = &env->tlb[0].tlbe;
+
+    tlb->attr = 0;
+    tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
+    tlb->size = 1 << 31; /* up to 0x80000000  */
+    tlb->EPN = va & TARGET_PAGE_MASK;
+    tlb->RPN = pa & TARGET_PAGE_MASK;
+    tlb->PID = 0;
+
+    tlb = &env->tlb[1].tlbe;
+    tlb->attr = 0;
+    tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
+    tlb->size = 1 << 31; /* up to 0xffffffff  */
+    tlb->EPN = 0x80000000 & TARGET_PAGE_MASK;
+    tlb->RPN = 0x80000000 & TARGET_PAGE_MASK;
+    tlb->PID = 0;
+}
+
+static CPUState *ppc440_init_xilinx(ram_addr_t *ram_size,
+                                    int do_init,
+                                    const char *cpu_model,
+                                    clk_setup_t *cpu_clk, clk_setup_t *tb_clk,
+                                    uint32_t sysclk)
+{
+    CPUState *env;
+    qemu_irq *irqs;
+
+    env = cpu_init(cpu_model);
+    if (!env) {
+        fprintf(stderr, "Unable to initialize CPU!\n");
+        exit(1);
+    }
+
+    cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */
+    cpu_clk->opaque = env;
+    /* Set time-base frequency to sysclk */
+    tb_clk->cb = ppc_emb_timers_init(env, sysclk, PPC_INTERRUPT_DECR);
+    tb_clk->opaque = env;
+
+    ppc_dcr_init(env, NULL, NULL);
+
+    /* interrupt controller */
+    irqs = qemu_mallocz(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
+    irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
+    irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
+    ppcuic_init(env, irqs, 0x0C0, 0, 1);
+    return env;
+}
+
+static void main_cpu_reset(void *opaque)
+{
+    CPUState *env = opaque;
+    struct boot_info *bi = env->load_info;
+
+    cpu_reset(env);
+    /* Linux Kernel Parameters (passing device tree):
+       *   r3: pointer to the fdt
+       *   r4: 0
+       *   r5: 0
+       *   r6: epapr magic
+       *   r7: size of IMA in bytes
+       *   r8: 0
+       *   r9: 0
+    */
+    env->gpr[1] = (16<<20) - 8;
+    /* Provide a device-tree.  */
+    env->gpr[3] = bi->fdt;
+    env->nip = bi->bootstrap_pc;
+
+    /* Create a mapping for the kernel.  */
+    mmubooke_create_initial_mapping(env, 0, 0);
+    env->gpr[6] = tswap32(EPAPR_MAGIC);
+    env->gpr[7] = bi->ima_size;
+}
+
+#define BINARY_DEVICE_TREE_FILE "virtex-ml507.dtb"
+static int xilinx_load_device_tree(target_phys_addr_t addr,
+                                      uint32_t ramsize,
+                                      target_phys_addr_t initrd_base,
+                                      target_phys_addr_t initrd_size,
+                                      const char *kernel_cmdline)
+{
+    char *path;
+    int fdt_size;
+#ifdef CONFIG_FDT
+    void *fdt;
+    int r;
+
+    /* Try the local "ppc.dtb" override.  */
+    fdt = load_device_tree("ppc.dtb", &fdt_size);
+    if (!fdt) {
+        path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
+        if (path) {
+            fdt = load_device_tree(path, &fdt_size);
+            qemu_free(path);
+        }
+        if (!fdt) {
+            return 0;
+        }
+    }
+
+    r = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline);
+    if (r < 0)
+        fprintf(stderr, "couldn't set /chosen/bootargs\n");
+    cpu_physical_memory_write (addr, (void *)fdt, fdt_size);
+#else
+    /* We lack libfdt so we cannot manipulate the fdt. Just pass on the blob
+       to the kernel.  */
+    fdt_size = load_image_targphys("ppc.dtb", addr, 0x10000);
+    if (fdt_size < 0) {
+        path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
+        if (path) {
+            fdt_size = load_image_targphys(path, addr, 0x10000);
+            qemu_free(path);
+        }
+    }
+
+    if (kernel_cmdline) {
+        fprintf(stderr,
+                "Warning: missing libfdt, cannot pass cmdline to kernel!\n");
+    }
+#endif
+    return fdt_size;
+}
+
+static void virtex_init(ram_addr_t ram_size,
+                        const char *boot_device,
+                        const char *kernel_filename,
+                        const char *kernel_cmdline,
+                        const char *initrd_filename, const char *cpu_model)
+{
+    DeviceState *dev;
+    CPUState *env;
+    target_phys_addr_t ram_base = 0;
+    DriveInfo *dinfo;
+    ram_addr_t phys_ram;
+    ram_addr_t phys_flash;
+    qemu_irq irq[32], *cpu_irq;
+    clk_setup_t clk_setup[7];
+    int kernel_size;
+    int i;
+
+    /* init CPUs */
+    if (cpu_model == NULL) {
+        cpu_model = "440-Xilinx";
+    }
+
+    memset(clk_setup, 0, sizeof(clk_setup));
+    env = ppc440_init_xilinx(&ram_size, 1, cpu_model, &clk_setup[0],
+                             &clk_setup[1], 400000000);
+    qemu_register_reset(main_cpu_reset, env);
+
+    phys_ram = qemu_ram_alloc(NULL, "ram", ram_size);
+    cpu_register_physical_memory(ram_base, ram_size, phys_ram | IO_MEM_RAM);
+
+    phys_flash = qemu_ram_alloc(NULL, "virtex.flash", FLASH_SIZE);
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    pflash_cfi01_register(0xfc000000, phys_flash,
+                          dinfo ? dinfo->bdrv : NULL, (64 * 1024),
+                          FLASH_SIZE >> 16,
+                          1, 0x89, 0x18, 0x0000, 0x0, 1);
+
+    cpu_irq = (qemu_irq *) &env->irq_inputs[PPC40x_INPUT_INT];
+    dev = xilinx_intc_create(0x81800000, cpu_irq[0], 0);
+    for (i = 0; i < 32; i++) {
+        irq[i] = qdev_get_gpio_in(dev, i);
+    }
+
+    serial_mm_init(0x83e01003ULL, 2, irq[9], 115200, serial_hds[0], 1, 0);
+
+    /* 2 timers at irq 2 @ 62 Mhz.  */
+    xilinx_timer_create(0x83c00000, irq[3], 2, 62 * 1000000);
+
+    if (kernel_filename) {
+        uint64_t entry, low, high;
+        target_phys_addr_t boot_offset;
+
+        /* Boots a kernel elf binary.  */
+        kernel_size = load_elf(kernel_filename, NULL, NULL,
+                               &entry, &low, &high, 1, ELF_MACHINE, 0);
+        boot_info.bootstrap_pc = entry & 0x00ffffff;
+
+        if (kernel_size < 0) {
+            boot_offset = 0x1200000;
+            /* If we failed loading ELF's try a raw image.  */
+            kernel_size = load_image_targphys(kernel_filename,
+                                              boot_offset,
+                                              ram_size);
+            boot_info.bootstrap_pc = boot_offset;
+            high = boot_info.bootstrap_pc + kernel_size + 8192;
+        }
+
+        boot_info.ima_size = kernel_size;
+
+        /* Provide a device-tree.  */
+        boot_info.fdt = high + (8192 * 2);
+        boot_info.fdt &= ~8191;
+        xilinx_load_device_tree(boot_info.fdt, ram_size, 0, 0, kernel_cmdline);
+    }
+    env->load_info = &boot_info;
+}
+
+static QEMUMachine virtex_machine = {
+    .name = "virtex-ml507",
+    .desc = "Xilinx Virtex ML507 reference design",
+    .init = virtex_init,
+};
+
+static void virtex_machine_init(void)
+{
+    qemu_register_machine(&virtex_machine);
+}
+
+machine_init(virtex_machine_init);
diff --git a/hw/virtio-9p-debug.c b/hw/virtio-9p-debug.c
index e4ab4bca5f..cff5b07297 100644
--- a/hw/virtio-9p-debug.c
+++ b/hw/virtio-9p-debug.c
@@ -169,15 +169,37 @@ static void pprint_stat(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
     pprint_str(pdu, rx, offsetp, ", uid");
     pprint_str(pdu, rx, offsetp, ", gid");
     pprint_str(pdu, rx, offsetp, ", muid");
-    if (dotu) {
-        pprint_str(pdu, rx, offsetp, ", extension");
-        pprint_int32(pdu, rx, offsetp, ", uid");
-        pprint_int32(pdu, rx, offsetp, ", gid");
-        pprint_int32(pdu, rx, offsetp, ", muid");
-    }
+    pprint_str(pdu, rx, offsetp, ", extension");
+    pprint_int32(pdu, rx, offsetp, ", uid");
+    pprint_int32(pdu, rx, offsetp, ", gid");
+    pprint_int32(pdu, rx, offsetp, ", muid");
+    fprintf(llogfile, "}");
+}
+
+static void pprint_stat_dotl(V9fsPDU *pdu, int rx, size_t *offsetp,
+                                                  const char *name)
+{
+    fprintf(llogfile, "%s={", name);
+    pprint_qid(pdu, rx, offsetp, "qid");
+    pprint_int32(pdu, rx, offsetp, ", st_mode");
+    pprint_int64(pdu, rx, offsetp, ", st_nlink");
+    pprint_int32(pdu, rx, offsetp, ", st_uid");
+    pprint_int32(pdu, rx, offsetp, ", st_gid");
+    pprint_int64(pdu, rx, offsetp, ", st_rdev");
+    pprint_int64(pdu, rx, offsetp, ", st_size");
+    pprint_int64(pdu, rx, offsetp, ", st_blksize");
+    pprint_int64(pdu, rx, offsetp, ", st_blocks");
+    pprint_int64(pdu, rx, offsetp, ", atime");
+    pprint_int64(pdu, rx, offsetp, ", atime_nsec");
+    pprint_int64(pdu, rx, offsetp, ", mtime");
+    pprint_int64(pdu, rx, offsetp, ", mtime_nsec");
+    pprint_int64(pdu, rx, offsetp, ", ctime");
+    pprint_int64(pdu, rx, offsetp, ", ctime_nsec");
     fprintf(llogfile, "}");
 }
 
+
+
 static void pprint_strs(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
 {
     int sg_count = get_sg_count(pdu, rx);
@@ -327,7 +349,33 @@ void pprint_pdu(V9fsPDU *pdu)
         llogfile = fopen("/tmp/pdu.log", "w");
     }
 
+    BUG_ON(!llogfile);
+
     switch (pdu->id) {
+    case P9_TREADDIR:
+        fprintf(llogfile, "TREADDIR: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_int64(pdu, 0, &offset, ", initial offset");
+        pprint_int32(pdu, 0, &offset, ", max count");
+        break;
+    case P9_RREADDIR:
+        fprintf(llogfile, "RREADDIR: (");
+        pprint_int32(pdu, 1, &offset, "count");
+#ifdef DEBUG_DATA
+        pprint_data(pdu, 1, &offset, ", data");
+#endif
+        break;
+    case P9_TMKDIR:
+        fprintf(llogfile, "TMKDIR: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_str(pdu, 0, &offset, "name");
+        pprint_int32(pdu, 0, &offset, "mode");
+        pprint_int32(pdu, 0, &offset, "gid");
+        break;
+    case P9_RMKDIR:
+        fprintf(llogfile, "RMKDIR: (");
+        pprint_qid(pdu, 0, &offset, "qid");
+        break;
     case P9_TVERSION:
         fprintf(llogfile, "TVERSION: (");
         pprint_int32(pdu, 0, &offset, "msize");
@@ -338,14 +386,20 @@ void pprint_pdu(V9fsPDU *pdu)
         pprint_int32(pdu, 1, &offset, "msize");
         pprint_str(pdu, 1, &offset, ", version");
         break;
+    case P9_TGETATTR:
+        fprintf(llogfile, "TGETATTR: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        break;
+    case P9_RGETATTR:
+        fprintf(llogfile, "RGETATTR: (");
+        pprint_stat_dotl(pdu, 1, &offset, "getattr");
+        break;
     case P9_TAUTH:
         fprintf(llogfile, "TAUTH: (");
         pprint_int32(pdu, 0, &offset, "afid");
         pprint_str(pdu, 0, &offset, ", uname");
         pprint_str(pdu, 0, &offset, ", aname");
-        if (dotu) {
-            pprint_int32(pdu, 0, &offset, ", n_uname");
-        }
+        pprint_int32(pdu, 0, &offset, ", n_uname");
         break;
     case P9_RAUTH:
         fprintf(llogfile, "RAUTH: (");
@@ -357,9 +411,7 @@ void pprint_pdu(V9fsPDU *pdu)
         pprint_int32(pdu, 0, &offset, ", afid");
         pprint_str(pdu, 0, &offset, ", uname");
         pprint_str(pdu, 0, &offset, ", aname");
-        if (dotu) {
-            pprint_int32(pdu, 0, &offset, ", n_uname");
-        }
+        pprint_int32(pdu, 0, &offset, ", n_uname");
         break;
     case P9_RATTACH:
         fprintf(llogfile, "RATTACH: (");
@@ -371,9 +423,7 @@ void pprint_pdu(V9fsPDU *pdu)
     case P9_RERROR:
         fprintf(llogfile, "RERROR: (");
         pprint_str(pdu, 1, &offset, "ename");
-        if (dotu) {
-            pprint_int32(pdu, 1, &offset, ", ecode");
-        }
+        pprint_int32(pdu, 1, &offset, ", ecode");
         break;
     case P9_TFLUSH:
         fprintf(llogfile, "TFLUSH: (");
@@ -408,15 +458,58 @@ void pprint_pdu(V9fsPDU *pdu)
         pprint_str(pdu, 0, &offset, ", name");
         pprint_int32(pdu, 0, &offset, ", perm");
         pprint_int8(pdu, 0, &offset, ", mode");
-        if (dotu) {
-            pprint_str(pdu, 0, &offset, ", extension");
-        }
+        pprint_str(pdu, 0, &offset, ", extension");
         break;
     case P9_RCREATE:
         fprintf(llogfile, "RCREATE: (");
         pprint_qid(pdu, 1, &offset, "qid");
         pprint_int32(pdu, 1, &offset, ", iounit");
         break;
+    case P9_TSYMLINK:
+        fprintf(llogfile, "TSYMLINK: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_str(pdu, 0, &offset, ", name");
+        pprint_str(pdu, 0, &offset, ", symname");
+        pprint_int32(pdu, 0, &offset, ", gid");
+        break;
+    case P9_RSYMLINK:
+        fprintf(llogfile, "RSYMLINK: (");
+        pprint_qid(pdu, 1, &offset, "qid");
+        break;
+    case P9_TLCREATE:
+        fprintf(llogfile, "TLCREATE: (");
+        pprint_int32(pdu, 0, &offset, "dfid");
+        pprint_str(pdu, 0, &offset, ", name");
+        pprint_int32(pdu, 0, &offset, ", flags");
+        pprint_int32(pdu, 0, &offset, ", mode");
+        pprint_int32(pdu, 0, &offset, ", gid");
+        break;
+    case P9_RLCREATE:
+        fprintf(llogfile, "RLCREATE: (");
+        pprint_qid(pdu, 1, &offset, "qid");
+        pprint_int32(pdu, 1, &offset, ", iounit");
+        break;
+    case P9_TMKNOD:
+	fprintf(llogfile, "TMKNOD: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_str(pdu, 0, &offset, "name");
+        pprint_int32(pdu, 0, &offset, "mode");
+        pprint_int32(pdu, 0, &offset, "major");
+        pprint_int32(pdu, 0, &offset, "minor");
+        pprint_int32(pdu, 0, &offset, "gid");
+        break;
+    case P9_RMKNOD:
+        fprintf(llogfile, "RMKNOD: )");
+        pprint_qid(pdu, 0, &offset, "qid");
+        break;
+    case P9_TREADLINK:
+	fprintf(llogfile, "TREADLINK: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        break;
+    case P9_RREADLINK:
+	fprintf(llogfile, "RREADLINK: (");
+        pprint_str(pdu, 0, &offset, "target");
+        break;
     case P9_TREAD:
         fprintf(llogfile, "TREAD: (");
         pprint_int32(pdu, 0, &offset, "fid");
@@ -450,6 +543,22 @@ void pprint_pdu(V9fsPDU *pdu)
     case P9_RCLUNK:
         fprintf(llogfile, "RCLUNK: (");
         break;
+    case P9_TFSYNC:
+        fprintf(llogfile, "TFSYNC: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        break;
+    case P9_RFSYNC:
+        fprintf(llogfile, "RFSYNC: (");
+        break;
+    case P9_TLINK:
+        fprintf(llogfile, "TLINK: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_str(pdu, 0, &offset, ", oldpath");
+        pprint_str(pdu, 0, &offset, ", newpath");
+        break;
+    case P9_RLINK:
+        fprintf(llogfile, "RLINK: (");
+        break;
     case P9_TREMOVE:
         fprintf(llogfile, "TREMOVE: (");
         pprint_int32(pdu, 0, &offset, "fid");
@@ -475,6 +584,56 @@ void pprint_pdu(V9fsPDU *pdu)
     case P9_RWSTAT:
         fprintf(llogfile, "RWSTAT: (");
         break;
+    case P9_TXATTRWALK:
+        fprintf(llogfile, "TXATTRWALK: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_int32(pdu, 0, &offset, ", newfid");
+        pprint_str(pdu, 0, &offset, ", xattr name");
+        break;
+    case P9_RXATTRWALK:
+        fprintf(llogfile, "RXATTRWALK: (");
+        pprint_int64(pdu, 1, &offset, "xattrsize");
+    case P9_TXATTRCREATE:
+        fprintf(llogfile, "TXATTRCREATE: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_str(pdu, 0, &offset, ", name");
+        pprint_int64(pdu, 0, &offset, ", xattrsize");
+        pprint_int32(pdu, 0, &offset, ", flags");
+        break;
+    case P9_RXATTRCREATE:
+        fprintf(llogfile, "RXATTRCREATE: (");
+        break;
+    case P9_TLOCK:
+        fprintf(llogfile, "TLOCK: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_int8(pdu, 0, &offset, ", type");
+        pprint_int32(pdu, 0, &offset, ", flags");
+        pprint_int64(pdu, 0, &offset, ", start");
+        pprint_int64(pdu, 0, &offset, ", length");
+        pprint_int32(pdu, 0, &offset, ", proc_id");
+        pprint_str(pdu, 0, &offset, ", client_id");
+        break;
+    case P9_RLOCK:
+        fprintf(llogfile, "RLOCK: (");
+        pprint_int8(pdu, 0, &offset, "status");
+        break;
+    case P9_TGETLOCK:
+        fprintf(llogfile, "TGETLOCK: (");
+        pprint_int32(pdu, 0, &offset, "fid");
+        pprint_int8(pdu, 0, &offset, ", type");
+        pprint_int64(pdu, 0, &offset, ", start");
+        pprint_int64(pdu, 0, &offset, ", length");
+        pprint_int32(pdu, 0, &offset, ", proc_id");
+        pprint_str(pdu, 0, &offset, ", client_id");
+        break;
+    case P9_RGETLOCK:
+        fprintf(llogfile, "RGETLOCK: (");
+        pprint_int8(pdu, 0, &offset, "type");
+        pprint_int64(pdu, 0, &offset, ", start");
+        pprint_int64(pdu, 0, &offset, ", length");
+        pprint_int32(pdu, 0, &offset, ", proc_id");
+        pprint_str(pdu, 0, &offset, ", client_id");
+        break;
     default:
         fprintf(llogfile, "unknown(%d): (", pdu->id);
         break;
diff --git a/hw/virtio-9p-debug.h b/hw/virtio-9p-debug.h
index 0104be5eb3..d9a249118d 100644
--- a/hw/virtio-9p-debug.h
+++ b/hw/virtio-9p-debug.h
@@ -1,7 +1,6 @@
 #ifndef _QEMU_VIRTIO_9P_DEBUG_H
 #define _QEMU_VIRTIO_9P_DEBUG_H
 
-extern int dotu;
 void pprint_pdu(V9fsPDU *pdu);
 
 #endif
diff --git a/hw/virtio-9p-local.c b/hw/virtio-9p-local.c
index 04f7f6f501..0d520201b4 100644
--- a/hw/virtio-9p-local.c
+++ b/hw/virtio-9p-local.c
@@ -12,6 +12,7 @@
  */
 #include "virtio.h"
 #include "virtio-9p.h"
+#include "virtio-9p-xattr.h"
 #include <arpa/inet.h>
 #include <pwd.h>
 #include <grp.h>
@@ -19,14 +20,6 @@
 #include <sys/un.h>
 #include <attr/xattr.h>
 
-static const char *rpath(FsContext *ctx, const char *path)
-{
-    /* FIXME: so wrong... */
-    static char buffer[4096];
-    snprintf(buffer, sizeof(buffer), "%s/%s", ctx->fs_root, path);
-    return buffer;
-}
-
 
 static int local_lstat(FsContext *fs_ctx, const char *path, struct stat *stbuf)
 {
@@ -101,8 +94,14 @@ static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
     if (chmod(rpath(fs_ctx, path), credp->fc_mode & 07777) < 0) {
         return -1;
     }
-    if (chown(rpath(fs_ctx, path), credp->fc_uid, credp->fc_gid) < 0) {
-        return -1;
+    if (lchown(rpath(fs_ctx, path), credp->fc_uid, credp->fc_gid) < 0) {
+        /*
+         * If we fail to change ownership and if we are
+         * using security model none. Ignore the error
+         */
+        if (fs_ctx->fs_sm != SM_NONE) {
+            return -1;
+        }
     }
     return 0;
 }
@@ -122,7 +121,8 @@ static ssize_t local_readlink(FsContext *fs_ctx, const char *path,
         } while (tsize == -1 && errno == EINTR);
         close(fd);
         return tsize;
-    } else if (fs_ctx->fs_sm == SM_PASSTHROUGH) {
+    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
+               (fs_ctx->fs_sm == SM_NONE)) {
         tsize = readlink(rpath(fs_ctx, path), buf, bufsz);
     }
     return tsize;
@@ -168,28 +168,42 @@ static void local_seekdir(FsContext *ctx, DIR *dir, off_t off)
     return seekdir(dir, off);
 }
 
-static ssize_t local_readv(FsContext *ctx, int fd, const struct iovec *iov,
-                            int iovcnt)
+static ssize_t local_preadv(FsContext *ctx, int fd, const struct iovec *iov,
+                            int iovcnt, off_t offset)
 {
-    return readv(fd, iov, iovcnt);
-}
-
-static off_t local_lseek(FsContext *ctx, int fd, off_t offset, int whence)
-{
-    return lseek(fd, offset, whence);
+#ifdef CONFIG_PREADV
+    return preadv(fd, iov, iovcnt, offset);
+#else
+    int err = lseek(fd, offset, SEEK_SET);
+    if (err == -1) {
+        return err;
+    } else {
+        return readv(fd, iov, iovcnt);
+    }
+#endif
 }
 
-static ssize_t local_writev(FsContext *ctx, int fd, const struct iovec *iov,
-                            int iovcnt)
+static ssize_t local_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
+                            int iovcnt, off_t offset)
 {
-    return writev(fd, iov, iovcnt);
+#ifdef CONFIG_PREADV
+    return pwritev(fd, iov, iovcnt, offset);
+#else
+    int err = lseek(fd, offset, SEEK_SET);
+    if (err == -1) {
+        return err;
+    } else {
+        return writev(fd, iov, iovcnt);
+    }
+#endif
 }
 
 static int local_chmod(FsContext *fs_ctx, const char *path, FsCred *credp)
 {
     if (fs_ctx->fs_sm == SM_MAPPED) {
         return local_set_xattr(rpath(fs_ctx, path), credp);
-    } else if (fs_ctx->fs_sm == SM_PASSTHROUGH) {
+    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
+               (fs_ctx->fs_sm == SM_NONE)) {
         return chmod(rpath(fs_ctx, path), credp->fc_mode);
     }
     return -1;
@@ -211,7 +225,8 @@ static int local_mknod(FsContext *fs_ctx, const char *path, FsCred *credp)
             serrno = errno;
             goto err_end;
         }
-    } else if (fs_ctx->fs_sm == SM_PASSTHROUGH) {
+    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
+               (fs_ctx->fs_sm == SM_NONE)) {
         err = mknod(rpath(fs_ctx, path), credp->fc_mode, credp->fc_rdev);
         if (err == -1) {
             return err;
@@ -247,7 +262,8 @@ static int local_mkdir(FsContext *fs_ctx, const char *path, FsCred *credp)
             serrno = errno;
             goto err_end;
         }
-    } else if (fs_ctx->fs_sm == SM_PASSTHROUGH) {
+    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
+               (fs_ctx->fs_sm == SM_NONE)) {
         err = mkdir(rpath(fs_ctx, path), credp->fc_mode);
         if (err == -1) {
             return err;
@@ -316,7 +332,8 @@ static int local_open2(FsContext *fs_ctx, const char *path, int flags,
             serrno = errno;
             goto err_end;
         }
-    } else if (fs_ctx->fs_sm == SM_PASSTHROUGH) {
+    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
+               (fs_ctx->fs_sm == SM_NONE)) {
         fd = open(rpath(fs_ctx, path), flags, credp->fc_mode);
         if (fd == -1) {
             return fd;
@@ -372,15 +389,23 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
             serrno = errno;
             goto err_end;
         }
-    } else if (fs_ctx->fs_sm == SM_PASSTHROUGH) {
+    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
+               (fs_ctx->fs_sm == SM_NONE)) {
         err = symlink(oldpath, rpath(fs_ctx, newpath));
         if (err) {
             return err;
         }
         err = lchown(rpath(fs_ctx, newpath), credp->fc_uid, credp->fc_gid);
         if (err == -1) {
-            serrno = errno;
-            goto err_end;
+            /*
+             * If we fail to change ownership and if we are
+             * using security model none. Ignore the error
+             */
+            if (fs_ctx->fs_sm != SM_NONE) {
+                serrno = errno;
+                goto err_end;
+            } else
+                err = 0;
         }
     }
     return err;
@@ -426,9 +451,6 @@ static int local_rename(FsContext *ctx, const char *oldpath,
     int err;
 
     tmp = qemu_strdup(rpath(ctx, oldpath));
-    if (tmp == NULL) {
-        return -1;
-    }
 
     err = rename(tmp, rpath(ctx, newpath));
     if (err == -1) {
@@ -445,18 +467,22 @@ static int local_rename(FsContext *ctx, const char *oldpath,
 
 static int local_chown(FsContext *fs_ctx, const char *path, FsCred *credp)
 {
-    if (fs_ctx->fs_sm == SM_MAPPED) {
+    if ((credp->fc_uid == -1 && credp->fc_gid == -1) ||
+            (fs_ctx->fs_sm == SM_PASSTHROUGH)) {
+        return lchown(rpath(fs_ctx, path), credp->fc_uid, credp->fc_gid);
+    } else if (fs_ctx->fs_sm == SM_MAPPED) {
         return local_set_xattr(rpath(fs_ctx, path), credp);
-    } else if (fs_ctx->fs_sm == SM_PASSTHROUGH) {
+    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
+               (fs_ctx->fs_sm == SM_NONE)) {
         return lchown(rpath(fs_ctx, path), credp->fc_uid, credp->fc_gid);
     }
     return -1;
 }
 
-static int local_utime(FsContext *ctx, const char *path,
-                        const struct utimbuf *buf)
+static int local_utimensat(FsContext *s, const char *path,
+		       const struct timespec *buf)
 {
-    return utime(rpath(ctx, path), buf);
+    return utimensat(AT_FDCWD, rpath(s, path), buf, AT_SYMLINK_NOFOLLOW);
 }
 
 static int local_remove(FsContext *ctx, const char *path)
@@ -469,6 +495,36 @@ static int local_fsync(FsContext *ctx, int fd)
     return fsync(fd);
 }
 
+static int local_statfs(FsContext *s, const char *path, struct statfs *stbuf)
+{
+   return statfs(rpath(s, path), stbuf);
+}
+
+static ssize_t local_lgetxattr(FsContext *ctx, const char *path,
+                               const char *name, void *value, size_t size)
+{
+    return v9fs_get_xattr(ctx, path, name, value, size);
+}
+
+static ssize_t local_llistxattr(FsContext *ctx, const char *path,
+                                void *value, size_t size)
+{
+    return v9fs_list_xattr(ctx, path, value, size);
+}
+
+static int local_lsetxattr(FsContext *ctx, const char *path, const char *name,
+                           void *value, size_t size, int flags)
+{
+    return v9fs_set_xattr(ctx, path, name, value, size, flags);
+}
+
+static int local_lremovexattr(FsContext *ctx,
+                              const char *path, const char *name)
+{
+    return v9fs_remove_xattr(ctx, path, name);
+}
+
+
 FileOperations local_ops = {
     .lstat = local_lstat,
     .readlink = local_readlink,
@@ -480,9 +536,8 @@ FileOperations local_ops = {
     .telldir = local_telldir,
     .readdir = local_readdir,
     .seekdir = local_seekdir,
-    .readv = local_readv,
-    .lseek = local_lseek,
-    .writev = local_writev,
+    .preadv = local_preadv,
+    .pwritev = local_pwritev,
     .chmod = local_chmod,
     .mknod = local_mknod,
     .mkdir = local_mkdir,
@@ -493,7 +548,12 @@ FileOperations local_ops = {
     .truncate = local_truncate,
     .rename = local_rename,
     .chown = local_chown,
-    .utime = local_utime,
+    .utimensat = local_utimensat,
     .remove = local_remove,
     .fsync = local_fsync,
+    .statfs = local_statfs,
+    .lgetxattr = local_lgetxattr,
+    .llistxattr = local_llistxattr,
+    .lsetxattr = local_lsetxattr,
+    .lremovexattr = local_lremovexattr,
 };
diff --git a/hw/virtio-9p-posix-acl.c b/hw/virtio-9p-posix-acl.c
new file mode 100644
index 0000000000..3978d0cf71
--- /dev/null
+++ b/hw/virtio-9p-posix-acl.c
@@ -0,0 +1,140 @@
+/*
+ * Virtio 9p system.posix* xattr callback
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include <sys/types.h>
+#include <attr/xattr.h>
+#include "virtio.h"
+#include "virtio-9p.h"
+#include "file-op-9p.h"
+#include "virtio-9p-xattr.h"
+
+#define MAP_ACL_ACCESS "user.virtfs.system.posix_acl_access"
+#define MAP_ACL_DEFAULT "user.virtfs.system.posix_acl_default"
+#define ACL_ACCESS "system.posix_acl_access"
+#define ACL_DEFAULT "system.posix_acl_default"
+
+static ssize_t mp_pacl_getxattr(FsContext *ctx, const char *path,
+                                const char *name, void *value, size_t size)
+{
+    return lgetxattr(rpath(ctx, path), MAP_ACL_ACCESS, value, size);
+}
+
+static ssize_t mp_pacl_listxattr(FsContext *ctx, const char *path,
+                                 char *name, void *value, size_t osize)
+{
+    ssize_t len = sizeof(ACL_ACCESS);
+
+    if (!value) {
+        return len;
+    }
+
+    if (osize < len) {
+        errno = ERANGE;
+        return -1;
+    }
+
+    strncpy(value, ACL_ACCESS, len);
+    return 0;
+}
+
+static int mp_pacl_setxattr(FsContext *ctx, const char *path, const char *name,
+                            void *value, size_t size, int flags)
+{
+    return lsetxattr(rpath(ctx, path), MAP_ACL_ACCESS, value, size, flags);
+}
+
+static int mp_pacl_removexattr(FsContext *ctx,
+                               const char *path, const char *name)
+{
+    int ret;
+    ret  = lremovexattr(rpath(ctx, path), MAP_ACL_ACCESS);
+    if (ret == -1 && errno == ENODATA) {
+        /*
+         * We don't get ENODATA error when trying to remote a
+         * posix acl that is not present. So don't throw the error
+         * even in case of mapped security model
+         */
+        errno = 0;
+        ret = 0;
+    }
+    return ret;
+}
+
+static ssize_t mp_dacl_getxattr(FsContext *ctx, const char *path,
+                                const char *name, void *value, size_t size)
+{
+    return lgetxattr(rpath(ctx, path), MAP_ACL_DEFAULT, value, size);
+}
+
+static ssize_t mp_dacl_listxattr(FsContext *ctx, const char *path,
+                                 char *name, void *value, size_t osize)
+{
+    ssize_t len = sizeof(ACL_DEFAULT);
+
+    if (!value) {
+        return len;
+    }
+
+    if (osize < len) {
+        errno = ERANGE;
+        return -1;
+    }
+
+    strncpy(value, ACL_DEFAULT, len);
+    return 0;
+}
+
+static int mp_dacl_setxattr(FsContext *ctx, const char *path, const char *name,
+                            void *value, size_t size, int flags)
+{
+    return lsetxattr(rpath(ctx, path), MAP_ACL_DEFAULT, value, size, flags);
+}
+
+static int mp_dacl_removexattr(FsContext *ctx,
+                               const char *path, const char *name)
+{
+    return lremovexattr(rpath(ctx, path), MAP_ACL_DEFAULT);
+}
+
+
+XattrOperations mapped_pacl_xattr = {
+    .name = "system.posix_acl_access",
+    .getxattr = mp_pacl_getxattr,
+    .setxattr = mp_pacl_setxattr,
+    .listxattr = mp_pacl_listxattr,
+    .removexattr = mp_pacl_removexattr,
+};
+
+XattrOperations mapped_dacl_xattr = {
+    .name = "system.posix_acl_default",
+    .getxattr = mp_dacl_getxattr,
+    .setxattr = mp_dacl_setxattr,
+    .listxattr = mp_dacl_listxattr,
+    .removexattr = mp_dacl_removexattr,
+};
+
+XattrOperations passthrough_acl_xattr = {
+    .name = "system.posix_acl_",
+    .getxattr = pt_getxattr,
+    .setxattr = pt_setxattr,
+    .listxattr = pt_listxattr,
+    .removexattr = pt_removexattr,
+};
+
+XattrOperations none_acl_xattr = {
+    .name = "system.posix_acl_",
+    .getxattr = notsup_getxattr,
+    .setxattr = notsup_setxattr,
+    .listxattr = notsup_listxattr,
+    .removexattr = notsup_removexattr,
+};
diff --git a/hw/virtio-9p-xattr-user.c b/hw/virtio-9p-xattr-user.c
new file mode 100644
index 0000000000..faa02a1911
--- /dev/null
+++ b/hw/virtio-9p-xattr-user.c
@@ -0,0 +1,109 @@
+/*
+ * Virtio 9p user. xattr callback
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include <sys/types.h>
+#include "virtio.h"
+#include "virtio-9p.h"
+#include "file-op-9p.h"
+#include "virtio-9p-xattr.h"
+
+
+static ssize_t mp_user_getxattr(FsContext *ctx, const char *path,
+                                const char *name, void *value, size_t size)
+{
+    if (strncmp(name, "user.virtfs.", 12) == 0) {
+        /*
+         * Don't allow fetch of user.virtfs namesapce
+         * in case of mapped security
+         */
+        errno = ENOATTR;
+        return -1;
+    }
+    return lgetxattr(rpath(ctx, path), name, value, size);
+}
+
+static ssize_t mp_user_listxattr(FsContext *ctx, const char *path,
+                                 char *name, void *value, size_t size)
+{
+    int name_size = strlen(name) + 1;
+    if (strncmp(name, "user.virtfs.", 12) == 0) {
+
+        /*  check if it is a mapped posix acl */
+        if (strncmp(name, "user.virtfs.system.posix_acl_", 29) == 0) {
+            /* adjust the name and size */
+            name += 12;
+            name_size -= 12;
+        } else {
+            /*
+             * Don't allow fetch of user.virtfs namesapce
+             * in case of mapped security
+             */
+            return 0;
+        }
+    }
+    if (!value) {
+        return name_size;
+    }
+
+    if (size < name_size) {
+        errno = ERANGE;
+        return -1;
+    }
+
+    strncpy(value, name, name_size);
+    return name_size;
+}
+
+static int mp_user_setxattr(FsContext *ctx, const char *path, const char *name,
+                            void *value, size_t size, int flags)
+{
+    if (strncmp(name, "user.virtfs.", 12) == 0) {
+        /*
+         * Don't allow fetch of user.virtfs namesapce
+         * in case of mapped security
+         */
+        errno = EACCES;
+        return -1;
+    }
+    return lsetxattr(rpath(ctx, path), name, value, size, flags);
+}
+
+static int mp_user_removexattr(FsContext *ctx,
+                               const char *path, const char *name)
+{
+    if (strncmp(name, "user.virtfs.", 12) == 0) {
+        /*
+         * Don't allow fetch of user.virtfs namesapce
+         * in case of mapped security
+         */
+        errno = EACCES;
+        return -1;
+    }
+    return lremovexattr(rpath(ctx, path), name);
+}
+
+XattrOperations mapped_user_xattr = {
+    .name = "user.",
+    .getxattr = mp_user_getxattr,
+    .setxattr = mp_user_setxattr,
+    .listxattr = mp_user_listxattr,
+    .removexattr = mp_user_removexattr,
+};
+
+XattrOperations passthrough_user_xattr = {
+    .name = "user.",
+    .getxattr = pt_getxattr,
+    .setxattr = pt_setxattr,
+    .listxattr = pt_listxattr,
+    .removexattr = pt_removexattr,
+};
diff --git a/hw/virtio-9p-xattr.c b/hw/virtio-9p-xattr.c
new file mode 100644
index 0000000000..175f372c39
--- /dev/null
+++ b/hw/virtio-9p-xattr.c
@@ -0,0 +1,156 @@
+/*
+ * Virtio 9p  xattr callback
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "virtio.h"
+#include "virtio-9p.h"
+#include "file-op-9p.h"
+#include "virtio-9p-xattr.h"
+
+
+static XattrOperations *get_xattr_operations(XattrOperations **h,
+                                             const char *name)
+{
+    XattrOperations *xops;
+    for (xops = *(h)++; xops != NULL; xops = *(h)++) {
+        if (!strncmp(name, xops->name, strlen(xops->name))) {
+            return xops;
+        }
+    }
+    return NULL;
+}
+
+ssize_t v9fs_get_xattr(FsContext *ctx, const char *path,
+                       const char *name, void *value, size_t size)
+{
+    XattrOperations *xops = get_xattr_operations(ctx->xops, name);
+    if (xops) {
+        return xops->getxattr(ctx, path, name, value, size);
+    }
+    errno = -EOPNOTSUPP;
+    return -1;
+}
+
+ssize_t pt_listxattr(FsContext *ctx, const char *path,
+                     char *name, void *value, size_t size)
+{
+    int name_size = strlen(name) + 1;
+    if (!value) {
+        return name_size;
+    }
+
+    if (size < name_size) {
+        errno = ERANGE;
+        return -1;
+    }
+
+    strncpy(value, name, name_size);
+    return name_size;
+}
+
+
+/*
+ * Get the list and pass to each layer to find out whether
+ * to send the data or not
+ */
+ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
+                        void *value, size_t vsize)
+{
+    ssize_t size = 0;
+    void *ovalue = value;
+    XattrOperations *xops;
+    char *orig_value, *orig_value_start;
+    ssize_t xattr_len, parsed_len = 0, attr_len;
+
+    /* Get the actual len */
+    xattr_len = llistxattr(rpath(ctx, path), value, 0);
+
+    /* Now fetch the xattr and find the actual size */
+    orig_value = qemu_malloc(xattr_len);
+    xattr_len = llistxattr(rpath(ctx, path), orig_value, xattr_len);
+
+    /* store the orig pointer */
+    orig_value_start = orig_value;
+    while (xattr_len > parsed_len) {
+        xops = get_xattr_operations(ctx->xops, orig_value);
+        if (!xops) {
+            goto next_entry;
+        }
+
+        if (!value) {
+            size += xops->listxattr(ctx, path, orig_value, value, vsize);
+        } else {
+            size = xops->listxattr(ctx, path, orig_value, value, vsize);
+            if (size < 0) {
+                goto err_out;
+            }
+            value += size;
+            vsize -= size;
+        }
+next_entry:
+        /* Got the next entry */
+        attr_len = strlen(orig_value) + 1;
+        parsed_len += attr_len;
+        orig_value += attr_len;
+    }
+    if (value) {
+        size = value - ovalue;
+    }
+
+err_out:
+    qemu_free(orig_value_start);
+    return size;
+}
+
+int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name,
+                   void *value, size_t size, int flags)
+{
+    XattrOperations *xops = get_xattr_operations(ctx->xops, name);
+    if (xops) {
+        return xops->setxattr(ctx, path, name, value, size, flags);
+    }
+    errno = -EOPNOTSUPP;
+    return -1;
+
+}
+
+int v9fs_remove_xattr(FsContext *ctx,
+                      const char *path, const char *name)
+{
+    XattrOperations *xops = get_xattr_operations(ctx->xops, name);
+    if (xops) {
+        return xops->removexattr(ctx, path, name);
+    }
+    errno = -EOPNOTSUPP;
+    return -1;
+
+}
+
+XattrOperations *mapped_xattr_ops[] = {
+    &mapped_user_xattr,
+    &mapped_pacl_xattr,
+    &mapped_dacl_xattr,
+    NULL,
+};
+
+XattrOperations *passthrough_xattr_ops[] = {
+    &passthrough_user_xattr,
+    &passthrough_acl_xattr,
+    NULL,
+};
+
+/* for .user none model should be same as passthrough */
+XattrOperations *none_xattr_ops[] = {
+    &passthrough_user_xattr,
+    &none_acl_xattr,
+    NULL,
+};
diff --git a/hw/virtio-9p-xattr.h b/hw/virtio-9p-xattr.h
new file mode 100644
index 0000000000..a6e31a152f
--- /dev/null
+++ b/hw/virtio-9p-xattr.h
@@ -0,0 +1,103 @@
+/*
+ * Virtio 9p
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#ifndef _QEMU_VIRTIO_9P_XATTR_H
+#define _QEMU_VIRTIO_9P_XATTR_H
+
+#include <attr/xattr.h>
+
+typedef struct xattr_operations
+{
+    const char *name;
+    ssize_t (*getxattr)(FsContext *ctx, const char *path,
+                        const char *name, void *value, size_t size);
+    ssize_t (*listxattr)(FsContext *ctx, const char *path,
+                         char *name, void *value, size_t size);
+    int (*setxattr)(FsContext *ctx, const char *path, const char *name,
+                    void *value, size_t size, int flags);
+    int (*removexattr)(FsContext *ctx,
+                       const char *path, const char *name);
+} XattrOperations;
+
+
+extern XattrOperations mapped_user_xattr;
+extern XattrOperations passthrough_user_xattr;
+
+extern XattrOperations mapped_pacl_xattr;
+extern XattrOperations mapped_dacl_xattr;
+extern XattrOperations passthrough_acl_xattr;
+extern XattrOperations none_acl_xattr;
+
+extern XattrOperations *mapped_xattr_ops[];
+extern XattrOperations *passthrough_xattr_ops[];
+extern XattrOperations *none_xattr_ops[];
+
+extern ssize_t v9fs_get_xattr(FsContext *ctx, const char *path,
+                              const char *name, void *value, size_t size);
+extern ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
+                               void *value, size_t vsize);
+extern int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name,
+                          void *value, size_t size, int flags);
+extern int v9fs_remove_xattr(FsContext *ctx,
+                             const char *path, const char *name);
+extern ssize_t pt_listxattr(FsContext *ctx, const char *path,
+                            char *name, void *value, size_t size);
+
+static inline ssize_t pt_getxattr(FsContext *ctx, const char *path,
+                                  const char *name, void *value, size_t size)
+{
+    return lgetxattr(rpath(ctx, path), name, value, size);
+}
+
+static inline int pt_setxattr(FsContext *ctx, const char *path,
+                              const char *name, void *value,
+                              size_t size, int flags)
+{
+    return lsetxattr(rpath(ctx, path), name, value, size, flags);
+}
+
+static inline int pt_removexattr(FsContext *ctx,
+                                 const char *path, const char *name)
+{
+    return lremovexattr(rpath(ctx, path), name);
+}
+
+static inline ssize_t notsup_getxattr(FsContext *ctx, const char *path,
+                                      const char *name, void *value,
+                                      size_t size)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+static inline int notsup_setxattr(FsContext *ctx, const char *path,
+                                  const char *name, void *value,
+                                  size_t size, int flags)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+static inline ssize_t notsup_listxattr(FsContext *ctx, const char *path,
+                                       char *name, void *value, size_t size)
+{
+    return 0;
+}
+
+static inline int notsup_removexattr(FsContext *ctx,
+                                     const char *path, const char *name)
+{
+    errno = ENOTSUP;
+    return -1;
+}
+
+#endif
diff --git a/hw/virtio-9p.c b/hw/virtio-9p.c
index f8c85c3d28..daade77ed9 100644
--- a/hw/virtio-9p.c
+++ b/hw/virtio-9p.c
@@ -17,8 +17,8 @@
 #include "virtio-9p.h"
 #include "fsdev/qemu-fsdev.h"
 #include "virtio-9p-debug.h"
+#include "virtio-9p-xattr.h"
 
-int dotu = 1;
 int debug_9p_pdu;
 
 enum {
@@ -135,21 +135,16 @@ static void v9fs_do_seekdir(V9fsState *s, DIR *dir, off_t off)
     return s->ops->seekdir(&s->ctx, dir, off);
 }
 
-static int v9fs_do_readv(V9fsState *s, int fd, const struct iovec *iov,
-                            int iovcnt)
+static int v9fs_do_preadv(V9fsState *s, int fd, const struct iovec *iov,
+                            int iovcnt, int64_t offset)
 {
-    return s->ops->readv(&s->ctx, fd, iov, iovcnt);
+    return s->ops->preadv(&s->ctx, fd, iov, iovcnt, offset);
 }
 
-static off_t v9fs_do_lseek(V9fsState *s, int fd, off_t offset, int whence)
+static int v9fs_do_pwritev(V9fsState *s, int fd, const struct iovec *iov,
+                       int iovcnt, int64_t offset)
 {
-    return s->ops->lseek(&s->ctx, fd, offset, whence);
-}
-
-static int v9fs_do_writev(V9fsState *s, int fd, const struct iovec *iov,
-                       int iovcnt)
-{
-    return s->ops->writev(&s->ctx, fd, iov, iovcnt);
+    return s->ops->pwritev(&s->ctx, fd, iov, iovcnt, offset);
 }
 
 static int v9fs_do_chmod(V9fsState *s, V9fsString *path, mode_t mode)
@@ -160,26 +155,29 @@ static int v9fs_do_chmod(V9fsState *s, V9fsString *path, mode_t mode)
     return s->ops->chmod(&s->ctx, path->data, &cred);
 }
 
-static int v9fs_do_mknod(V9fsState *s, V9fsCreateState *vs, mode_t mode,
-        dev_t dev)
+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 = vs->fidp->uid;
+    cred.fc_uid = uid;
+    cred.fc_gid = gid;
     cred.fc_mode = mode;
     cred.fc_rdev = dev;
-    return s->ops->mknod(&s->ctx, vs->fullname.data, &cred);
+    return s->ops->mknod(&s->ctx, name, &cred);
 }
 
-static int v9fs_do_mkdir(V9fsState *s, V9fsCreateState *vs)
+static int v9fs_do_mkdir(V9fsState *s, char *name, mode_t mode,
+                uid_t uid, gid_t gid)
 {
     FsCred cred;
 
     cred_init(&cred);
-    cred.fc_uid = vs->fidp->uid;
-    cred.fc_mode = vs->perm & 0777;
+    cred.fc_uid = uid;
+    cred.fc_gid = gid;
+    cred.fc_mode = mode;
 
-    return s->ops->mkdir(&s->ctx, vs->fullname.data, &cred);
+    return s->ops->mkdir(&s->ctx, name, &cred);
 }
 
 static int v9fs_do_fstat(V9fsState *s, int fd, struct stat *stbuf)
@@ -187,28 +185,30 @@ 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, V9fsCreateState *vs)
+static int v9fs_do_open2(V9fsState *s, char *fullname, uid_t uid, gid_t gid,
+        int flags, int mode)
 {
     FsCred cred;
-    int flags;
 
     cred_init(&cred);
-    cred.fc_uid = vs->fidp->uid;
-    cred.fc_mode = vs->perm & 0777;
-    flags = omode_to_uflags(vs->mode) | O_CREAT;
+    cred.fc_uid = uid;
+    cred.fc_gid = gid;
+    cred.fc_mode = mode & 07777;
+    flags = flags;
 
-    return s->ops->open2(&s->ctx, vs->fullname.data, flags, &cred);
+    return s->ops->open2(&s->ctx, fullname, flags, &cred);
 }
 
-static int v9fs_do_symlink(V9fsState *s, V9fsCreateState *vs)
+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 = vs->fidp->uid;
-    cred.fc_mode = vs->perm | 0777;
+    cred.fc_uid = fidp->uid;
+    cred.fc_gid = gid;
+    cred.fc_mode = 0777;
 
-    return s->ops->symlink(&s->ctx, vs->extension.data, vs->fullname.data,
-            &cred);
+    return s->ops->symlink(&s->ctx, oldpath, newpath, &cred);
 }
 
 static int v9fs_do_link(V9fsState *s, V9fsString *oldpath, V9fsString *newpath)
@@ -237,10 +237,10 @@ static int v9fs_do_chown(V9fsState *s, V9fsString *path, uid_t uid, gid_t gid)
     return s->ops->chown(&s->ctx, path->data, &cred);
 }
 
-static int v9fs_do_utime(V9fsState *s, V9fsString *path,
-                            const struct utimbuf *buf)
+static int v9fs_do_utimensat(V9fsState *s, V9fsString *path,
+                                           const struct timespec times[2])
 {
-    return s->ops->utime(&s->ctx, path->data, buf);
+    return s->ops->utimensat(&s->ctx, path->data, times);
 }
 
 static int v9fs_do_remove(V9fsState *s, V9fsString *path)
@@ -253,6 +253,42 @@ static int v9fs_do_fsync(V9fsState *s, int fd)
     return s->ops->fsync(&s->ctx, fd);
 }
 
+static int v9fs_do_statfs(V9fsState *s, V9fsString *path, struct statfs *stbuf)
+{
+    return s->ops->statfs(&s->ctx, path->data, stbuf);
+}
+
+static ssize_t v9fs_do_lgetxattr(V9fsState *s, V9fsString *path,
+                             V9fsString *xattr_name,
+                             void *value, size_t size)
+{
+    return s->ops->lgetxattr(&s->ctx, path->data,
+                             xattr_name->data, value, size);
+}
+
+static ssize_t v9fs_do_llistxattr(V9fsState *s, V9fsString *path,
+                              void *value, size_t size)
+{
+    return s->ops->llistxattr(&s->ctx, path->data,
+                              value, size);
+}
+
+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;
@@ -285,6 +321,14 @@ static int number_to_string(void *arg, char type)
         } while (num);
         break;
     }
+    case 'U': {
+        unsigned long num = *(unsigned long *)arg;
+        do {
+            ret++;
+            num = num/10;
+        } while (num);
+        break;
+    }
     default:
         printf("Number_to_string: Unknown number format\n");
         return -1;
@@ -293,7 +337,8 @@ static int number_to_string(void *arg, char type)
     return ret;
 }
 
-static int v9fs_string_alloc_printf(char **strp, const char *fmt, va_list ap)
+static int GCC_FMT_ATTR(2, 0)
+v9fs_string_alloc_printf(char **strp, const char *fmt, va_list ap)
 {
     va_list ap2;
     char *iter = (char *)fmt;
@@ -301,6 +346,7 @@ static int v9fs_string_alloc_printf(char **strp, const char *fmt, va_list ap)
     int nr_args = 0;
     char *arg_char_ptr;
     unsigned int arg_uint;
+    unsigned long arg_ulong;
 
     /* Find the number of %'s that denotes an argument */
     for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) {
@@ -326,6 +372,14 @@ static int v9fs_string_alloc_printf(char **strp, const char *fmt, va_list ap)
             arg_uint = va_arg(ap2, unsigned int);
             len += number_to_string((void *)&arg_uint, 'u');
             break;
+        case 'l':
+            if (*++iter == 'u') {
+                arg_ulong = va_arg(ap2, unsigned long);
+                len += number_to_string((void *)&arg_ulong, 'U');
+            } else {
+                return -1;
+            }
+            break;
         case 's':
             arg_char_ptr = va_arg(ap2, char *);
             len += strlen(arg_char_ptr);
@@ -347,7 +401,8 @@ alloc_print:
     return vsprintf(*strp, fmt, ap);
 }
 
-static void v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
+static void GCC_FMT_ATTR(2, 3)
+v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
 {
     va_list ap;
     int err;
@@ -398,8 +453,7 @@ static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
     f = qemu_mallocz(sizeof(V9fsFidState));
 
     f->fid = fid;
-    f->fd = -1;
-    f->dir = NULL;
+    f->fid_type = P9_FID_NONE;
 
     f->next = s->fid_list;
     s->fid_list = f;
@@ -407,8 +461,43 @@ static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
     return f;
 }
 
+static int v9fs_xattr_fid_clunk(V9fsState *s, V9fsFidState *fidp)
+{
+    int retval = 0;
+
+    if (fidp->fs.xattr.copied_len == -1) {
+        /* getxattr/listxattr fid */
+        goto free_value;
+    }
+    /*
+     * if this is fid for setxattr. clunk should
+     * result in setxattr localcall
+     */
+    if (fidp->fs.xattr.len != fidp->fs.xattr.copied_len) {
+        /* clunk after partial write */
+        retval = -EINVAL;
+        goto free_out;
+    }
+    if (fidp->fs.xattr.len) {
+        retval = v9fs_do_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);
+    }
+free_out:
+    v9fs_string_free(&fidp->fs.xattr.name);
+free_value:
+    if (fidp->fs.xattr.value) {
+        qemu_free(fidp->fs.xattr.value);
+    }
+    return retval;
+}
+
 static int free_fid(V9fsState *s, int32_t fid)
 {
+    int retval = 0;
     V9fsFidState **fidpp, *fidp;
 
     for (fidpp = &s->fid_list; *fidpp; fidpp = &(*fidpp)->next) {
@@ -424,16 +513,17 @@ static int free_fid(V9fsState *s, int32_t fid)
     fidp = *fidpp;
     *fidpp = fidp->next;
 
-    if (fidp->fd != -1) {
-        v9fs_do_close(s, fidp->fd);
-    }
-    if (fidp->dir) {
-        v9fs_do_closedir(s, fidp->dir);
+    if (fidp->fid_type == P9_FID_FILE) {
+        v9fs_do_close(s, fidp->fs.fd);
+    } else if (fidp->fid_type == P9_FID_DIR) {
+        v9fs_do_closedir(s, fidp->fs.dir);
+    } else if (fidp->fid_type == P9_FID_XATTR) {
+        retval = v9fs_xattr_fid_clunk(s, fidp);
     }
     v9fs_string_free(&fidp->path);
     qemu_free(fidp);
 
-    return 0;
+    return retval;
 }
 
 #define P9_QID_TYPE_DIR         0x80
@@ -660,6 +750,15 @@ static size_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
                         &statp->n_muid);
             break;
         }
+        case 'I': {
+            V9fsIattr *iattr = va_arg(ap, V9fsIattr *);
+            offset += pdu_unmarshal(pdu, offset, "ddddqqqqq",
+                        &iattr->valid, &iattr->mode,
+                        &iattr->uid, &iattr->gid, &iattr->size,
+                        &iattr->atime_sec, &iattr->atime_nsec,
+                        &iattr->mtime_sec, &iattr->mtime_nsec);
+            break;
+        }
         default:
             break;
         }
@@ -731,6 +830,21 @@ static size_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
                         statp->n_gid, statp->n_muid);
             break;
         }
+        case 'A': {
+            V9fsStatDotl *statp = va_arg(ap, V9fsStatDotl *);
+            offset += pdu_marshal(pdu, offset, "qQdddqqqqqqqqqqqqqqq",
+                        statp->st_result_mask,
+                        &statp->qid, statp->st_mode,
+                        statp->st_uid, statp->st_gid,
+                        statp->st_nlink, statp->st_rdev,
+                        statp->st_size, statp->st_blksize, statp->st_blocks,
+                        statp->st_atime_sec, statp->st_atime_nsec,
+                        statp->st_mtime_sec, statp->st_mtime_nsec,
+                        statp->st_ctime_sec, statp->st_ctime_nsec,
+                        statp->st_btime_sec, statp->st_btime_nsec,
+                        statp->st_gen, statp->st_data_version);
+            break;
+        }
         default:
             break;
         }
@@ -745,19 +859,24 @@ static void complete_pdu(V9fsState *s, V9fsPDU *pdu, ssize_t len)
     int8_t id = pdu->id + 1; /* Response */
 
     if (len < 0) {
-        V9fsString str;
         int err = -len;
+        len = 7;
 
-        str.data = strerror(err);
-        str.size = strlen(str.data);
+        if (s->proto_version != V9FS_PROTO_2000L) {
+            V9fsString str;
 
-        len = 7;
-        len += pdu_marshal(pdu, len, "s", &str);
-        if (dotu) {
-            len += pdu_marshal(pdu, len, "d", err);
+            str.data = strerror(err);
+            str.size = strlen(str.data);
+
+            len += pdu_marshal(pdu, len, "s", &str);
+            id = P9_RERROR;
         }
 
-        id = P9_RERROR;
+        len += pdu_marshal(pdu, len, "d", err);
+
+        if (s->proto_version == V9FS_PROTO_2000L) {
+            id = P9_RLERROR;
+        }
     }
 
     /* fill out the header */
@@ -785,22 +904,20 @@ static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension)
         ret |= S_IFDIR;
     }
 
-    if (dotu) {
-        if (mode & P9_STAT_MODE_SYMLINK) {
-            ret |= S_IFLNK;
-        }
-        if (mode & P9_STAT_MODE_SOCKET) {
-            ret |= S_IFSOCK;
-        }
-        if (mode & P9_STAT_MODE_NAMED_PIPE) {
-            ret |= S_IFIFO;
-        }
-        if (mode & P9_STAT_MODE_DEVICE) {
-            if (extension && extension->data[0] == 'c') {
-                ret |= S_IFCHR;
-            } else {
-                ret |= S_IFBLK;
-            }
+    if (mode & P9_STAT_MODE_SYMLINK) {
+        ret |= S_IFLNK;
+    }
+    if (mode & P9_STAT_MODE_SOCKET) {
+        ret |= S_IFSOCK;
+    }
+    if (mode & P9_STAT_MODE_NAMED_PIPE) {
+        ret |= S_IFIFO;
+    }
+    if (mode & P9_STAT_MODE_DEVICE) {
+        if (extension && extension->data[0] == 'c') {
+            ret |= S_IFCHR;
+        } else {
+            ret |= S_IFBLK;
         }
     }
 
@@ -863,34 +980,32 @@ static uint32_t stat_to_v9mode(const struct stat *stbuf)
         mode |= P9_STAT_MODE_DIR;
     }
 
-    if (dotu) {
-        if (S_ISLNK(stbuf->st_mode)) {
-            mode |= P9_STAT_MODE_SYMLINK;
-        }
+    if (S_ISLNK(stbuf->st_mode)) {
+        mode |= P9_STAT_MODE_SYMLINK;
+    }
 
-        if (S_ISSOCK(stbuf->st_mode)) {
-            mode |= P9_STAT_MODE_SOCKET;
-        }
+    if (S_ISSOCK(stbuf->st_mode)) {
+        mode |= P9_STAT_MODE_SOCKET;
+    }
 
-        if (S_ISFIFO(stbuf->st_mode)) {
-            mode |= P9_STAT_MODE_NAMED_PIPE;
-        }
+    if (S_ISFIFO(stbuf->st_mode)) {
+        mode |= P9_STAT_MODE_NAMED_PIPE;
+    }
 
-        if (S_ISBLK(stbuf->st_mode) || S_ISCHR(stbuf->st_mode)) {
-            mode |= P9_STAT_MODE_DEVICE;
-        }
+    if (S_ISBLK(stbuf->st_mode) || S_ISCHR(stbuf->st_mode)) {
+        mode |= P9_STAT_MODE_DEVICE;
+    }
 
-        if (stbuf->st_mode & S_ISUID) {
-            mode |= P9_STAT_MODE_SETUID;
-        }
+    if (stbuf->st_mode & S_ISUID) {
+        mode |= P9_STAT_MODE_SETUID;
+    }
 
-        if (stbuf->st_mode & S_ISGID) {
-            mode |= P9_STAT_MODE_SETGID;
-        }
+    if (stbuf->st_mode & S_ISGID) {
+        mode |= P9_STAT_MODE_SETGID;
+    }
 
-        if (stbuf->st_mode & S_ISVTX) {
-            mode |= P9_STAT_MODE_SETVTX;
-        }
+    if (stbuf->st_mode & S_ISVTX) {
+        mode |= P9_STAT_MODE_SETVTX;
     }
 
     return mode;
@@ -915,29 +1030,27 @@ static int stat_to_v9stat(V9fsState *s, V9fsString *name,
     v9fs_string_null(&v9stat->gid);
     v9fs_string_null(&v9stat->muid);
 
-    if (dotu) {
-        v9stat->n_uid = stbuf->st_uid;
-        v9stat->n_gid = stbuf->st_gid;
-        v9stat->n_muid = 0;
+    v9stat->n_uid = stbuf->st_uid;
+    v9stat->n_gid = stbuf->st_gid;
+    v9stat->n_muid = 0;
 
-        v9fs_string_null(&v9stat->extension);
+    v9fs_string_null(&v9stat->extension);
 
-        if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
-            err = v9fs_do_readlink(s, name, &v9stat->extension);
-            if (err == -1) {
-                err = -errno;
-                return err;
-            }
-            v9stat->extension.data[err] = 0;
-            v9stat->extension.size = err;
-        } else if (v9stat->mode & P9_STAT_MODE_DEVICE) {
-            v9fs_string_sprintf(&v9stat->extension, "%c %u %u",
-                    S_ISCHR(stbuf->st_mode) ? 'c' : 'b',
-                    major(stbuf->st_rdev), minor(stbuf->st_rdev));
-        } else if (S_ISDIR(stbuf->st_mode) || S_ISREG(stbuf->st_mode)) {
-            v9fs_string_sprintf(&v9stat->extension, "%s %u",
-                    "HARDLINKCOUNT", stbuf->st_nlink);
+    if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
+        err = v9fs_do_readlink(s, name, &v9stat->extension);
+        if (err == -1) {
+            err = -errno;
+            return err;
         }
+        v9stat->extension.data[err] = 0;
+        v9stat->extension.size = err;
+    } else if (v9stat->mode & P9_STAT_MODE_DEVICE) {
+        v9fs_string_sprintf(&v9stat->extension, "%c %u %u",
+                S_ISCHR(stbuf->st_mode) ? 'c' : 'b',
+                major(stbuf->st_rdev), minor(stbuf->st_rdev));
+    } else if (S_ISDIR(stbuf->st_mode) || S_ISREG(stbuf->st_mode)) {
+        v9fs_string_sprintf(&v9stat->extension, "%s %lu",
+                "HARDLINKCOUNT", (unsigned long)stbuf->st_nlink);
     }
 
     str = strrchr(name->data, '/');
@@ -958,6 +1071,51 @@ static int stat_to_v9stat(V9fsState *s, V9fsString *name,
     return 0;
 }
 
+#define P9_STATS_MODE          0x00000001ULL
+#define P9_STATS_NLINK         0x00000002ULL
+#define P9_STATS_UID           0x00000004ULL
+#define P9_STATS_GID           0x00000008ULL
+#define P9_STATS_RDEV          0x00000010ULL
+#define P9_STATS_ATIME         0x00000020ULL
+#define P9_STATS_MTIME         0x00000040ULL
+#define P9_STATS_CTIME         0x00000080ULL
+#define P9_STATS_INO           0x00000100ULL
+#define P9_STATS_SIZE          0x00000200ULL
+#define P9_STATS_BLOCKS        0x00000400ULL
+
+#define P9_STATS_BTIME         0x00000800ULL
+#define P9_STATS_GEN           0x00001000ULL
+#define P9_STATS_DATA_VERSION  0x00002000ULL
+
+#define P9_STATS_BASIC         0x000007ffULL /* Mask for fields up to BLOCKS */
+#define P9_STATS_ALL           0x00003fffULL /* Mask for All fields above */
+
+
+static void stat_to_v9stat_dotl(V9fsState *s, const struct stat *stbuf,
+                            V9fsStatDotl *v9lstat)
+{
+    memset(v9lstat, 0, sizeof(*v9lstat));
+
+    v9lstat->st_mode = stbuf->st_mode;
+    v9lstat->st_nlink = stbuf->st_nlink;
+    v9lstat->st_uid = stbuf->st_uid;
+    v9lstat->st_gid = stbuf->st_gid;
+    v9lstat->st_rdev = stbuf->st_rdev;
+    v9lstat->st_size = stbuf->st_size;
+    v9lstat->st_blksize = stbuf->st_blksize;
+    v9lstat->st_blocks = stbuf->st_blocks;
+    v9lstat->st_atime_sec = stbuf->st_atime;
+    v9lstat->st_atime_nsec = stbuf->st_atim.tv_nsec;
+    v9lstat->st_mtime_sec = stbuf->st_mtime;
+    v9lstat->st_mtime_nsec = stbuf->st_mtim.tv_nsec;
+    v9lstat->st_ctime_sec = stbuf->st_ctime;
+    v9lstat->st_ctime_nsec = stbuf->st_ctim.tv_nsec;
+    /* Currently we only support BASIC fields in stat */
+    v9lstat->st_result_mask = P9_STATS_BASIC;
+
+    stat_to_qid(stbuf, &v9lstat->qid);
+}
+
 static struct iovec *adjust_sg(struct iovec *sg, int len, int *iovcnt)
 {
     while (len && *iovcnt) {
@@ -1019,17 +1177,20 @@ static void v9fs_fix_path(V9fsString *dst, V9fsString *src, int len)
 
 static void v9fs_version(V9fsState *s, V9fsPDU *pdu)
 {
-    int32_t msize;
     V9fsString version;
     size_t offset = 7;
 
-    pdu_unmarshal(pdu, offset, "ds", &msize, &version);
+    pdu_unmarshal(pdu, offset, "ds", &s->msize, &version);
 
-    if (strcmp(version.data, "9P2000.u")) {
+    if (!strcmp(version.data, "9P2000.u")) {
+        s->proto_version = V9FS_PROTO_2000U;
+    } else if (!strcmp(version.data, "9P2000.L")) {
+        s->proto_version = V9FS_PROTO_2000L;
+    } else {
         v9fs_string_sprintf(&version, "unknown");
     }
 
-    offset += pdu_marshal(pdu, offset, "ds", msize, &version);
+    offset += pdu_marshal(pdu, offset, "ds", s->msize, &version);
     complete_pdu(s, pdu, offset);
 
     v9fs_string_free(&version);
@@ -1121,6 +1282,202 @@ out:
     qemu_free(vs);
 }
 
+static void v9fs_getattr_post_lstat(V9fsState *s, V9fsStatStateDotl *vs,
+                                                                int err)
+{
+    if (err == -1) {
+        err = -errno;
+        goto out;
+    }
+
+    stat_to_v9stat_dotl(s, &vs->stbuf, &vs->v9stat_dotl);
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "A", &vs->v9stat_dotl);
+    err = vs->offset;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_getattr(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsStatStateDotl *vs;
+    ssize_t err = 0;
+    V9fsFidState *fidp;
+    uint64_t request_mask;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    memset(&vs->v9stat_dotl, 0, sizeof(vs->v9stat_dotl));
+
+    pdu_unmarshal(vs->pdu, vs->offset, "dq", &fid, &request_mask);
+
+    fidp = lookup_fid(s, fid);
+    if (fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    /* Currently we only support BASIC fields in stat, so there is no
+     * need to look at request_mask.
+     */
+    err = v9fs_do_lstat(s, &fidp->path, &vs->stbuf);
+    v9fs_getattr_post_lstat(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+/* From Linux kernel code */
+#define ATTR_MODE    (1 << 0)
+#define ATTR_UID     (1 << 1)
+#define ATTR_GID     (1 << 2)
+#define ATTR_SIZE    (1 << 3)
+#define ATTR_ATIME   (1 << 4)
+#define ATTR_MTIME   (1 << 5)
+#define ATTR_CTIME   (1 << 6)
+#define ATTR_MASK    127
+#define ATTR_ATIME_SET  (1 << 7)
+#define ATTR_MTIME_SET  (1 << 8)
+
+static void v9fs_setattr_post_truncate(V9fsState *s, V9fsSetattrState *vs,
+                                                                  int err)
+{
+    if (err == -1) {
+        err = -errno;
+        goto out;
+    }
+    err = vs->offset;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_setattr_post_chown(V9fsState *s, V9fsSetattrState *vs, int err)
+{
+    if (err == -1) {
+        err = -errno;
+        goto out;
+    }
+
+    if (vs->v9iattr.valid & (ATTR_SIZE)) {
+        err = v9fs_do_truncate(s, &vs->fidp->path, vs->v9iattr.size);
+    }
+    v9fs_setattr_post_truncate(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_setattr_post_utimensat(V9fsState *s, V9fsSetattrState *vs,
+                                                                   int err)
+{
+    if (err == -1) {
+        err = -errno;
+        goto out;
+    }
+
+    /* If the only valid entry in iattr is ctime we can call
+     * chown(-1,-1) to update the ctime of the file
+     */
+    if ((vs->v9iattr.valid & (ATTR_UID | ATTR_GID)) ||
+            ((vs->v9iattr.valid & ATTR_CTIME)
+            && !((vs->v9iattr.valid & ATTR_MASK) & ~ATTR_CTIME))) {
+        if (!(vs->v9iattr.valid & ATTR_UID)) {
+            vs->v9iattr.uid = -1;
+        }
+        if (!(vs->v9iattr.valid & ATTR_GID)) {
+            vs->v9iattr.gid = -1;
+        }
+        err = v9fs_do_chown(s, &vs->fidp->path, vs->v9iattr.uid,
+                                                vs->v9iattr.gid);
+    }
+    v9fs_setattr_post_chown(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_setattr_post_chmod(V9fsState *s, V9fsSetattrState *vs, int err)
+{
+    if (err == -1) {
+        err = -errno;
+        goto out;
+    }
+
+    if (vs->v9iattr.valid & (ATTR_ATIME | ATTR_MTIME)) {
+        struct timespec times[2];
+        if (vs->v9iattr.valid & ATTR_ATIME) {
+            if (vs->v9iattr.valid & ATTR_ATIME_SET) {
+                times[0].tv_sec = vs->v9iattr.atime_sec;
+                times[0].tv_nsec = vs->v9iattr.atime_nsec;
+            } else {
+                times[0].tv_nsec = UTIME_NOW;
+            }
+        } else {
+            times[0].tv_nsec = UTIME_OMIT;
+        }
+
+        if (vs->v9iattr.valid & ATTR_MTIME) {
+            if (vs->v9iattr.valid & ATTR_MTIME_SET) {
+                times[1].tv_sec = vs->v9iattr.mtime_sec;
+                times[1].tv_nsec = vs->v9iattr.mtime_nsec;
+            } else {
+                times[1].tv_nsec = UTIME_NOW;
+            }
+        } else {
+            times[1].tv_nsec = UTIME_OMIT;
+        }
+        err = v9fs_do_utimensat(s, &vs->fidp->path, times);
+    }
+    v9fs_setattr_post_utimensat(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_setattr(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsSetattrState *vs;
+    int err = 0;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    pdu_unmarshal(pdu, vs->offset, "dI", &fid, &vs->v9iattr);
+
+    vs->fidp = lookup_fid(s, fid);
+    if (vs->fidp == NULL) {
+        err = -EINVAL;
+        goto out;
+    }
+
+    if (vs->v9iattr.valid & ATTR_MODE) {
+        err = v9fs_do_chmod(s, &vs->fidp->path, vs->v9iattr.mode);
+    }
+
+    v9fs_setattr_post_chmod(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
 static void v9fs_walk_complete(V9fsState *s, V9fsWalkState *vs, int err)
 {
     complete_pdu(s, vs->pdu, err);
@@ -1241,8 +1598,7 @@ static void v9fs_walk(V9fsState *s, V9fsPDU *pdu)
     /* FIXME: is this really valid? */
     if (fid == newfid) {
 
-        BUG_ON(vs->fidp->fd != -1);
-        BUG_ON(vs->fidp->dir);
+        BUG_ON(vs->fidp->fid_type != P9_FID_NONE);
         v9fs_string_init(&vs->path);
         vs->name_idx = 0;
 
@@ -1284,13 +1640,33 @@ out:
     v9fs_walk_complete(s, vs, err);
 }
 
+static int32_t get_iounit(V9fsState *s, V9fsString *name)
+{
+    struct statfs stbuf;
+    int32_t iounit = 0;
+
+    /*
+     * 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)) {
+        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->dir == NULL) {
+    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:
@@ -1299,15 +1675,25 @@ out:
 
 }
 
+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);
+    qemu_free(vs);
+}
+
 static void v9fs_open_post_open(V9fsState *s, V9fsOpenState *vs, int err)
 {
-    if (vs->fidp->fd == -1) {
+    if (vs->fidp->fs.fd == -1) {
         err = -errno;
         goto out;
     }
-
-    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, 0);
-    err = vs->offset;
+    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);
     qemu_free(vs);
@@ -1315,6 +1701,8 @@ out:
 
 static void v9fs_open_post_lstat(V9fsState *s, V9fsOpenState *vs, int err)
 {
+    int flags;
+
     if (err) {
         err = -errno;
         goto out;
@@ -1323,11 +1711,18 @@ static void v9fs_open_post_lstat(V9fsState *s, V9fsOpenState *vs, int err)
     stat_to_qid(&vs->stbuf, &vs->qid);
 
     if (S_ISDIR(vs->stbuf.st_mode)) {
-        vs->fidp->dir = v9fs_do_opendir(s, &vs->fidp->path);
+        vs->fidp->fs.dir = v9fs_do_opendir(s, &vs->fidp->path);
         v9fs_open_post_opendir(s, vs, err);
     } else {
-        vs->fidp->fd = v9fs_do_open(s, &vs->fidp->path,
-                                    omode_to_uflags(vs->mode));
+        if (s->proto_version == V9FS_PROTO_2000L) {
+            flags = vs->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);
+        }
+        vs->fidp->fs.fd = v9fs_do_open(s, &vs->fidp->path, flags);
         v9fs_open_post_open(s, vs, err);
     }
     return;
@@ -1342,12 +1737,16 @@ static void v9fs_open(V9fsState *s, V9fsPDU *pdu)
     V9fsOpenState *vs;
     ssize_t err = 0;
 
-
     vs = qemu_malloc(sizeof(*vs));
     vs->pdu = pdu;
     vs->offset = 7;
+    vs->mode = 0;
 
-    pdu_unmarshal(vs->pdu, vs->offset, "db", &fid, &vs->mode);
+    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) {
@@ -1355,8 +1754,7 @@ static void v9fs_open(V9fsState *s, V9fsPDU *pdu)
         goto out;
     }
 
-    BUG_ON(vs->fidp->fd != -1);
-    BUG_ON(vs->fidp->dir);
+    BUG_ON(vs->fidp->fid_type != P9_FID_NONE);
 
     err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
 
@@ -1367,6 +1765,122 @@ out:
     qemu_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);
+    qemu_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(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t dfid, flags, mode;
+    gid_t gid;
+    V9fsLcreateState *vs;
+    ssize_t err = 0;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    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) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->fidp->path.data,
+             vs->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);
+    qemu_free(vs);
+}
+
+static void v9fs_post_do_fsync(V9fsState *s, V9fsPDU *pdu, int err)
+{
+    if (err == -1) {
+        err = -errno;
+    }
+    complete_pdu(s, pdu, err);
+}
+
+static void v9fs_fsync(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    size_t offset = 7;
+    V9fsFidState *fidp;
+    int err;
+
+    pdu_unmarshal(pdu, offset, "d", &fid);
+    fidp = lookup_fid(s, fid);
+    if (fidp == NULL) {
+        err = -ENOENT;
+        v9fs_post_do_fsync(s, pdu, err);
+        return;
+    }
+    err = v9fs_do_fsync(s, fidp->fs.fd);
+    v9fs_post_do_fsync(s, pdu, err);
+}
+
 static void v9fs_clunk(V9fsState *s, V9fsPDU *pdu)
 {
     int32_t fid;
@@ -1420,7 +1934,7 @@ static void v9fs_read_post_dir_lstat(V9fsState *s, V9fsReadState *vs,
                             &vs->v9stat);
     if ((vs->len != (vs->v9stat.size + 2)) ||
             ((vs->count + vs->len) > vs->max_count)) {
-        v9fs_do_seekdir(s, vs->fidp->dir, vs->dir_pos);
+        v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->dir_pos);
         v9fs_read_post_seekdir(s, vs, err);
         return;
     }
@@ -1428,11 +1942,11 @@ static void v9fs_read_post_dir_lstat(V9fsState *s, V9fsReadState *vs,
     v9fs_stat_free(&vs->v9stat);
     v9fs_string_free(&vs->name);
     vs->dir_pos = vs->dent->d_off;
-    vs->dent = v9fs_do_readdir(s, vs->fidp->dir);
+    vs->dent = v9fs_do_readdir(s, vs->fidp->fs.dir);
     v9fs_read_post_readdir(s, vs, err);
     return;
 out:
-    v9fs_do_seekdir(s, vs->fidp->dir, vs->dir_pos);
+    v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->dir_pos);
     v9fs_read_post_seekdir(s, vs, err);
     return;
 
@@ -1460,7 +1974,7 @@ static void v9fs_read_post_readdir(V9fsState *s, V9fsReadState *vs, ssize_t err)
 
 static void v9fs_read_post_telldir(V9fsState *s, V9fsReadState *vs, ssize_t err)
 {
-    vs->dent = v9fs_do_readdir(s, vs->fidp->dir);
+    vs->dent = v9fs_do_readdir(s, vs->fidp->fs.dir);
     v9fs_read_post_readdir(s, vs, err);
     return;
 }
@@ -1468,12 +1982,12 @@ static void v9fs_read_post_telldir(V9fsState *s, V9fsReadState *vs, ssize_t err)
 static void v9fs_read_post_rewinddir(V9fsState *s, V9fsReadState *vs,
                                        ssize_t err)
 {
-    vs->dir_pos = v9fs_do_telldir(s, vs->fidp->dir);
+    vs->dir_pos = v9fs_do_telldir(s, vs->fidp->fs.dir);
     v9fs_read_post_telldir(s, vs, err);
     return;
 }
 
-static void v9fs_read_post_readv(V9fsState *s, V9fsReadState *vs, ssize_t err)
+static void v9fs_read_post_preadv(V9fsState *s, V9fsReadState *vs, ssize_t err)
 {
     if (err  < 0) {
         /* IO error return the error */
@@ -1487,12 +2001,16 @@ static void v9fs_read_post_readv(V9fsState *s, V9fsReadState *vs, ssize_t err)
             if (0) {
                 print_sg(vs->sg, vs->cnt);
             }
-            vs->len = v9fs_do_readv(s, vs->fidp->fd, 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_readv(s, vs, err);
+        v9fs_read_post_preadv(s, vs, err);
         return;
     }
     vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total);
@@ -1504,28 +2022,27 @@ out:
     qemu_free(vs);
 }
 
-static void v9fs_read_post_lseek(V9fsState *s, V9fsReadState *vs, ssize_t err)
+static void v9fs_xattr_read(V9fsState *s, V9fsReadState *vs)
 {
-    if (err == -1) {
-        err = -errno;
-        goto out;
-    }
-    vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
-
-    if (vs->total < vs->count) {
-        do {
-            if (0) {
-                print_sg(vs->sg, vs->cnt);
-            }
-            vs->len = v9fs_do_readv(s, vs->fidp->fd, vs->sg, vs->cnt);
-        } while (vs->len == -1 && errno == EINTR);
-        if (vs->len == -1) {
-            err  = -errno;
-        }
-        v9fs_read_post_readv(s, vs, err);
-        return;
+    ssize_t err = 0;
+    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;
+    } else if (read_count < 0) {
+        /*
+         * read beyond XATTR value
+         */
+        read_count = 0;
     }
-out:
+    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);
     qemu_free(vs);
 }
@@ -1551,19 +2068,30 @@ static void v9fs_read(V9fsState *s, V9fsPDU *pdu)
         goto out;
     }
 
-    if (vs->fidp->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->dir);
+            v9fs_do_rewinddir(s, vs->fidp->fs.dir);
         }
         v9fs_read_post_rewinddir(s, vs, err);
         return;
-    } else if (vs->fidp->fd != -1) {
+    } 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);
-        err = v9fs_do_lseek(s, vs->fidp->fd, vs->off, SEEK_SET);
-        v9fs_read_post_lseek(s, vs, err);
+        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;
+            }
+            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;
     } else {
         err = -EINVAL;
@@ -1573,7 +2101,128 @@ out:
     qemu_free(vs);
 }
 
-static void v9fs_write_post_writev(V9fsState *s, V9fsWriteState *vs,
+typedef struct V9fsReadDirState {
+    V9fsPDU *pdu;
+    V9fsFidState *fidp;
+    V9fsQID qid;
+    off_t saved_dir_pos;
+    struct dirent *dent;
+    int32_t count;
+    int32_t max_count;
+    size_t offset;
+    int64_t initial_offset;
+    V9fsString name;
+} V9fsReadDirState;
+
+static void v9fs_readdir_post_seekdir(V9fsState *s, V9fsReadDirState *vs)
+{
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
+    vs->offset += vs->count;
+    complete_pdu(s, vs->pdu, vs->offset);
+    qemu_free(vs);
+    return;
+}
+
+/* Size of each dirent on the wire: size of qid (13) + size of offset (8)
+ * size of type (1) + size of name.size (2) + strlen(name.data)
+ */
+#define V9_READDIR_DATA_SZ (24 + strlen(vs->name.data))
+
+static void v9fs_readdir_post_readdir(V9fsState *s, V9fsReadDirState *vs)
+{
+    int len;
+    size_t size;
+
+    if (vs->dent) {
+        v9fs_string_init(&vs->name);
+        v9fs_string_sprintf(&vs->name, "%s", vs->dent->d_name);
+
+        if ((vs->count + V9_READDIR_DATA_SZ) > vs->max_count) {
+            /* Ran out of buffer. Set dir back to old position and return */
+            v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->saved_dir_pos);
+            v9fs_readdir_post_seekdir(s, vs);
+            return;
+        }
+
+        /* Fill up just the path field of qid because the client uses
+         * only that. To fill the entire qid structure we will have
+         * to stat each dirent found, which is expensive
+         */
+        size = MIN(sizeof(vs->dent->d_ino), sizeof(vs->qid.path));
+        memcpy(&vs->qid.path, &vs->dent->d_ino, size);
+        /* Fill the other fields with dummy values */
+        vs->qid.type = 0;
+        vs->qid.version = 0;
+
+        len = pdu_marshal(vs->pdu, vs->offset+4+vs->count, "Qqbs",
+                              &vs->qid, vs->dent->d_off,
+                              vs->dent->d_type, &vs->name);
+        vs->count += len;
+        v9fs_string_free(&vs->name);
+        vs->saved_dir_pos = vs->dent->d_off;
+        vs->dent = v9fs_do_readdir(s, vs->fidp->fs.dir);
+        v9fs_readdir_post_readdir(s, vs);
+        return;
+    }
+
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
+    vs->offset += vs->count;
+    complete_pdu(s, vs->pdu, vs->offset);
+    qemu_free(vs);
+    return;
+}
+
+static void v9fs_readdir_post_telldir(V9fsState *s, V9fsReadDirState *vs)
+{
+    vs->dent = v9fs_do_readdir(s, vs->fidp->fs.dir);
+    v9fs_readdir_post_readdir(s, vs);
+    return;
+}
+
+static void v9fs_readdir_post_setdir(V9fsState *s, V9fsReadDirState *vs)
+{
+    vs->saved_dir_pos = v9fs_do_telldir(s, vs->fidp->fs.dir);
+    v9fs_readdir_post_telldir(s, vs);
+    return;
+}
+
+static void v9fs_readdir(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsReadDirState *vs;
+    ssize_t err = 0;
+    size_t offset = 7;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+    vs->count = 0;
+
+    pdu_unmarshal(vs->pdu, offset, "dqd", &fid, &vs->initial_offset,
+                                                        &vs->max_count);
+
+    vs->fidp = lookup_fid(s, fid);
+    if (vs->fidp == NULL || !(vs->fidp->fs.dir)) {
+        err = -EINVAL;
+        goto out;
+    }
+
+    if (vs->initial_offset == 0) {
+        v9fs_do_rewinddir(s, vs->fidp->fs.dir);
+    } else {
+        v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->initial_offset);
+    }
+
+    v9fs_readdir_post_setdir(s, vs);
+    return;
+
+out:
+    complete_pdu(s, pdu, err);
+    qemu_free(vs);
+    return;
+}
+
+static void v9fs_write_post_pwritev(V9fsState *s, V9fsWriteState *vs,
                                    ssize_t err)
 {
     if (err  < 0) {
@@ -1588,44 +2237,62 @@ static void v9fs_write_post_writev(V9fsState *s, V9fsWriteState *vs,
             if (0) {
                 print_sg(vs->sg, vs->cnt);
             }
-            vs->len =  v9fs_do_writev(s, vs->fidp->fd, 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_writev(s, vs, err);
+        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);
     qemu_free(vs);
 }
 
-static void v9fs_write_post_lseek(V9fsState *s, V9fsWriteState *vs, ssize_t err)
+static void v9fs_xattr_write(V9fsState *s, V9fsWriteState *vs)
 {
-    if (err == -1) {
-        err = -errno;
+    int i, to_copy;
+    ssize_t err = 0;
+    int write_count;
+    int64_t xattr_len;
+
+    xattr_len = vs->fidp->fs.xattr.len;
+    write_count = xattr_len - vs->off;
+    if (write_count > vs->count) {
+        write_count = vs->count;
+    } else if (write_count < 0) {
+        /*
+         * write beyond XATTR value len specified in
+         * xattrcreate
+         */
+        err = -ENOSPC;
         goto out;
     }
-    vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
-
-    if (vs->total < vs->count) {
-        do {
-            if (0) {
-                print_sg(vs->sg, vs->cnt);
-            }
-            vs->len = v9fs_do_writev(s, vs->fidp->fd, vs->sg, vs->cnt);
-        } while (vs->len == -1 && errno == EINTR);
-        if (vs->len == -1) {
-            err  = -errno;
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", write_count);
+    err = vs->offset;
+    vs->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;
+        } else {
+            to_copy = write_count;
         }
-        v9fs_write_post_writev(s, vs, err);
-        return;
+        memcpy((char *)vs->fidp->fs.xattr.value + vs->off,
+               vs->sg[i].iov_base, to_copy);
+        /* updating vs->off since we are not using below */
+        vs->off += to_copy;
+        write_count -= to_copy;
     }
-
 out:
     complete_pdu(s, vs->pdu, err);
     qemu_free(vs);
@@ -1646,7 +2313,7 @@ static void v9fs_write(V9fsState *s, V9fsPDU *pdu)
     vs->len = 0;
 
     pdu_unmarshal(vs->pdu, vs->offset, "dqdv", &fid, &vs->off, &vs->count,
-                    vs->sg, &vs->cnt);
+                  vs->sg, &vs->cnt);
 
     vs->fidp = lookup_fid(s, fid);
     if (vs->fidp == NULL) {
@@ -1654,30 +2321,58 @@ static void v9fs_write(V9fsState *s, V9fsPDU *pdu)
         goto out;
     }
 
-    if (vs->fidp->fd == -1) {
+    if (vs->fidp->fid_type == P9_FID_FILE) {
+        if (vs->fidp->fs.fd == -1) {
+            err = -EINVAL;
+            goto out;
+        }
+    } else if (vs->fidp->fid_type == P9_FID_XATTR) {
+        /*
+         * setxattr operation
+         */
+        v9fs_xattr_write(s, vs);
+        return;
+    } 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;
+        }
+        err = vs->len;
+        v9fs_write_post_pwritev(s, vs, err);
+    }
+    return;
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
 
-    err = v9fs_do_lseek(s, vs->fidp->fd, vs->off, SEEK_SET);
+static void v9fs_create_post_getiounit(V9fsState *s, V9fsCreateState *vs)
+{
+    int err;
+    v9fs_string_copy(&vs->fidp->path, &vs->fullname);
+    stat_to_qid(&vs->stbuf, &vs->qid);
 
-    v9fs_write_post_lseek(s, vs, err);
-    return;
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, vs->iounit);
+    err = vs->offset;
 
-out:
     complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    v9fs_string_free(&vs->extension);
+    v9fs_string_free(&vs->fullname);
     qemu_free(vs);
 }
 
 static void v9fs_post_create(V9fsState *s, V9fsCreateState *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, 0);
-
-        err = vs->offset;
+        vs->iounit = get_iounit(s, &vs->fidp->path);
+        v9fs_create_post_getiounit(s, vs);
+        return;
     }
 
     complete_pdu(s, vs->pdu, err);
@@ -1698,9 +2393,10 @@ static void v9fs_create_post_perms(V9fsState *s, V9fsCreateState *vs, int err)
 static void v9fs_create_post_opendir(V9fsState *s, V9fsCreateState *vs,
                                                                     int err)
 {
-    if (!vs->fidp->dir) {
+    if (!vs->fidp->fs.dir) {
         err = -errno;
     }
+    vs->fidp->fid_type = P9_FID_DIR;
     v9fs_post_create(s, vs, err);
 }
 
@@ -1712,7 +2408,7 @@ static void v9fs_create_post_dir_lstat(V9fsState *s, V9fsCreateState *vs,
         goto out;
     }
 
-    vs->fidp->dir = v9fs_do_opendir(s, &vs->fullname);
+    vs->fidp->fs.dir = v9fs_do_opendir(s, &vs->fullname);
     v9fs_create_post_opendir(s, vs, err);
     return;
 
@@ -1738,22 +2434,22 @@ out:
 static void v9fs_create_post_fstat(V9fsState *s, V9fsCreateState *vs, int err)
 {
     if (err) {
-        vs->fidp->fd = -1;
+        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->fd == -1) {
+    if (vs->fidp->fs.fd == -1) {
         err = -errno;
         goto out;
     }
-
-    err = v9fs_do_fstat(s, vs->fidp->fd, &vs->stbuf);
+    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;
@@ -1772,10 +2468,12 @@ static void v9fs_create_post_lstat(V9fsState *s, V9fsCreateState *vs, int err)
     }
 
     if (vs->perm & P9_STAT_MODE_DIR) {
-        err = v9fs_do_mkdir(s, vs);
+        err = v9fs_do_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);
+        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);
@@ -1810,16 +2508,21 @@ static void v9fs_create_post_lstat(V9fsState *s, V9fsCreateState *vs, int err)
         }
 
         nmode |= vs->perm & 0777;
-        err = v9fs_do_mknod(s, vs, nmode, makedev(major, minor));
+        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, S_IFIFO | (vs->perm & 0777), 0);
+        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, S_IFSOCK | (vs->perm & 0777), 0);
+        err = v9fs_do_mknod(s, vs->fullname.data, S_IFSOCK | (vs->perm & 0777),
+                0, vs->fidp->uid, -1);
         v9fs_post_create(s, vs, err);
     } else {
-        vs->fidp->fd = v9fs_do_open2(s, vs);
+        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);
     }
 
@@ -1864,23 +2567,124 @@ out:
     qemu_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);
+    qemu_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);
+}
+
+static void v9fs_symlink(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t dfid;
+    V9fsSymlinkState *vs;
+    int err = 0;
+    gid_t gid;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    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) {
+        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;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    v9fs_string_free(&vs->symname);
+    qemu_free(vs);
+}
+
 static void v9fs_flush(V9fsState *s, V9fsPDU *pdu)
 {
     /* A nop call with no return */
     complete_pdu(s, pdu, 7);
 }
 
+static void v9fs_link(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t dfid, oldfid;
+    V9fsFidState *dfidp, *oldfidp;
+    V9fsString name, fullname;
+    size_t offset = 7;
+    int err = 0;
+
+    v9fs_string_init(&fullname);
+
+    pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
+
+    dfidp = lookup_fid(s, dfid);
+    if (dfidp == NULL) {
+        err = -errno;
+        goto out;
+    }
+
+    oldfidp = lookup_fid(s, oldfid);
+    if (oldfidp == NULL) {
+        err = -errno;
+        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;
+    }
+    v9fs_string_free(&fullname);
+
+out:
+    v9fs_string_free(&name);
+    complete_pdu(s, pdu, err);
+}
+
 static void v9fs_remove_post_remove(V9fsState *s, V9fsRemoveState *vs,
                                                                 int err)
 {
-    /* For TREMOVE we need to clunk the fid even on failed remove */
-    err = free_fid(s, vs->fidp->fid);
     if (err < 0) {
-        goto out;
+        err = -errno;
+    } else {
+        err = vs->offset;
     }
 
-    err = vs->offset;
-out:
+    /* For TREMOVE we need to clunk the fid even on failed remove */
+    free_fid(s, vs->fidp->fid);
+
     complete_pdu(s, vs->pdu, err);
     qemu_free(vs);
 }
@@ -1931,11 +2735,6 @@ static void v9fs_wstat_post_rename(V9fsState *s, V9fsWstatState *vs, int err)
     if (err < 0) {
         goto out;
     }
-
-    if (vs->v9stat.name.size != 0) {
-        v9fs_string_free(&vs->nname);
-    }
-
     if (vs->v9stat.length != -1) {
         if (v9fs_do_truncate(s, &vs->fidp->path, vs->v9stat.length) < 0) {
             err = -errno;
@@ -1950,17 +2749,29 @@ out:
     qemu_free(vs);
 }
 
-static void v9fs_wstat_post_chown(V9fsState *s, V9fsWstatState *vs, int err)
+static int v9fs_complete_rename(V9fsState *s, V9fsRenameState *vs)
 {
-    V9fsFidState *fidp;
-    if (err < 0) {
-        goto out;
-    }
+    int err = 0;
+    char *old_name, *new_name;
+    char *end;
 
-    if (vs->v9stat.name.size != 0) {
-        char *old_name, *new_name;
-        char *end;
+    if (vs->newdirfid != -1) {
+        V9fsFidState *dirfidp;
+        dirfidp = lookup_fid(s, vs->newdirfid);
 
+        if (dirfidp == NULL) {
+            err = -ENOENT;
+            goto out;
+        }
+
+        BUG_ON(dirfidp->fid_type != P9_FID_NONE);
+
+        new_name = qemu_mallocz(dirfidp->path.size + vs->name.size + 2);
+
+        strcpy(new_name, dirfidp->path.data);
+        strcat(new_name, "/");
+        strcat(new_name + dirfidp->path.size, vs->name.data);
+    } else {
         old_name = vs->fidp->path.data;
         end = strrchr(old_name, '/');
         if (end) {
@@ -1968,44 +2779,74 @@ static void v9fs_wstat_post_chown(V9fsState *s, V9fsWstatState *vs, int err)
         } else {
             end = old_name;
         }
+        new_name = qemu_mallocz(end - old_name + vs->name.size + 1);
 
-        new_name = qemu_malloc(end - old_name + vs->v9stat.name.size + 1);
+        strncat(new_name, old_name, end - old_name);
+        strncat(new_name + (end - old_name), vs->name.data, vs->name.size);
+    }
 
-        memset(new_name, 0, end - old_name + vs->v9stat.name.size + 1);
-        memcpy(new_name, old_name, end - old_name);
-        memcpy(new_name + (end - old_name), vs->v9stat.name.data,
-                vs->v9stat.name.size);
-        vs->nname.data = new_name;
-        vs->nname.size = strlen(new_name);
+    v9fs_string_free(&vs->name);
+    vs->name.data = qemu_strdup(new_name);
+    vs->name.size = strlen(new_name);
 
-        if (strcmp(new_name, vs->fidp->path.data) != 0) {
-            if (v9fs_do_rename(s, &vs->fidp->path, &vs->nname)) {
-                err = -errno;
-            } else {
-                /*
-                 * Fixup fid's pointing to the old name to
-                 * start pointing to the new name
-                 */
-                for (fidp = s->fid_list; fidp; fidp = fidp->next) {
-
-                    if (vs->fidp == fidp) {
-                        /*
-                         * we replace name of this fid towards the end
-                         * so that our below strcmp will work
-                         */
-                        continue;
-                    }
-                    if (!strncmp(vs->fidp->path.data, fidp->path.data,
-                                 strlen(vs->fidp->path.data))) {
-                        /* replace the name */
-                        v9fs_fix_path(&fidp->path, &vs->nname,
-                                      strlen(vs->fidp->path.data));
-                    }
+    if (strcmp(new_name, vs->fidp->path.data) != 0) {
+        if (v9fs_do_rename(s, &vs->fidp->path, &vs->name)) {
+            err = -errno;
+        } else {
+            V9fsFidState *fidp;
+            /*
+            * Fixup fid's pointing to the old name to
+            * start pointing to the new name
+            */
+            for (fidp = s->fid_list; fidp; fidp = fidp->next) {
+                if (vs->fidp == fidp) {
+                    /*
+                    * we replace name of this fid towards the end
+                    * so that our below strcmp will work
+                    */
+                    continue;
+                }
+                if (!strncmp(vs->fidp->path.data, fidp->path.data,
+                    strlen(vs->fidp->path.data))) {
+                    /* replace the name */
+                    v9fs_fix_path(&fidp->path, &vs->name,
+                                  strlen(vs->fidp->path.data));
                 }
-                v9fs_string_copy(&vs->fidp->path, &vs->nname);
             }
+            v9fs_string_copy(&vs->fidp->path, &vs->name);
         }
     }
+out:
+    v9fs_string_free(&vs->name);
+    return err;
+}
+
+static void v9fs_rename_post_rename(V9fsState *s, V9fsRenameState *vs, int err)
+{
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_wstat_post_chown(V9fsState *s, V9fsWstatState *vs, int err)
+{
+    if (err < 0) {
+        goto out;
+    }
+
+    if (vs->v9stat.name.size != 0) {
+        V9fsRenameState *vr;
+
+        vr = qemu_mallocz(sizeof(V9fsRenameState));
+        vr->newdirfid = -1;
+        vr->pdu = vs->pdu;
+        vr->fidp = vs->fidp;
+        vr->offset = vs->offset;
+        vr->name.size = vs->v9stat.name.size;
+        vr->name.data = qemu_strdup(vs->v9stat.name.data);
+
+        err = v9fs_complete_rename(s, vr);
+        qemu_free(vr);
+    }
     v9fs_wstat_post_rename(s, vs, err);
     return;
 
@@ -2015,6 +2856,34 @@ out:
     qemu_free(vs);
 }
 
+static void v9fs_rename(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsRenameState *vs;
+    ssize_t err = 0;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    pdu_unmarshal(vs->pdu, vs->offset, "dds", &fid, &vs->newdirfid, &vs->name);
+
+    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_complete_rename(s, vs);
+    v9fs_rename_post_rename(s, vs, err);
+    return;
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
 static void v9fs_wstat_post_utime(V9fsState *s, V9fsWstatState *vs, int err)
 {
     if (err < 0) {
@@ -2042,11 +2911,22 @@ static void v9fs_wstat_post_chmod(V9fsState *s, V9fsWstatState *vs, int err)
         goto out;
     }
 
-    if (vs->v9stat.mtime != -1) {
-        struct utimbuf tb;
-        tb.actime = 0;
-        tb.modtime = vs->v9stat.mtime;
-        if (v9fs_do_utime(s, &vs->fidp->path, &tb)) {
+    if (vs->v9stat.mtime != -1 || vs->v9stat.atime != -1) {
+        struct timespec times[2];
+        if (vs->v9stat.atime != -1) {
+            times[0].tv_sec = vs->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;
+            times[1].tv_nsec = 0;
+        } else {
+            times[1].tv_nsec = UTIME_OMIT;
+        }
+
+        if (v9fs_do_utimensat(s, &vs->fidp->path, times)) {
             err = -errno;
         }
     }
@@ -2121,7 +3001,7 @@ static void v9fs_wstat(V9fsState *s, V9fsPDU *pdu)
 
     /* do we need to sync the file? */
     if (donttouch_stat(&vs->v9stat)) {
-        err = v9fs_do_fsync(s, vs->fidp->fd);
+        err = v9fs_do_fsync(s, vs->fidp->fs.fd);
         v9fs_wstat_post_fsync(s, vs, err);
         return;
     }
@@ -2141,21 +3021,565 @@ out:
     qemu_free(vs);
 }
 
+static void v9fs_statfs_post_statfs(V9fsState *s, V9fsStatfsState *vs, int err)
+{
+    int32_t bsize_factor;
+
+    if (err) {
+        err = -errno;
+        goto out;
+    }
+
+    /*
+     * compute bsize factor based on host file system block size
+     * and client msize
+     */
+    bsize_factor = (s->msize - P9_IOHDRSZ)/vs->stbuf.f_bsize;
+    if (!bsize_factor) {
+        bsize_factor = 1;
+    }
+    vs->v9statfs.f_type = vs->stbuf.f_type;
+    vs->v9statfs.f_bsize = vs->stbuf.f_bsize;
+    vs->v9statfs.f_bsize *= bsize_factor;
+    /*
+     * f_bsize is adjusted(multiplied) by bsize factor, so we need to
+     * adjust(divide) the number of blocks, free blocks and available
+     * blocks by bsize factor
+     */
+    vs->v9statfs.f_blocks = vs->stbuf.f_blocks/bsize_factor;
+    vs->v9statfs.f_bfree = vs->stbuf.f_bfree/bsize_factor;
+    vs->v9statfs.f_bavail = vs->stbuf.f_bavail/bsize_factor;
+    vs->v9statfs.f_files = vs->stbuf.f_files;
+    vs->v9statfs.f_ffree = vs->stbuf.f_ffree;
+    vs->v9statfs.fsid_val = (unsigned int) vs->stbuf.f_fsid.__val[0] |
+			(unsigned long long)vs->stbuf.f_fsid.__val[1] << 32;
+    vs->v9statfs.f_namelen = vs->stbuf.f_namelen;
+
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "ddqqqqqqd",
+         vs->v9statfs.f_type, vs->v9statfs.f_bsize, vs->v9statfs.f_blocks,
+         vs->v9statfs.f_bfree, vs->v9statfs.f_bavail, vs->v9statfs.f_files,
+         vs->v9statfs.f_ffree, vs->v9statfs.fsid_val,
+         vs->v9statfs.f_namelen);
+
+out:
+    complete_pdu(s, vs->pdu, vs->offset);
+    qemu_free(vs);
+}
+
+static void v9fs_statfs(V9fsState *s, V9fsPDU *pdu)
+{
+    V9fsStatfsState *vs;
+    ssize_t err = 0;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    memset(&vs->v9statfs, 0, sizeof(vs->v9statfs));
+
+    pdu_unmarshal(vs->pdu, vs->offset, "d", &vs->fid);
+
+    vs->fidp = lookup_fid(s, vs->fid);
+    if (vs->fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    err = v9fs_do_statfs(s, &vs->fidp->path, &vs->stbuf);
+    v9fs_statfs_post_statfs(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
+static void v9fs_mknod_post_lstat(V9fsState *s, V9fsMkState *vs, int err)
+{
+    if (err == -1) {
+        err = -errno;
+        goto out;
+    }
+
+    stat_to_qid(&vs->stbuf, &vs->qid);
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qid);
+    err = vs->offset;
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->fullname);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+}
+
+static void v9fs_mknod_post_mknod(V9fsState *s, V9fsMkState *vs, int err)
+{
+    if (err == -1) {
+        err = -errno;
+        goto out;
+    }
+
+    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
+    v9fs_mknod_post_lstat(s, vs, err);
+    return;
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->fullname);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+}
+
+static void v9fs_mknod(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsMkState *vs;
+    int err = 0;
+    V9fsFidState *fidp;
+    gid_t gid;
+    int mode;
+    int major, minor;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    v9fs_string_init(&vs->fullname);
+    pdu_unmarshal(vs->pdu, vs->offset, "dsdddd", &fid, &vs->name, &mode,
+        &major, &minor, &gid);
+
+    fidp = lookup_fid(s, fid);
+    if (fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    v9fs_string_sprintf(&vs->fullname, "%s/%s", fidp->path.data, vs->name.data);
+    err = v9fs_do_mknod(s, vs->fullname.data, mode, makedev(major, minor),
+        fidp->uid, gid);
+    v9fs_mknod_post_mknod(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->fullname);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+}
+
+/*
+ * Implement posix byte range locking code
+ * Server side handling of locking code is very simple, because 9p server in
+ * QEMU can handle only one client. And most of the lock handling
+ * (like conflict, merging) etc is done by the VFS layer itself, so no need to
+ * do any thing in * qemu 9p server side lock code path.
+ * So when a TLOCK request comes, always return success
+ */
+
+static void v9fs_lock(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid, err = 0;
+    V9fsLockState *vs;
+
+    vs = qemu_mallocz(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    vs->flock = qemu_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;
+
+    /* We support only block flag now (that too ignored currently) */
+    if (vs->flock->flags & ~P9_LOCK_FLAGS_BLOCK) {
+        err = -EINVAL;
+        goto out;
+    }
+    vs->fidp = lookup_fid(s, fid);
+    if (vs->fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf);
+    if (err < 0) {
+        err = -errno;
+        goto out;
+    }
+    vs->status = P9_LOCK_SUCCESS;
+out:
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "b", vs->status);
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs->flock);
+    qemu_free(vs);
+}
+
+/*
+ * When a TGETLOCK request comes, always return success because all lock
+ * handling is done by client's VFS layer.
+ */
+
+static void v9fs_getlock(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid, err = 0;
+    V9fsGetlockState *vs;
+
+    vs = qemu_mallocz(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    vs->glock = qemu_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) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->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);
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs->glock);
+    qemu_free(vs);
+}
+
+static void v9fs_mkdir_post_lstat(V9fsState *s, V9fsMkState *vs, int err)
+{
+    if (err == -1) {
+        err = -errno;
+        goto out;
+    }
+
+    stat_to_qid(&vs->stbuf, &vs->qid);
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qid);
+    err = vs->offset;
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->fullname);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+}
+
+static void v9fs_mkdir_post_mkdir(V9fsState *s, V9fsMkState *vs, int err)
+{
+    if (err == -1) {
+        err = -errno;
+        goto out;
+    }
+
+    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
+    v9fs_mkdir_post_lstat(s, vs, err);
+    return;
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->fullname);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+}
+
+static void v9fs_mkdir(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsMkState *vs;
+    int err = 0;
+    V9fsFidState *fidp;
+    gid_t gid;
+    int mode;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    v9fs_string_init(&vs->fullname);
+    pdu_unmarshal(vs->pdu, vs->offset, "dsdd", &fid, &vs->name, &mode,
+        &gid);
+
+    fidp = lookup_fid(s, fid);
+    if (fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    v9fs_string_sprintf(&vs->fullname, "%s/%s", fidp->path.data, vs->name.data);
+    err = v9fs_do_mkdir(s, vs->fullname.data, mode, fidp->uid, gid);
+    v9fs_mkdir_post_mkdir(s, vs, err);
+    return;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->fullname);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+}
+
+static void v9fs_post_xattr_getvalue(V9fsState *s, V9fsXattrState *vs, int err)
+{
+
+    if (err < 0) {
+        err = -errno;
+        free_fid(s, vs->xattr_fidp->fid);
+        goto out;
+    }
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "q", vs->size);
+    err = vs->offset;
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+    return;
+}
+
+static void v9fs_post_xattr_check(V9fsState *s, V9fsXattrState *vs, ssize_t err)
+{
+    if (err < 0) {
+        err = -errno;
+        free_fid(s, vs->xattr_fidp->fid);
+        goto out;
+    }
+    /*
+     * Read the xattr value
+     */
+    vs->xattr_fidp->fs.xattr.len = vs->size;
+    vs->xattr_fidp->fid_type = P9_FID_XATTR;
+    vs->xattr_fidp->fs.xattr.copied_len = -1;
+    if (vs->size) {
+        vs->xattr_fidp->fs.xattr.value = qemu_malloc(vs->size);
+        err = v9fs_do_lgetxattr(s, &vs->xattr_fidp->path,
+                                &vs->name, vs->xattr_fidp->fs.xattr.value,
+                                vs->xattr_fidp->fs.xattr.len);
+    }
+    v9fs_post_xattr_getvalue(s, vs, err);
+    return;
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+}
+
+static void v9fs_post_lxattr_getvalue(V9fsState *s,
+                                      V9fsXattrState *vs, int err)
+{
+    if (err < 0) {
+        err = -errno;
+        free_fid(s, vs->xattr_fidp->fid);
+        goto out;
+    }
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "q", vs->size);
+    err = vs->offset;
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+    return;
+}
+
+static void v9fs_post_lxattr_check(V9fsState *s,
+                                   V9fsXattrState *vs, ssize_t err)
+{
+    if (err < 0) {
+        err = -errno;
+        free_fid(s, vs->xattr_fidp->fid);
+        goto out;
+    }
+    /*
+     * Read the xattr value
+     */
+    vs->xattr_fidp->fs.xattr.len = vs->size;
+    vs->xattr_fidp->fid_type = P9_FID_XATTR;
+    vs->xattr_fidp->fs.xattr.copied_len = -1;
+    if (vs->size) {
+        vs->xattr_fidp->fs.xattr.value = qemu_malloc(vs->size);
+        err = v9fs_do_llistxattr(s, &vs->xattr_fidp->path,
+                                 vs->xattr_fidp->fs.xattr.value,
+                                 vs->xattr_fidp->fs.xattr.len);
+    }
+    v9fs_post_lxattr_getvalue(s, vs, err);
+    return;
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+}
+
+static void v9fs_xattrwalk(V9fsState *s, V9fsPDU *pdu)
+{
+    ssize_t err = 0;
+    V9fsXattrState *vs;
+    int32_t fid, newfid;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    pdu_unmarshal(vs->pdu, vs->offset, "dds", &fid, &newfid, &vs->name);
+    vs->file_fidp = lookup_fid(s, fid);
+    if (vs->file_fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    vs->xattr_fidp = alloc_fid(s, newfid);
+    if (vs->xattr_fidp == NULL) {
+        err = -EINVAL;
+        goto out;
+    }
+
+    v9fs_string_copy(&vs->xattr_fidp->path, &vs->file_fidp->path);
+    if (vs->name.data[0] == 0) {
+        /*
+         * listxattr request. Get the size first
+         */
+        vs->size = v9fs_do_llistxattr(s, &vs->xattr_fidp->path,
+                                      NULL, 0);
+        if (vs->size < 0) {
+            err = vs->size;
+        }
+        v9fs_post_lxattr_check(s, vs, err);
+        return;
+    } else {
+        /*
+         * specific xattr fid. We check for xattr
+         * presence also collect the xattr size
+         */
+        vs->size = v9fs_do_lgetxattr(s, &vs->xattr_fidp->path,
+                                     &vs->name, NULL, 0);
+        if (vs->size < 0) {
+            err = vs->size;
+        }
+        v9fs_post_xattr_check(s, vs, err);
+        return;
+    }
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+}
+
+static void v9fs_xattrcreate(V9fsState *s, V9fsPDU *pdu)
+{
+    int flags;
+    int32_t fid;
+    ssize_t err = 0;
+    V9fsXattrState *vs;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    pdu_unmarshal(vs->pdu, vs->offset, "dsqd",
+                  &fid, &vs->name, &vs->size, &flags);
+
+    vs->file_fidp = lookup_fid(s, fid);
+    if (vs->file_fidp == NULL) {
+        err = -EINVAL;
+        goto out;
+    }
+
+    /* Make the file fid point to xattr */
+    vs->xattr_fidp = vs->file_fidp;
+    vs->xattr_fidp->fid_type = P9_FID_XATTR;
+    vs->xattr_fidp->fs.xattr.copied_len = 0;
+    vs->xattr_fidp->fs.xattr.len = vs->size;
+    vs->xattr_fidp->fs.xattr.flags = flags;
+    v9fs_string_init(&vs->xattr_fidp->fs.xattr.name);
+    v9fs_string_copy(&vs->xattr_fidp->fs.xattr.name, &vs->name);
+    if (vs->size)
+        vs->xattr_fidp->fs.xattr.value = qemu_malloc(vs->size);
+    else
+        vs->xattr_fidp->fs.xattr.value = NULL;
+
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->name);
+    qemu_free(vs);
+}
+
+static void v9fs_readlink_post_readlink(V9fsState *s, V9fsReadLinkState *vs,
+                                                    int err)
+{
+    if (err < 0) {
+        err = -errno;
+        goto out;
+    }
+    vs->offset += pdu_marshal(vs->pdu, vs->offset, "s", &vs->target);
+    err = vs->offset;
+out:
+    complete_pdu(s, vs->pdu, err);
+    v9fs_string_free(&vs->target);
+    qemu_free(vs);
+}
+
+static void v9fs_readlink(V9fsState *s, V9fsPDU *pdu)
+{
+    int32_t fid;
+    V9fsReadLinkState *vs;
+    int err = 0;
+    V9fsFidState *fidp;
+
+    vs = qemu_malloc(sizeof(*vs));
+    vs->pdu = pdu;
+    vs->offset = 7;
+
+    pdu_unmarshal(vs->pdu, vs->offset, "d", &fid);
+
+    fidp = lookup_fid(s, fid);
+    if (fidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+
+    v9fs_string_init(&vs->target);
+    err = v9fs_do_readlink(s, &fidp->path, &vs->target);
+    v9fs_readlink_post_readlink(s, vs, err);
+    return;
+out:
+    complete_pdu(s, vs->pdu, err);
+    qemu_free(vs);
+}
+
 typedef void (pdu_handler_t)(V9fsState *s, V9fsPDU *pdu);
 
 static pdu_handler_t *pdu_handlers[] = {
+    [P9_TREADDIR] = v9fs_readdir,
+    [P9_TSTATFS] = v9fs_statfs,
+    [P9_TGETATTR] = v9fs_getattr,
+    [P9_TSETATTR] = v9fs_setattr,
+    [P9_TXATTRWALK] = v9fs_xattrwalk,
+    [P9_TXATTRCREATE] = v9fs_xattrcreate,
+    [P9_TMKNOD] = v9fs_mknod,
+    [P9_TRENAME] = v9fs_rename,
+    [P9_TLOCK] = v9fs_lock,
+    [P9_TGETLOCK] = v9fs_getlock,
+    [P9_TREADLINK] = v9fs_readlink,
+    [P9_TMKDIR] = v9fs_mkdir,
     [P9_TVERSION] = v9fs_version,
+    [P9_TLOPEN] = v9fs_open,
     [P9_TATTACH] = v9fs_attach,
     [P9_TSTAT] = v9fs_stat,
     [P9_TWALK] = v9fs_walk,
     [P9_TCLUNK] = v9fs_clunk,
+    [P9_TFSYNC] = v9fs_fsync,
     [P9_TOPEN] = v9fs_open,
     [P9_TREAD] = v9fs_read,
 #if 0
     [P9_TAUTH] = v9fs_auth,
 #endif
     [P9_TFLUSH] = v9fs_flush,
+    [P9_TLINK] = v9fs_link,
+    [P9_TSYMLINK] = v9fs_symlink,
     [P9_TCREATE] = v9fs_create,
+    [P9_TLCREATE] = v9fs_lcreate,
     [P9_TWRITE] = v9fs_write,
     [P9_TWSTAT] = v9fs_wstat,
     [P9_TREMOVE] = v9fs_remove,
@@ -2252,8 +3676,8 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
 
     if (!fse) {
         /* We don't have a fsdev identified by fsdev_id */
-        fprintf(stderr, "Virtio-9p device couldn't find fsdev "
-                    "with the id %s\n", conf->fsdev_id);
+        fprintf(stderr, "Virtio-9p device couldn't find fsdev with the "
+                "id = %s\n", conf->fsdev_id ? conf->fsdev_id : "NULL");
         exit(1);
     }
 
@@ -2268,17 +3692,26 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
     if (!strcmp(fse->security_model, "passthrough")) {
         /* Files on the Fileserver set to client user credentials */
         s->ctx.fs_sm = SM_PASSTHROUGH;
+        s->ctx.xops = passthrough_xattr_ops;
     } else if (!strcmp(fse->security_model, "mapped")) {
         /* Files on the fileserver are set to QEMU credentials.
          * Client user credentials are saved in extended attributes.
          */
         s->ctx.fs_sm = SM_MAPPED;
+        s->ctx.xops = mapped_xattr_ops;
+    } else if (!strcmp(fse->security_model, "none")) {
+        /*
+         * Files on the fileserver are set to QEMU credentials.
+         */
+        s->ctx.fs_sm = SM_NONE;
+        s->ctx.xops = none_xattr_ops;
     } else {
-        /* user haven't specified a correct security option */
-        fprintf(stderr, "one of the following must be specified as the"
+        fprintf(stderr, "Default to security_model=none. You may want"
+                " enable advanced security model using "
                 "security option:\n\t security_model=passthrough \n\t "
                 "security_model=mapped\n");
-        return NULL;
+        s->ctx.fs_sm = SM_NONE;
+        s->ctx.xops = none_xattr_ops;
     }
 
     if (lstat(fse->path, &stat)) {
diff --git a/hw/virtio-9p.h b/hw/virtio-9p.h
index 67f808761f..6c233192e3 100644
--- a/hw/virtio-9p.h
+++ b/hw/virtio-9p.h
@@ -13,6 +13,42 @@
 #define VIRTIO_9P_MOUNT_TAG 0
 
 enum {
+    P9_TLERROR = 6,
+    P9_RLERROR,
+    P9_TSTATFS = 8,
+    P9_RSTATFS,
+    P9_TLOPEN = 12,
+    P9_RLOPEN,
+    P9_TLCREATE = 14,
+    P9_RLCREATE,
+    P9_TSYMLINK = 16,
+    P9_RSYMLINK,
+    P9_TMKNOD = 18,
+    P9_RMKNOD,
+    P9_TRENAME = 20,
+    P9_RRENAME,
+    P9_TREADLINK = 22,
+    P9_RREADLINK,
+    P9_TGETATTR = 24,
+    P9_RGETATTR,
+    P9_TSETATTR = 26,
+    P9_RSETATTR,
+    P9_TXATTRWALK = 30,
+    P9_RXATTRWALK,
+    P9_TXATTRCREATE = 32,
+    P9_RXATTRCREATE,
+    P9_TREADDIR = 40,
+    P9_RREADDIR,
+    P9_TFSYNC = 50,
+    P9_RFSYNC,
+    P9_TLOCK = 52,
+    P9_RLOCK,
+    P9_TGETLOCK = 54,
+    P9_RGETLOCK,
+    P9_TLINK = 70,
+    P9_RLINK,
+    P9_TMKDIR = 72,
+    P9_RMKDIR,
     P9_TVERSION = 100,
     P9_RVERSION,
     P9_TAUTH = 102,
@@ -57,10 +93,21 @@ enum {
     P9_QTFILE = 0x00,
 };
 
+enum p9_proto_version {
+    V9FS_PROTO_2000U = 0x01,
+    V9FS_PROTO_2000L = 0x02,
+};
+
 #define P9_NOTAG    (u16)(~0)
 #define P9_NOFID    (u32)(~0)
 #define P9_MAXWELEM 16
 
+/*
+ * ample room for Twrite/Rread header
+ * size[4] Tread/Twrite tag[2] fid[4] offset[8] count[4]
+ */
+#define P9_IOHDRSZ 24
+
 typedef struct V9fsPDU V9fsPDU;
 
 struct V9fsPDU
@@ -122,12 +169,32 @@ typedef struct V9fsStat
     int32_t n_muid;
 } V9fsStat;
 
+enum {
+    P9_FID_NONE = 0,
+    P9_FID_FILE,
+    P9_FID_DIR,
+    P9_FID_XATTR,
+};
+
+typedef struct V9fsXattr
+{
+    int64_t copied_len;
+    int64_t len;
+    void *value;
+    V9fsString name;
+    int flags;
+} V9fsXattr;
+
 struct V9fsFidState
 {
+    int fid_type;
     int32_t fid;
     V9fsString path;
-    int fd;
-    DIR *dir;
+    union {
+	int fd;
+	DIR *dir;
+	V9fsXattr xattr;
+    } fs;
     uid_t uid;
     V9fsFidState *next;
 };
@@ -144,6 +211,8 @@ typedef struct V9fsState
     uint16_t tag_len;
     uint8_t *tag;
     size_t config_size;
+    enum p9_proto_version proto_version;
+    int32_t msize;
 } V9fsState;
 
 typedef struct V9fsCreateState {
@@ -157,8 +226,20 @@ typedef struct V9fsCreateState {
     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;
@@ -167,6 +248,37 @@ typedef struct V9fsStatState {
     struct stat stbuf;
 } V9fsStatState;
 
+typedef struct V9fsStatDotl {
+    uint64_t st_result_mask;
+    V9fsQID qid;
+    uint32_t st_mode;
+    uint32_t st_uid;
+    uint32_t st_gid;
+    uint64_t st_nlink;
+    uint64_t st_rdev;
+    uint64_t st_size;
+    uint64_t st_blksize;
+    uint64_t st_blocks;
+    uint64_t st_atime_sec;
+    uint64_t st_atime_nsec;
+    uint64_t st_mtime_sec;
+    uint64_t st_mtime_nsec;
+    uint64_t st_ctime_sec;
+    uint64_t st_ctime_nsec;
+    uint64_t st_btime_sec;
+    uint64_t st_btime_nsec;
+    uint64_t st_gen;
+    uint64_t st_data_version;
+} V9fsStatDotl;
+
+typedef struct V9fsStatStateDotl {
+    V9fsPDU *pdu;
+    size_t offset;
+    V9fsStatDotl v9stat_dotl;
+    struct stat stbuf;
+} V9fsStatStateDotl;
+
+
 typedef struct V9fsWalkState {
     V9fsPDU *pdu;
     size_t offset;
@@ -183,10 +295,11 @@ typedef struct V9fsWalkState {
 typedef struct V9fsOpenState {
     V9fsPDU *pdu;
     size_t offset;
-    int8_t mode;
+    int32_t mode;
     V9fsFidState *fidp;
     V9fsQID qid;
     struct stat stbuf;
+    int iounit;
 } V9fsOpenState;
 
 typedef struct V9fsReadState {
@@ -235,9 +348,41 @@ typedef struct V9fsWstatState
     V9fsStat v9stat;
     V9fsFidState *fidp;
     struct stat stbuf;
-    V9fsString nname;
 } 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;
+    int32_t mode;
+    int32_t uid;
+    int32_t gid;
+    int64_t size;
+    int64_t atime_sec;
+    int64_t atime_nsec;
+    int64_t mtime_sec;
+    int64_t mtime_nsec;
+} V9fsIattr;
+
+typedef struct V9fsSetattrState
+{
+    V9fsPDU *pdu;
+    size_t offset;
+    V9fsIattr v9iattr;
+    V9fsFidState *fidp;
+} V9fsSetattrState;
+
 struct virtio_9p_config
 {
     /* number of characters in tag */
@@ -246,6 +391,110 @@ struct virtio_9p_config
     uint8_t tag[0];
 } __attribute__((packed));
 
+typedef struct V9fsStatfs
+{
+    uint32_t f_type;
+    uint32_t f_bsize;
+    uint64_t f_blocks;
+    uint64_t f_bfree;
+    uint64_t f_bavail;
+    uint64_t f_files;
+    uint64_t f_ffree;
+    uint64_t fsid_val;
+    uint32_t f_namelen;
+} V9fsStatfs;
+
+typedef struct V9fsStatfsState {
+    V9fsPDU *pdu;
+    size_t offset;
+    int32_t fid;
+    V9fsStatfs v9statfs;
+    V9fsFidState *fidp;
+    struct statfs stbuf;
+} V9fsStatfsState;
+
+typedef struct V9fsMkState {
+    V9fsPDU *pdu;
+    size_t offset;
+    V9fsQID qid;
+    struct stat stbuf;
+    V9fsString name;
+    V9fsString fullname;
+} V9fsMkState;
+
+typedef struct V9fsRenameState {
+    V9fsPDU *pdu;
+    V9fsFidState *fidp;
+    size_t offset;
+    int32_t newdirfid;
+    V9fsString name;
+} V9fsRenameState;
+
+typedef struct V9fsXattrState
+{
+    V9fsPDU *pdu;
+    size_t offset;
+    V9fsFidState *file_fidp;
+    V9fsFidState *xattr_fidp;
+    V9fsString name;
+    int64_t size;
+    int flags;
+    void *value;
+} V9fsXattrState;
+
+#define P9_LOCK_SUCCESS 0
+#define P9_LOCK_BLOCKED 1
+#define P9_LOCK_ERROR 2
+#define P9_LOCK_GRACE 3
+
+#define P9_LOCK_FLAGS_BLOCK 1
+#define P9_LOCK_FLAGS_RECLAIM 2
+
+typedef struct V9fsFlock
+{
+    uint8_t type;
+    uint32_t flags;
+    uint64_t start; /* absolute offset */
+    uint64_t length;
+    uint32_t proc_id;
+    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;
+    uint64_t start; /* absolute offset */
+    uint64_t length;
+    uint32_t proc_id;
+    V9fsString client_id;
+} V9fsGetlock;
+
+typedef struct V9fsGetlockState
+{
+    V9fsPDU *pdu;
+    size_t offset;
+    struct stat stbuf;
+    V9fsFidState *fidp;
+    V9fsGetlock *glock;
+} V9fsGetlockState;
+
+typedef struct V9fsReadLinkState
+{
+    V9fsPDU *pdu;
+    size_t offset;
+    V9fsString target;
+} V9fsReadLinkState;
+
 extern size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count,
                             size_t offset, size_t size, int pack);
 
diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c
index 9fe3886b0f..8adddeaa53 100644
--- a/hw/virtio-balloon.c
+++ b/hw/virtio-balloon.c
@@ -29,6 +29,10 @@
 #include <sys/mman.h>
 #endif
 
+/* Disable guest-provided stats by now (https://bugzilla.redhat.com/show_bug.cgi?id=623903) */
+#define ENABLE_GUEST_STATS   0
+
+
 typedef struct VirtIOBalloon
 {
     VirtIODevice vdev;
@@ -51,8 +55,8 @@ static void balloon_page(void *addr, int deflate)
 {
 #if defined(__linux__)
     if (!kvm_enabled() || kvm_has_sync_mmu())
-        madvise(addr, TARGET_PAGE_SIZE,
-                deflate ? MADV_WILLNEED : MADV_DONTNEED);
+        qemu_madvise(addr, TARGET_PAGE_SIZE,
+                deflate ? QEMU_MADV_WILLNEED : QEMU_MADV_DONTNEED);
 #endif
 }
 
@@ -83,12 +87,14 @@ static QObject *get_stats_qobject(VirtIOBalloon *dev)
                                   VIRTIO_BALLOON_PFN_SHIFT);
 
     stat_put(dict, "actual", actual);
+#if ENABLE_GUEST_STATS
     stat_put(dict, "mem_swapped_in", dev->stats[VIRTIO_BALLOON_S_SWAP_IN]);
     stat_put(dict, "mem_swapped_out", dev->stats[VIRTIO_BALLOON_S_SWAP_OUT]);
     stat_put(dict, "major_page_faults", dev->stats[VIRTIO_BALLOON_S_MAJFLT]);
     stat_put(dict, "minor_page_faults", dev->stats[VIRTIO_BALLOON_S_MINFLT]);
     stat_put(dict, "free_mem", dev->stats[VIRTIO_BALLOON_S_MEMFREE]);
     stat_put(dict, "total_mem", dev->stats[VIRTIO_BALLOON_S_MEMTOT]);
+#endif
 
     return QOBJECT(dict);
 }
@@ -214,7 +220,7 @@ static void virtio_balloon_to_target(void *opaque, ram_addr_t target,
         }
         dev->stats_callback = cb;
         dev->stats_opaque_callback_data = cb_data; 
-        if (dev->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ)) {
+        if (ENABLE_GUEST_STATS && (dev->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ))) {
             virtqueue_push(dev->svq, &dev->stats_vq_elem, dev->stats_vq_offset);
             virtio_notify(&dev->vdev, dev->svq);
         } else {
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index 8747634fbe..a1df26dbcf 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -12,6 +12,9 @@
  */
 
 #include <qemu-common.h>
+#include "qemu-error.h"
+#include "trace.h"
+#include "blockdev.h"
 #include "virtio-blk.h"
 #ifdef __linux__
 # include <scsi/sg.h>
@@ -27,6 +30,7 @@ typedef struct VirtIOBlock
     BlockConf *conf;
     unsigned short sector_mask;
     char sn[BLOCK_SERIAL_STRLEN];
+    DeviceState *qdev;
 } VirtIOBlock;
 
 static VirtIOBlock *to_virtio_blk(VirtIODevice *vdev)
@@ -49,6 +53,8 @@ static void virtio_blk_req_complete(VirtIOBlockReq *req, int status)
 {
     VirtIOBlock *s = req->dev;
 
+    trace_virtio_blk_req_complete(req, status);
+
     req->in->status = status;
     virtqueue_push(s->vq, &req->elem, req->qiov.size + sizeof(*req->in));
     virtio_notify(&s->vdev, s->vq);
@@ -85,6 +91,8 @@ static void virtio_blk_rw_complete(void *opaque, int ret)
 {
     VirtIOBlockReq *req = opaque;
 
+    trace_virtio_blk_rw_complete(req, ret);
+
     if (ret) {
         int is_read = !(req->out->type & VIRTIO_BLK_T_OUT);
         if (virtio_blk_handle_rw_error(req, -ret, is_read))
@@ -267,6 +275,8 @@ static void virtio_blk_handle_write(VirtIOBlockReq *req, MultiReqBuffer *mrb)
 {
     BlockRequest *blkreq;
 
+    trace_virtio_blk_handle_write(req, req->out->sector, req->qiov.size / 512);
+
     if (req->out->sector & req->dev->sector_mask) {
         virtio_blk_rw_complete(req, -EIO);
         return;
@@ -478,6 +488,11 @@ static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id)
         qemu_get_buffer(f, (unsigned char*)&req->elem, sizeof(req->elem));
         req->next = s->rq;
         s->rq = req;
+
+        virtqueue_map_sg(req->elem.in_sg, req->elem.in_addr,
+            req->elem.in_num, 1);
+        virtqueue_map_sg(req->elem.out_sg, req->elem.out_addr,
+            req->elem.out_num, 0);
     }
 
     return 0;
@@ -490,6 +505,15 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf)
     static int virtio_blk_id;
     DriveInfo *dinfo;
 
+    if (!conf->bs) {
+        error_report("virtio-blk-pci: drive property not set");
+        return NULL;
+    }
+    if (!bdrv_is_inserted(conf->bs)) {
+        error_report("Device needs media, but drive is empty");
+        return NULL;
+    }
+
     s = (VirtIOBlock *)virtio_common_init("virtio-blk", VIRTIO_ID_BLOCK,
                                           sizeof(struct virtio_blk_config),
                                           sizeof(VirtIOBlock));
@@ -512,9 +536,17 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf)
     s->vq = virtio_add_queue(&s->vdev, 128, virtio_blk_handle_output);
 
     qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s);
+    s->qdev = dev;
     register_savevm(dev, "virtio-blk", virtio_blk_id++, 2,
                     virtio_blk_save, virtio_blk_load, s);
     bdrv_set_removable(s->bs, 0);
+    s->bs->buffer_alignment = conf->logical_block_size;
 
     return &s->vdev;
 }
+
+void virtio_blk_exit(VirtIODevice *vdev)
+{
+    VirtIOBlock *s = to_virtio_blk(vdev);
+    unregister_savevm(s->qdev, "virtio-blk", s);
+}
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index 075f72df2d..7e1688cf69 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -36,7 +36,10 @@ typedef struct VirtIONet
     VirtQueue *ctrl_vq;
     NICState *nic;
     QEMUTimer *tx_timer;
-    int tx_timer_active;
+    QEMUBH *tx_bh;
+    uint32_t tx_timeout;
+    int32_t tx_burst;
+    int tx_waiting;
     uint32_t has_vnet_hdr;
     uint8_t has_ufo;
     struct {
@@ -51,6 +54,7 @@ typedef struct VirtIONet
     uint8_t nouni;
     uint8_t nobcast;
     uint8_t vhost_started;
+    bool vm_running;
     VMChangeStateEntry *vmstate;
     struct {
         int in_use;
@@ -95,6 +99,38 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config)
     }
 }
 
+static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
+{
+    VirtIONet *n = to_virtio_net(vdev);
+    if (!n->nic->nc.peer) {
+        return;
+    }
+    if (n->nic->nc.peer->info->type != NET_CLIENT_TYPE_TAP) {
+        return;
+    }
+
+    if (!tap_get_vhost_net(n->nic->nc.peer)) {
+        return;
+    }
+    if (!!n->vhost_started == ((status & VIRTIO_CONFIG_S_DRIVER_OK) &&
+                               (n->status & VIRTIO_NET_S_LINK_UP) &&
+                               n->vm_running)) {
+        return;
+    }
+    if (!n->vhost_started) {
+        int r = vhost_net_start(tap_get_vhost_net(n->nic->nc.peer), &n->vdev);
+        if (r < 0) {
+            fprintf(stderr, "unable to start vhost net: %d: "
+                    "falling back on userspace virtio\n", -r);
+        } else {
+            n->vhost_started = 1;
+        }
+    } else {
+        vhost_net_stop(tap_get_vhost_net(n->nic->nc.peer), &n->vdev);
+        n->vhost_started = 0;
+    }
+}
+
 static void virtio_net_set_link_status(VLANClientState *nc)
 {
     VirtIONet *n = DO_UPCAST(NICState, nc, nc)->opaque;
@@ -107,6 +143,8 @@ static void virtio_net_set_link_status(VLANClientState *nc)
 
     if (n->status != old_status)
         virtio_notify_config(&n->vdev);
+
+    virtio_net_set_status(&n->vdev, n->vdev.status);
 }
 
 static void virtio_net_reset(VirtIODevice *vdev)
@@ -120,10 +158,6 @@ static void virtio_net_reset(VirtIODevice *vdev)
     n->nomulti = 0;
     n->nouni = 0;
     n->nobcast = 0;
-    if (n->vhost_started) {
-        vhost_net_stop(tap_get_vhost_net(n->nic->nc.peer), vdev);
-        n->vhost_started = 0;
-    }
 
     /* Flush any MAC and VLAN filter table state */
     n->mac_table.in_use = 0;
@@ -619,7 +653,7 @@ static ssize_t virtio_net_receive(VLANClientState *nc, const uint8_t *buf, size_
     return size;
 }
 
-static void virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq);
+static int32_t virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq);
 
 static void virtio_net_tx_complete(VLANClientState *nc, ssize_t len)
 {
@@ -635,16 +669,18 @@ static void virtio_net_tx_complete(VLANClientState *nc, ssize_t len)
 }
 
 /* TX */
-static void virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq)
+static int32_t virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq)
 {
     VirtQueueElement elem;
+    int32_t num_packets = 0;
 
-    if (!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK))
-        return;
+    if (!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) {
+        return num_packets;
+    }
 
     if (n->async_tx.elem.out_num) {
         virtio_queue_set_notification(n->tx_vq, 0);
-        return;
+        return num_packets;
     }
 
     while (virtqueue_pop(vq, &elem)) {
@@ -681,38 +717,55 @@ static void virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq)
             virtio_queue_set_notification(n->tx_vq, 0);
             n->async_tx.elem = elem;
             n->async_tx.len  = len;
-            return;
+            return -EBUSY;
         }
 
         len += ret;
 
         virtqueue_push(vq, &elem, len);
         virtio_notify(&n->vdev, vq);
+
+        if (++num_packets >= n->tx_burst) {
+            break;
+        }
     }
+    return num_packets;
 }
 
-static void virtio_net_handle_tx(VirtIODevice *vdev, VirtQueue *vq)
+static void virtio_net_handle_tx_timer(VirtIODevice *vdev, VirtQueue *vq)
 {
     VirtIONet *n = to_virtio_net(vdev);
 
-    if (n->tx_timer_active) {
+    if (n->tx_waiting) {
         virtio_queue_set_notification(vq, 1);
         qemu_del_timer(n->tx_timer);
-        n->tx_timer_active = 0;
+        n->tx_waiting = 0;
         virtio_net_flush_tx(n, vq);
     } else {
         qemu_mod_timer(n->tx_timer,
-                       qemu_get_clock(vm_clock) + TX_TIMER_INTERVAL);
-        n->tx_timer_active = 1;
+                       qemu_get_clock(vm_clock) + n->tx_timeout);
+        n->tx_waiting = 1;
         virtio_queue_set_notification(vq, 0);
     }
 }
 
+static void virtio_net_handle_tx_bh(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtIONet *n = to_virtio_net(vdev);
+
+    if (unlikely(n->tx_waiting)) {
+        return;
+    }
+    virtio_queue_set_notification(vq, 0);
+    qemu_bh_schedule(n->tx_bh);
+    n->tx_waiting = 1;
+}
+
 static void virtio_net_tx_timer(void *opaque)
 {
     VirtIONet *n = opaque;
 
-    n->tx_timer_active = 0;
+    n->tx_waiting = 0;
 
     /* Just in case the driver is not ready on more */
     if (!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK))
@@ -722,20 +775,52 @@ static void virtio_net_tx_timer(void *opaque)
     virtio_net_flush_tx(n, n->tx_vq);
 }
 
-static void virtio_net_save(QEMUFile *f, void *opaque)
+static void virtio_net_tx_bh(void *opaque)
 {
     VirtIONet *n = opaque;
+    int32_t ret;
 
-    if (n->vhost_started) {
-        /* TODO: should we really stop the backend?
-         * If we don't, it might keep writing to memory. */
-        vhost_net_stop(tap_get_vhost_net(n->nic->nc.peer), &n->vdev);
-        n->vhost_started = 0;
+    n->tx_waiting = 0;
+
+    /* Just in case the driver is not ready on more */
+    if (unlikely(!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)))
+        return;
+
+    ret = virtio_net_flush_tx(n, n->tx_vq);
+    if (ret == -EBUSY) {
+        return; /* Notification re-enable handled by tx_complete */
     }
+
+    /* If we flush a full burst of packets, assume there are
+     * more coming and immediately reschedule */
+    if (ret >= n->tx_burst) {
+        qemu_bh_schedule(n->tx_bh);
+        n->tx_waiting = 1;
+        return;
+    }
+
+    /* If less than a full burst, re-enable notification and flush
+     * anything that may have come in while we weren't looking.  If
+     * we find something, assume the guest is still active and reschedule */
+    virtio_queue_set_notification(n->tx_vq, 1);
+    if (virtio_net_flush_tx(n, n->tx_vq) > 0) {
+        virtio_queue_set_notification(n->tx_vq, 0);
+        qemu_bh_schedule(n->tx_bh);
+        n->tx_waiting = 1;
+    }
+}
+
+static void virtio_net_save(QEMUFile *f, void *opaque)
+{
+    VirtIONet *n = opaque;
+
+    /* At this point, backend must be stopped, otherwise
+     * it might keep writing to memory. */
+    assert(!n->vhost_started);
     virtio_save(&n->vdev, f);
 
     qemu_put_buffer(f, n->mac, ETH_ALEN);
-    qemu_put_be32(f, n->tx_timer_active);
+    qemu_put_be32(f, n->tx_waiting);
     qemu_put_be32(f, n->mergeable_rx_bufs);
     qemu_put_be16(f, n->status);
     qemu_put_byte(f, n->promisc);
@@ -764,7 +849,7 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
     virtio_load(&n->vdev, f);
 
     qemu_get_buffer(f, n->mac, ETH_ALEN);
-    n->tx_timer_active = qemu_get_be32(f);
+    n->tx_waiting = qemu_get_be32(f);
     n->mergeable_rx_bufs = qemu_get_be32(f);
 
     if (version_id >= 3)
@@ -840,9 +925,13 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
     }
     n->mac_table.first_multi = i;
 
-    if (n->tx_timer_active) {
-        qemu_mod_timer(n->tx_timer,
-                       qemu_get_clock(vm_clock) + TX_TIMER_INTERVAL);
+    if (n->tx_waiting) {
+        if (n->tx_timer) {
+            qemu_mod_timer(n->tx_timer,
+                           qemu_get_clock(vm_clock) + n->tx_timeout);
+        } else {
+            qemu_bh_schedule(n->tx_bh);
+        }
     }
     return 0;
 }
@@ -863,47 +952,18 @@ static NetClientInfo net_virtio_info = {
     .link_status_changed = virtio_net_set_link_status,
 };
 
-static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
-{
-    VirtIONet *n = to_virtio_net(vdev);
-    if (!n->nic->nc.peer) {
-        return;
-    }
-    if (n->nic->nc.peer->info->type != NET_CLIENT_TYPE_TAP) {
-        return;
-    }
-
-    if (!tap_get_vhost_net(n->nic->nc.peer)) {
-        return;
-    }
-    if (!!n->vhost_started == !!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
-        return;
-    }
-    if (status & VIRTIO_CONFIG_S_DRIVER_OK) {
-        int r = vhost_net_start(tap_get_vhost_net(n->nic->nc.peer), vdev);
-        if (r < 0) {
-            fprintf(stderr, "unable to start vhost net: %d: "
-                    "falling back on userspace virtio\n", -r);
-        } else {
-            n->vhost_started = 1;
-        }
-    } else {
-        vhost_net_stop(tap_get_vhost_net(n->nic->nc.peer), vdev);
-        n->vhost_started = 0;
-    }
-}
-
 static void virtio_net_vmstate_change(void *opaque, int running, int reason)
 {
     VirtIONet *n = opaque;
-    uint8_t status = running ? VIRTIO_CONFIG_S_DRIVER_OK : 0;
+    n->vm_running = running;
     /* This is called when vm is started/stopped,
-     * it will start/stop vhost backend if * appropriate
+     * it will start/stop vhost backend if appropriate
      * e.g. after migration. */
-    virtio_net_set_status(&n->vdev, n->vdev.status & status);
+    virtio_net_set_status(&n->vdev, n->vdev.status);
 }
 
-VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf)
+VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
+                              virtio_net_conf *net)
 {
     VirtIONet *n;
 
@@ -919,7 +979,22 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf)
     n->vdev.reset = virtio_net_reset;
     n->vdev.set_status = virtio_net_set_status;
     n->rx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_rx);
-    n->tx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_tx);
+
+    if (net->tx && strcmp(net->tx, "timer") && strcmp(net->tx, "bh")) {
+        fprintf(stderr, "virtio-net: "
+                "Unknown option tx=%s, valid options: \"timer\" \"bh\"\n",
+                net->tx);
+        fprintf(stderr, "Defaulting to \"bh\"\n");
+    }
+
+    if (net->tx && !strcmp(net->tx, "timer")) {
+        n->tx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_tx_timer);
+        n->tx_timer = qemu_new_timer(vm_clock, virtio_net_tx_timer, n);
+        n->tx_timeout = net->txtimer;
+    } else {
+        n->tx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_tx_bh);
+        n->tx_bh = qemu_bh_new(virtio_net_tx_bh, n);
+    }
     n->ctrl_vq = virtio_add_queue(&n->vdev, 64, virtio_net_handle_ctrl);
     qemu_macaddr_default_if_unset(&conf->macaddr);
     memcpy(&n->mac[0], &conf->macaddr, sizeof(n->mac));
@@ -929,8 +1004,8 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf)
 
     qemu_format_nic_info_str(&n->nic->nc, conf->macaddr.a);
 
-    n->tx_timer = qemu_new_timer(vm_clock, virtio_net_tx_timer, n);
-    n->tx_timer_active = 0;
+    n->tx_waiting = 0;
+    n->tx_burst = net->txburst;
     n->mergeable_rx_bufs = 0;
     n->promisc = 1; /* for compatibility */
 
@@ -951,9 +1026,8 @@ void virtio_net_exit(VirtIODevice *vdev)
     VirtIONet *n = DO_UPCAST(VirtIONet, vdev, vdev);
     qemu_del_vm_change_state_handler(n->vmstate);
 
-    if (n->vhost_started) {
-        vhost_net_stop(tap_get_vhost_net(n->nic->nc.peer), vdev);
-    }
+    /* This will stop vhost backend if appropriate. */
+    virtio_net_set_status(vdev, 0);
 
     qemu_purge_queued_packets(&n->nic->nc);
 
@@ -962,8 +1036,12 @@ void virtio_net_exit(VirtIODevice *vdev)
     qemu_free(n->mac_table.macs);
     qemu_free(n->vlans);
 
-    qemu_del_timer(n->tx_timer);
-    qemu_free_timer(n->tx_timer);
+    if (n->tx_timer) {
+        qemu_del_timer(n->tx_timer);
+        qemu_free_timer(n->tx_timer);
+    } else {
+        qemu_bh_delete(n->tx_bh);
+    }
 
     virtio_cleanup(&n->vdev);
     qemu_del_vlan_client(&n->nic->nc);
diff --git a/hw/virtio-net.h b/hw/virtio-net.h
index 235f1a9fa8..8af9a1ce55 100644
--- a/hw/virtio-net.h
+++ b/hw/virtio-net.h
@@ -49,6 +49,20 @@
 
 #define TX_TIMER_INTERVAL 150000 /* 150 us */
 
+/* Limit the number of packets that can be sent via a single flush
+ * of the TX queue.  This gives us a guaranteed exit condition and
+ * ensures fairness in the io path.  256 conveniently matches the
+ * length of the TX queue and shows a good balance of performance
+ * and latency. */
+#define TX_BURST 256
+
+typedef struct virtio_net_conf
+{
+    uint32_t txtimer;
+    int32_t txburst;
+    char *tx;
+} virtio_net_conf;
+
 /* Maximum packet size we can receive from tap device: header + 64k */
 #define VIRTIO_NET_MAX_BUFSIZE (sizeof(struct virtio_net_hdr) + (64 << 10))
 
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index c728fffd73..729917d891 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -24,6 +24,7 @@
 #include "net.h"
 #include "loader.h"
 #include "kvm.h"
+#include "blockdev.h"
 
 /* from Linux's linux/virtio_pci.h */
 
@@ -106,6 +107,7 @@ typedef struct {
 #endif
     /* Max. number of ports we can have for a the virtio-serial device */
     uint32_t max_virtserial_ports;
+    virtio_net_conf net;
 } VirtIOPCIProxy;
 
 /* virtio device */
@@ -449,6 +451,33 @@ static int virtio_pci_set_guest_notifier(void *opaque, int n, bool assign)
     return 0;
 }
 
+static int virtio_pci_set_guest_notifiers(void *opaque, bool assign)
+{
+    VirtIOPCIProxy *proxy = opaque;
+    VirtIODevice *vdev = proxy->vdev;
+    int r, n;
+
+    for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
+        if (!virtio_queue_get_num(vdev, n)) {
+            break;
+        }
+
+        r = virtio_pci_set_guest_notifier(opaque, n, assign);
+        if (r < 0) {
+            goto assign_error;
+        }
+    }
+
+    return 0;
+
+assign_error:
+    /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */
+    while (--n >= 0) {
+        virtio_pci_set_guest_notifier(opaque, n, !assign);
+    }
+    return r;
+}
+
 static int virtio_pci_set_host_notifier(void *opaque, int n, bool assign)
 {
     VirtIOPCIProxy *proxy = opaque;
@@ -486,7 +515,7 @@ static const VirtIOBindings virtio_pci_bindings = {
     .load_queue = virtio_pci_load_queue,
     .get_features = virtio_pci_get_features,
     .set_host_notifier = virtio_pci_set_host_notifier,
-    .set_guest_notifier = virtio_pci_set_guest_notifier,
+    .set_guest_notifiers = virtio_pci_set_guest_notifiers,
 };
 
 static void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev,
@@ -546,11 +575,10 @@ static int virtio_blk_init_pci(PCIDevice *pci_dev)
         proxy->class_code != PCI_CLASS_STORAGE_OTHER)
         proxy->class_code = PCI_CLASS_STORAGE_SCSI;
 
-    if (!proxy->block.bs) {
-        error_report("virtio-blk-pci: drive property not set");
+    vdev = virtio_blk_init(&pci_dev->qdev, &proxy->block);
+    if (!vdev) {
         return -1;
     }
-    vdev = virtio_blk_init(&pci_dev->qdev, &proxy->block);
     vdev->nvectors = proxy->nvectors;
     virtio_init_pci(proxy, vdev,
                     PCI_VENDOR_ID_REDHAT_QUMRANET,
@@ -570,6 +598,7 @@ static int virtio_blk_exit_pci(PCIDevice *pci_dev)
 {
     VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
 
+    virtio_blk_exit(proxy->vdev);
     blockdev_mark_auto_del(proxy->block.bs);
     return virtio_exit_pci(pci_dev);
 }
@@ -599,12 +628,20 @@ static int virtio_serial_init_pci(PCIDevice *pci_dev)
     return 0;
 }
 
+static int virtio_serial_exit_pci(PCIDevice *pci_dev)
+{
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+
+    virtio_serial_exit(proxy->vdev);
+    return virtio_exit_pci(pci_dev);
+}
+
 static int virtio_net_init_pci(PCIDevice *pci_dev)
 {
     VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
     VirtIODevice *vdev;
 
-    vdev = virtio_net_init(&pci_dev->qdev, &proxy->nic);
+    vdev = virtio_net_init(&pci_dev->qdev, &proxy->nic, &proxy->net);
 
     vdev->nvectors = proxy->nvectors;
     virtio_init_pci(proxy, vdev,
@@ -681,6 +718,11 @@ static PCIDeviceInfo virtio_info[] = {
             DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
             DEFINE_VIRTIO_NET_FEATURES(VirtIOPCIProxy, host_features),
             DEFINE_NIC_PROPERTIES(VirtIOPCIProxy, nic),
+            DEFINE_PROP_UINT32("x-txtimer", VirtIOPCIProxy,
+                               net.txtimer, TX_TIMER_INTERVAL),
+            DEFINE_PROP_INT32("x-txburst", VirtIOPCIProxy,
+                              net.txburst, TX_BURST),
+            DEFINE_PROP_STRING("tx", VirtIOPCIProxy, net.tx),
             DEFINE_PROP_END_OF_LIST(),
         },
         .qdev.reset = virtio_pci_reset,
@@ -689,7 +731,7 @@ static PCIDeviceInfo virtio_info[] = {
         .qdev.alias = "virtio-serial",
         .qdev.size = sizeof(VirtIOPCIProxy),
         .init      = virtio_serial_init_pci,
-        .exit      = virtio_exit_pci,
+        .exit      = virtio_serial_exit_pci,
         .qdev.props = (Property[]) {
             DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
                                DEV_NVECTORS_UNSPECIFIED),
diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
index 26d5841154..74ba5ec3d3 100644
--- a/hw/virtio-serial-bus.c
+++ b/hw/virtio-serial-bus.c
@@ -41,6 +41,8 @@ struct VirtIOSerial {
 
     VirtIOSerialBus *bus;
 
+    DeviceState *qdev;
+
     QTAILQ_HEAD(, VirtIOSerialPort) ports;
 
     /* bitmap for identifying active ports */
@@ -117,6 +119,7 @@ static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
     VirtQueueElement elem;
 
     assert(port || discard);
+    assert(virtio_queue_ready(vq));
 
     while ((discard || !port->throttled) && virtqueue_pop(vq, &elem)) {
         uint8_t *buf;
@@ -139,6 +142,9 @@ static void flush_queued_data(VirtIOSerialPort *port, bool discard)
 {
     assert(port);
 
+    if (!virtio_queue_ready(port->ovq)) {
+        return;
+    }
     do_flush_queued_data(port, port->ovq, &port->vser->vdev, discard);
 }
 
@@ -730,11 +736,19 @@ VirtIODevice *virtio_serial_init(DeviceState *dev, uint32_t max_nr_ports)
 {
     VirtIOSerial *vser;
     VirtIODevice *vdev;
-    uint32_t i;
+    uint32_t i, max_supported_ports;
 
     if (!max_nr_ports)
         return NULL;
 
+    /* Each port takes 2 queues, and one pair is for the control queue */
+    max_supported_ports = VIRTIO_PCI_QUEUE_MAX / 2 - 1;
+
+    if (max_nr_ports > max_supported_ports) {
+        error_report("maximum ports supported: %u", max_supported_ports);
+        return NULL;
+    }
+
     vdev = virtio_common_init("virtio-serial", VIRTIO_ID_CONSOLE,
                               sizeof(struct virtio_console_config),
                               sizeof(VirtIOSerial));
@@ -780,6 +794,8 @@ VirtIODevice *virtio_serial_init(DeviceState *dev, uint32_t max_nr_ports)
     vser->vdev.get_config = get_config;
     vser->vdev.set_config = set_config;
 
+    vser->qdev = dev;
+
     /*
      * Register for the savevm section with the virtio-console name
      * to preserve backward compat
@@ -789,3 +805,16 @@ VirtIODevice *virtio_serial_init(DeviceState *dev, uint32_t max_nr_ports)
 
     return vdev;
 }
+
+void virtio_serial_exit(VirtIODevice *vdev)
+{
+    VirtIOSerial *vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
+
+    unregister_savevm(vser->qdev, "virtio-console", vser);
+
+    qemu_free(vser->ivqs);
+    qemu_free(vser->ovqs);
+    qemu_free(vser->ports_map);
+
+    virtio_cleanup(vdev);
+}
diff --git a/hw/virtio.c b/hw/virtio.c
index 4475bb3e44..a2a657e132 100644
--- a/hw/virtio.c
+++ b/hw/virtio.c
@@ -13,6 +13,7 @@
 
 #include <inttypes.h>
 
+#include "trace.h"
 #include "virtio.h"
 #include "sysemu.h"
 
@@ -205,6 +206,8 @@ void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
     unsigned int offset;
     int i;
 
+    trace_virtqueue_fill(vq, elem, len, idx);
+
     offset = 0;
     for (i = 0; i < elem->in_num; i++) {
         size_t size = MIN(len - offset, elem->in_sg[i].iov_len);
@@ -232,6 +235,7 @@ void virtqueue_flush(VirtQueue *vq, unsigned int count)
 {
     /* Make sure buffer is written before we update index. */
     wmb();
+    trace_virtqueue_flush(vq, count);
     vring_used_idx_increment(vq, count);
     vq->inuse -= count;
 }
@@ -360,11 +364,26 @@ int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes)
     return 0;
 }
 
+void virtqueue_map_sg(struct iovec *sg, target_phys_addr_t *addr,
+    size_t num_sg, int is_write)
+{
+    unsigned int i;
+    target_phys_addr_t len;
+
+    for (i = 0; i < num_sg; i++) {
+        len = sg[i].iov_len;
+        sg[i].iov_base = cpu_physical_memory_map(addr[i], &len, is_write);
+        if (sg[i].iov_base == NULL || len != sg[i].iov_len) {
+            fprintf(stderr, "virtio: trying to map MMIO memory\n");
+            exit(1);
+        }
+    }
+}
+
 int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
 {
     unsigned int i, head, max;
     target_phys_addr_t desc_pa = vq->vring.desc;
-    target_phys_addr_t len;
 
     if (!virtqueue_num_heads(vq, vq->last_avail_idx))
         return 0;
@@ -388,28 +407,19 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
         i = 0;
     }
 
+    /* Collect all the descriptors */
     do {
         struct iovec *sg;
-        int is_write = 0;
 
         if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_WRITE) {
             elem->in_addr[elem->in_num] = vring_desc_addr(desc_pa, i);
             sg = &elem->in_sg[elem->in_num++];
-            is_write = 1;
-        } else
+        } else {
+            elem->out_addr[elem->out_num] = vring_desc_addr(desc_pa, i);
             sg = &elem->out_sg[elem->out_num++];
+        }
 
-        /* Grab the first descriptor, and check it's OK. */
         sg->iov_len = vring_desc_len(desc_pa, i);
-        len = sg->iov_len;
-
-        sg->iov_base = cpu_physical_memory_map(vring_desc_addr(desc_pa, i),
-                                               &len, is_write);
-
-        if (sg->iov_base == NULL || len != sg->iov_len) {
-            fprintf(stderr, "virtio: trying to map MMIO memory\n");
-            exit(1);
-        }
 
         /* If we've got too many, that implies a descriptor loop. */
         if ((elem->in_num + elem->out_num) > max) {
@@ -418,10 +428,15 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
         }
     } while ((i = virtqueue_next_desc(desc_pa, i, max)) != max);
 
+    /* Now map what we have collected */
+    virtqueue_map_sg(elem->in_sg, elem->in_addr, elem->in_num, 1);
+    virtqueue_map_sg(elem->out_sg, elem->out_addr, elem->out_num, 0);
+
     elem->index = head;
 
     vq->inuse++;
 
+    trace_virtqueue_pop(vq, elem, elem->in_num, elem->out_num);
     return elem->in_num + elem->out_num;
 }
 
@@ -443,6 +458,8 @@ void virtio_reset(void *opaque)
     VirtIODevice *vdev = opaque;
     int i;
 
+    virtio_set_status(vdev, 0);
+
     if (vdev->reset)
         vdev->reset(vdev);
 
@@ -560,6 +577,7 @@ int virtio_queue_get_num(VirtIODevice *vdev, int n)
 void virtio_queue_notify(VirtIODevice *vdev, int n)
 {
     if (n < VIRTIO_PCI_QUEUE_MAX && vdev->vq[n].vring.desc) {
+        trace_virtio_queue_notify(vdev, n, &vdev->vq[n]);
         vdev->vq[n].handle_output(vdev, &vdev->vq[n]);
     }
 }
@@ -597,6 +615,7 @@ VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
 
 void virtio_irq(VirtQueue *vq)
 {
+    trace_virtio_irq(vq);
     vq->vdev->isr |= 0x01;
     virtio_notify_vector(vq->vdev, vq->vector);
 }
@@ -609,6 +628,7 @@ void virtio_notify(VirtIODevice *vdev, VirtQueue *vq)
          (vq->inuse || vring_avail_idx(vq) != vq->last_avail_idx)))
         return;
 
+    trace_virtio_notify(vdev, vq);
     vdev->isr |= 0x01;
     virtio_notify_vector(vdev, vq->vector);
 }
@@ -661,6 +681,7 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f)
     uint32_t features;
     uint32_t supported_features =
         vdev->binding->get_features(vdev->binding_opaque);
+    uint16_t num_heads;
 
     if (vdev->binding->load_config) {
         ret = vdev->binding->load_config(vdev->binding_opaque, f);
@@ -693,6 +714,16 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f)
         if (vdev->vq[i].pa) {
             virtqueue_init(&vdev->vq[i]);
         }
+	num_heads = vring_avail_idx(&vdev->vq[i]) - vdev->vq[i].last_avail_idx;
+	/* Check it isn't doing very strange things with descriptor numbers. */
+	if (num_heads > vdev->vq[i].vring.num) {
+		fprintf(stderr, "VQ %d size 0x%x Guest index 0x%x "
+                        "inconsistent with Host index 0x%x: delta 0x%x\n",
+			i, vdev->vq[i].vring.num,
+                        vring_avail_idx(&vdev->vq[i]),
+                        vdev->vq[i].last_avail_idx, num_heads);
+		return -1;
+	}
         if (vdev->binding->load_queue) {
             ret = vdev->binding->load_queue(vdev->binding_opaque, i, f);
             if (ret)
diff --git a/hw/virtio.h b/hw/virtio.h
index e4306cd750..02fa312d3e 100644
--- a/hw/virtio.h
+++ b/hw/virtio.h
@@ -81,6 +81,7 @@ typedef struct VirtQueueElement
     unsigned int out_num;
     unsigned int in_num;
     target_phys_addr_t in_addr[VIRTQUEUE_MAX_SIZE];
+    target_phys_addr_t out_addr[VIRTQUEUE_MAX_SIZE];
     struct iovec in_sg[VIRTQUEUE_MAX_SIZE];
     struct iovec out_sg[VIRTQUEUE_MAX_SIZE];
 } VirtQueueElement;
@@ -92,7 +93,7 @@ typedef struct {
     int (*load_config)(void * opaque, QEMUFile *f);
     int (*load_queue)(void * opaque, int n, QEMUFile *f);
     unsigned (*get_features)(void * opaque);
-    int (*set_guest_notifier)(void * opaque, int n, bool assigned);
+    int (*set_guest_notifiers)(void * opaque, bool assigned);
     int (*set_host_notifier)(void * opaque, int n, bool assigned);
 } VirtIOBindings;
 
@@ -142,6 +143,8 @@ void virtqueue_flush(VirtQueue *vq, unsigned int count);
 void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
                     unsigned int len, unsigned int idx);
 
+void virtqueue_map_sg(struct iovec *sg, target_phys_addr_t *addr,
+    size_t num_sg, int is_write);
 int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem);
 int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes);
 
@@ -185,7 +188,9 @@ void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding,
 
 /* Base devices.  */
 VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf);
-VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf);
+struct virtio_net_conf;
+VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
+                              struct virtio_net_conf *net);
 VirtIODevice *virtio_serial_init(DeviceState *dev, uint32_t max_nr_ports);
 VirtIODevice *virtio_balloon_init(DeviceState *dev);
 #ifdef CONFIG_LINUX
@@ -194,6 +199,8 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf);
 
 
 void virtio_net_exit(VirtIODevice *vdev);
+void virtio_blk_exit(VirtIODevice *vdev);
+void virtio_serial_exit(VirtIODevice *vdev);
 
 #define DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) \
 	DEFINE_PROP_BIT("indirect_desc", _state, _field, \
diff --git a/hw/vmmouse.c b/hw/vmmouse.c
index f3593047e7..209711942f 100644
--- a/hw/vmmouse.c
+++ b/hw/vmmouse.c
@@ -100,16 +100,29 @@ static void vmmouse_mouse_event(void *opaque, int x, int y, int dz, int buttons_
     i8042_isa_mouse_fake_event(s->ps2_mouse);
 }
 
-static void vmmouse_update_handler(VMMouseState *s)
+static void vmmouse_remove_handler(VMMouseState *s)
 {
     if (s->entry) {
         qemu_remove_mouse_event_handler(s->entry);
         s->entry = NULL;
     }
-    if (s->status == 0)
+}
+
+static void vmmouse_update_handler(VMMouseState *s, int absolute)
+{
+    if (s->status != 0) {
+        return;
+    }
+    if (s->absolute != absolute) {
+        s->absolute = absolute;
+        vmmouse_remove_handler(s);
+    }
+    if (s->entry == NULL) {
         s->entry = qemu_add_mouse_event_handler(vmmouse_mouse_event,
                                                 s, s->absolute,
                                                 "vmmouse");
+        qemu_activate_mouse_event_handler(s->entry);
+    }
 }
 
 static void vmmouse_read_id(VMMouseState *s)
@@ -121,28 +134,25 @@ static void vmmouse_read_id(VMMouseState *s)
 
     s->queue[s->nb_queue++] = VMMOUSE_VERSION;
     s->status = 0;
-    vmmouse_update_handler(s);
 }
 
 static void vmmouse_request_relative(VMMouseState *s)
 {
     DPRINTF("vmmouse_request_relative()\n");
-    s->absolute = 0;
-    vmmouse_update_handler(s);
+    vmmouse_update_handler(s, 0);
 }
 
 static void vmmouse_request_absolute(VMMouseState *s)
 {
     DPRINTF("vmmouse_request_absolute()\n");
-    s->absolute = 1;
-    vmmouse_update_handler(s);
+    vmmouse_update_handler(s, 1);
 }
 
 static void vmmouse_disable(VMMouseState *s)
 {
     DPRINTF("vmmouse_disable()\n");
     s->status = 0xffff;
-    vmmouse_update_handler(s);
+    vmmouse_remove_handler(s);
 }
 
 static void vmmouse_data(VMMouseState *s, uint32_t *data, uint32_t size)
@@ -154,7 +164,7 @@ static void vmmouse_data(VMMouseState *s, uint32_t *data, uint32_t size)
     if (size == 0 || size > 6 || size > s->nb_queue) {
         printf("vmmouse: driver requested too much data %d\n", size);
         s->status = 0xffff;
-        vmmouse_update_handler(s);
+        vmmouse_remove_handler(s);
         return;
     }
 
@@ -239,7 +249,8 @@ static int vmmouse_post_load(void *opaque, int version_id)
 {
     VMMouseState *s = opaque;
 
-    vmmouse_update_handler(s);
+    vmmouse_remove_handler(s);
+    vmmouse_update_handler(s, s->absolute);
     return 0;
 }
 
diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
index 12bff480eb..3d25c14da9 100644
--- a/hw/vmware_vga.c
+++ b/hw/vmware_vga.c
@@ -519,11 +519,15 @@ static inline void vmsvga_cursor_define(struct vmsvga_state_s *s,
 
 #define CMD(f)	le32_to_cpu(s->cmd->f)
 
-static inline int vmsvga_fifo_empty(struct vmsvga_state_s *s)
+static inline int vmsvga_fifo_length(struct vmsvga_state_s *s)
 {
+    int num;
     if (!s->config || !s->enable)
-        return 1;
-    return (s->cmd->next_cmd == s->cmd->stop);
+        return 0;
+    num = CMD(next_cmd) - CMD(stop);
+    if (num < 0)
+        num += CMD(max) - CMD(min);
+    return num >> 2;
 }
 
 static inline uint32_t vmsvga_fifo_read_raw(struct vmsvga_state_s *s)
@@ -543,13 +547,23 @@ static inline uint32_t vmsvga_fifo_read(struct vmsvga_state_s *s)
 static void vmsvga_fifo_run(struct vmsvga_state_s *s)
 {
     uint32_t cmd, colour;
-    int args = 0;
+    int args, len;
     int x, y, dx, dy, width, height;
     struct vmsvga_cursor_definition_s cursor;
-    while (!vmsvga_fifo_empty(s))
+    uint32_t cmd_start;
+
+    len = vmsvga_fifo_length(s);
+    while (len > 0) {
+        /* May need to go back to the start of the command if incomplete */
+        cmd_start = s->cmd->stop;
+
         switch (cmd = vmsvga_fifo_read(s)) {
         case SVGA_CMD_UPDATE:
         case SVGA_CMD_UPDATE_VERBOSE:
+            len -= 5;
+            if (len < 0)
+                goto rewind;
+
             x = vmsvga_fifo_read(s);
             y = vmsvga_fifo_read(s);
             width = vmsvga_fifo_read(s);
@@ -558,6 +572,10 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s)
             break;
 
         case SVGA_CMD_RECT_FILL:
+            len -= 6;
+            if (len < 0)
+                goto rewind;
+
             colour = vmsvga_fifo_read(s);
             x = vmsvga_fifo_read(s);
             y = vmsvga_fifo_read(s);
@@ -567,10 +585,15 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s)
             vmsvga_fill_rect(s, colour, x, y, width, height);
             break;
 #else
+            args = 0;
             goto badcmd;
 #endif
 
         case SVGA_CMD_RECT_COPY:
+            len -= 7;
+            if (len < 0)
+                goto rewind;
+
             x = vmsvga_fifo_read(s);
             y = vmsvga_fifo_read(s);
             dx = vmsvga_fifo_read(s);
@@ -581,10 +604,15 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s)
             vmsvga_copy_rect(s, x, y, dx, dy, width, height);
             break;
 #else
+            args = 0;
             goto badcmd;
 #endif
 
         case SVGA_CMD_DEFINE_CURSOR:
+            len -= 8;
+            if (len < 0)
+                goto rewind;
+
             cursor.id = vmsvga_fifo_read(s);
             cursor.hot_x = vmsvga_fifo_read(s);
             cursor.hot_y = vmsvga_fifo_read(s);
@@ -593,11 +621,14 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s)
             vmsvga_fifo_read(s);
             cursor.bpp = vmsvga_fifo_read(s);
 
-	    if (SVGA_BITMAP_SIZE(x, y) > sizeof cursor.mask ||
-		SVGA_PIXMAP_SIZE(x, y, cursor.bpp) > sizeof cursor.image) {
-		    args = SVGA_BITMAP_SIZE(x, y) + SVGA_PIXMAP_SIZE(x, y, cursor.bpp);
-		    goto badcmd;
-	    }
+            args = SVGA_BITMAP_SIZE(x, y) + SVGA_PIXMAP_SIZE(x, y, cursor.bpp);
+            if (SVGA_BITMAP_SIZE(x, y) > sizeof cursor.mask ||
+                SVGA_PIXMAP_SIZE(x, y, cursor.bpp) > sizeof cursor.image)
+                    goto badcmd;
+
+            len -= args;
+            if (len < 0)
+                goto rewind;
 
             for (args = 0; args < SVGA_BITMAP_SIZE(x, y); args ++)
                 cursor.mask[args] = vmsvga_fifo_read_raw(s);
@@ -616,6 +647,10 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s)
          * for so we can avoid FIFO desync if driver uses them illegally.
          */
         case SVGA_CMD_DEFINE_ALPHA_CURSOR:
+            len -= 6;
+            if (len < 0)
+                goto rewind;
+
             vmsvga_fifo_read(s);
             vmsvga_fifo_read(s);
             vmsvga_fifo_read(s);
@@ -630,6 +665,10 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s)
             args = 7;
             goto badcmd;
         case SVGA_CMD_DRAW_GLYPH_CLIPPED:
+            len -= 4;
+            if (len < 0)
+                goto rewind;
+
             vmsvga_fifo_read(s);
             vmsvga_fifo_read(s);
             args = 7 + (vmsvga_fifo_read(s) >> 2);
@@ -650,13 +689,22 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s)
             break; /* Nop */
 
         default:
+            args = 0;
         badcmd:
+            len -= args;
+            if (len < 0)
+                goto rewind;
             while (args --)
                 vmsvga_fifo_read(s);
             printf("%s: Unknown command 0x%02x in SVGA command FIFO\n",
                             __FUNCTION__, cmd);
             break;
+
+        rewind:
+            s->cmd->stop = cmd_start;
+            break;
         }
+    }
 
     s->syncing = 0;
 }
@@ -809,11 +857,11 @@ static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value)
         s->invalidated = 1;
         s->vga.invalidate(&s->vga);
         if (s->enable) {
-	  s->fb_size = ((s->depth + 7) >> 3) * s->new_width * s->new_height;
-	  vga_dirty_log_stop(&s->vga);
-	} else {
-	  vga_dirty_log_start(&s->vga);
-	}
+            s->fb_size = ((s->depth + 7) >> 3) * s->new_width * s->new_height;
+            vga_dirty_log_stop(&s->vga);
+        } else {
+            vga_dirty_log_start(&s->vga);
+        }
         break;
 
     case SVGA_REG_WIDTH:
@@ -1255,7 +1303,7 @@ static int pci_vmsvga_initfn(PCIDevice *dev)
                     PCI_BASE_ADDRESS_MEM_PREFETCH, pci_vmsvga_map_mem);
 
     pci_register_bar(&s->card, 2, SVGA_FIFO_SIZE,
-		     PCI_BASE_ADDRESS_MEM_PREFETCH, pci_vmsvga_map_fifo);
+                    PCI_BASE_ADDRESS_MEM_PREFETCH, pci_vmsvga_map_fifo);
 
     vmsvga_init(&s->chip, VGA_RAM_SIZE);
 
diff --git a/hw/vt82c686.c b/hw/vt82c686.c
index a0c5747b59..cacc21767b 100644
--- a/hw/vt82c686.c
+++ b/hw/vt82c686.c
@@ -468,7 +468,6 @@ static int vt82c686b_pm_initfn(PCIDevice *dev)
     pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_VIA_ACPI);
     pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_OTHER);
     pci_config_set_revision(pci_conf, 0x40);
-    pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
 
     pci_set_word(pci_conf + PCI_COMMAND, 0);
     pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_FAST_BACK |
@@ -556,8 +555,6 @@ static int vt82c686b_initfn(PCIDevice *d)
     pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_ISA);
     pci_config_set_prog_interface(pci_conf, 0x0);
     pci_config_set_revision(pci_conf,0x40); /* Revision 4.0 */
-    pci_conf[PCI_HEADER_TYPE] =
-        PCI_HEADER_TYPE_NORMAL | PCI_HEADER_TYPE_MULTI_FUNCTION;
 
     wmask = d->wmask;
     for (i = 0x00; i < 0xff; i++) {
@@ -575,7 +572,7 @@ int vt82c686b_init(PCIBus *bus, int devfn)
 {
     PCIDevice *d;
 
-    d = pci_create_simple(bus, devfn, "VT82C686B");
+    d = pci_create_simple_multifunction(bus, devfn, true, "VT82C686B");
 
     return d->devfn;
 }
diff --git a/hw/watchdog.c b/hw/watchdog.c
index aebb08a0ee..e9dd56e229 100644
--- a/hw/watchdog.c
+++ b/hw/watchdog.c
@@ -66,7 +66,7 @@ int select_watchdog(const char *p)
     QLIST_FOREACH(model, &watchdog_list, entry) {
         if (strcasecmp(model->wdt_name, p) == 0) {
             /* add the device */
-            opts = qemu_opts_create(&qemu_device_opts, NULL, 0);
+            opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0);
             qemu_opt_set(opts, "driver", p);
             return 0;
         }
diff --git a/hw/wm8750.c b/hw/wm8750.c
index ce43c234ac..c9c674451b 100644
--- a/hw/wm8750.c
+++ b/hw/wm8750.c
@@ -171,7 +171,6 @@ static void wm8750_set_format(WM8750State *s)
     int i;
     struct audsettings in_fmt;
     struct audsettings out_fmt;
-    struct audsettings monoout_fmt;
 
     wm8750_out_flush(s);
 
@@ -212,10 +211,6 @@ static void wm8750_set_format(WM8750State *s)
     out_fmt.nchannels = 2;
     out_fmt.freq = s->dac_hz;
     out_fmt.fmt = AUD_FMT_S16;
-    monoout_fmt.endianness = 0;
-    monoout_fmt.nchannels = 1;
-    monoout_fmt.freq = s->rate->dac_hz;
-    monoout_fmt.fmt = AUD_FMT_S16;
 
     s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0],
                     CODEC ".speaker", s, wm8750_audio_out_cb, &out_fmt);
diff --git a/hw/xen_backend.h b/hw/xen_backend.h
index cc25f9d7db..1b428e3bf4 100644
--- a/hw/xen_backend.h
+++ b/hw/xen_backend.h
@@ -4,8 +4,6 @@
 #include "xen_common.h"
 #include "sysemu.h"
 #include "net.h"
-#include "block_int.h"
-#include "blockdev.h"
 
 /* ------------------------------------------------------------- */
 
@@ -86,7 +84,7 @@ int xen_be_bind_evtchn(struct XenDevice *xendev);
 void xen_be_unbind_evtchn(struct XenDevice *xendev);
 int xen_be_send_notify(struct XenDevice *xendev);
 void xen_be_printf(struct XenDevice *xendev, int msg_level, const char *fmt, ...)
-    __attribute__ ((format(printf, 3, 4)));
+    GCC_FMT_ATTR(3, 4);
 
 /* actual backend drivers */
 extern struct XenDevOps xen_console_ops;      /* xen_console.c     */
diff --git a/hw/xen_devconfig.c b/hw/xen_devconfig.c
index ea8f8c4c2d..8d50216c04 100644
--- a/hw/xen_devconfig.c
+++ b/hw/xen_devconfig.c
@@ -1,4 +1,6 @@
 #include "xen_backend.h"
+#include "blockdev.h"
+#include "block_int.h" /* XXX */
 
 /* ------------------------------------------------------------- */
 
diff --git a/hw/xen_disk.c b/hw/xen_disk.c
index 9a466f3cc1..134ac3388e 100644
--- a/hw/xen_disk.c
+++ b/hw/xen_disk.c
@@ -41,6 +41,7 @@
 #include "qemu-char.h"
 #include "xen_blkif.h"
 #include "xen_backend.h"
+#include "blockdev.h"
 
 /* ------------------------------------------------------------- */
 
diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c
index 586214d8ba..77a34bf111 100644
--- a/hw/xen_machine_pv.c
+++ b/hw/xen_machine_pv.c
@@ -28,6 +28,7 @@
 #include "boards.h"
 #include "xen_backend.h"
 #include "xen_domainbuild.h"
+#include "blockdev.h"
 
 static void xen_init_pv(ram_addr_t ram_size,
 			const char *boot_device,