[Spice-commits] 194 commits - .gitignore MAINTAINERS Makefile Makefile.objs Makefile.target async.c balloon.c balloon.h block.c block.h block/qcow.c block/qcow2-cluster.c block/qcow2-snapshot.c block/qcow2.c block/qcow2.h block/qed-table.c block/qed.c block/raw-posix.c block/raw-win32.c block/raw.c block/vpc.c block_int.h blockdev.c bsd-user/main.c configure coroutine-gthread.c coroutine-ucontext.c coroutine-win32.c cutils.c darwin-user/main.c darwin-user/signal.c dma.h exec-memory.h exec.c hmp-commands.hx hw/ac97.c hw/apb_pci.c hw/axis_dev88.c hw/bonito.c hw/bt-hid.c hw/cirrus_vga.c hw/cuda.c hw/e1000.c hw/eepro100.c hw/es1370.c hw/escc.c hw/escc.h hw/etraxfs.c hw/etraxfs.h hw/etraxfs_eth.c hw/fw_cfg.c hw/grackle_pci.c hw/gt64xxx.c hw/heathrow_pic.c hw/hid.c hw/hid.h hw/ide hw/ide.h hw/intel-hda.c hw/isa.h hw/isa_mmio.c hw/ivshmem.c hw/kvmclock.c hw/lance.c hw/lsi53c895a.c hw/mac_dbdma.c hw/mac_dbdma.h hw/mac_nvram.c hw/macio.c hw/milkymist-softusb.c hw/msix.c hw/msix.h hw/ne2000-i sa.c hw/ne2000.c hw/ne2000.h hw/openpic.c hw/openpic.h hw/pc.h hw/pc_piix.c hw/pci.c hw/pci.h hw/pci_host.c hw/pci_host.h hw/pci_internals.h hw/pcie_host.c hw/pcnet-pci.c hw/pcnet.h hw/piix_pci.c hw/ppc4xx_pci.c hw/ppc_mac.h hw/ppc_newworld.c hw/ppc_oldworld.c hw/ppc_prep.c hw/ppce500_pci.c hw/prep_pci.c hw/prep_pci.h hw/qdev.c hw/qxl-render.c hw/qxl.c hw/qxl.h hw/rtl8139.c hw/scsi-bus.c hw/scsi-defs.h hw/scsi-disk.c hw/scsi-generic.c hw/sh_pci.c hw/sun4u.c hw/unin_pci.c hw/usb-bt.c hw/usb-ccid.c hw/usb-ehci.c hw/usb-hid.c hw/usb-hub.c hw/usb-libhw.c hw/usb-msd.c hw/usb-musb.c hw/usb-net.c hw/usb-ohci.c hw/usb-serial.c hw/usb-uhci.c hw/usb-wacom.c hw/usb.c hw/usb.h hw/versatile_pci.c hw/vga-isa-mm.c hw/vga-isa.c hw/vga-pci.c hw/vga.c hw/vga_int.h hw/vhost.c hw/virtio-balloon.c hw/virtio-blk.c hw/virtio-net.c hw/virtio-pci.c hw/virtio-pci.h hw/virtio.c hw/virtio.h hw/vmware_vga.c hw/wdt_i6300esb.c hw/xen_platform.c iov.c iov.h kvm-all.c libcacard/Makefile linux-aio.c linux-us er/main.c memory.c memory.h migration.c net.c net/socket.c net/tap-bsd.c posix-aio-compat.c qemu-common.h qemu-coroutine-int.h qemu-coroutine-lock.c qemu-coroutine.c qemu-coroutine.h qemu-doc.texi slirp/arp_table.c slirp/bootp.c slirp/if.c slirp/main.h slirp/mbuf.c slirp/mbuf.h slirp/slirp.c slirp/slirp.h target-alpha/cpu.h target-alpha/helper.c target-alpha/op_helper.c target-arm/cpu.h target-arm/helper.c target-arm/op_helper.c target-arm/translate.c target-cris/cpu.h target-cris/helper.c target-cris/op_helper.c target-i386/cpu.h target-i386/cpuid.c target-i386/helper.c target-i386/kvm.c target-i386/op_helper.c target-lm32/cpu.h target-lm32/helper.c target-lm32/op_helper.c target-m68k/cpu.h target-m68k/helper.c target-m68k/op_helper.c target-microblaze/cpu.h target-microblaze/helper.c target-microblaze/op_helper.c target-mips/cpu.h target-mips/helper.c target-mips/op_helper.c target-ppc/cpu.h target-ppc/helper.c target-ppc/op_helper.c target-s390x/cpu.h target-s390x/helper. c target-s390x/op_helper.c target-sh4/cpu.h target-sh4/helper.c target-sh4/op_helper.c target-sparc/cpu.h target-sparc/helper.c target-sparc/op_helper.c target-sparc/translate.c target-unicore32/cpu.h target-unicore32/helper.c tcg/optimize.c tcg/tcg.h test-coroutine.c trace-events ui/sdl.c ui/spice-display.c ui/spice-display.h usb-bsd.c usb-linux.c usb-redir.c user-exec.c vl.c

Gerd Hoffmann kraxel at kemper.freedesktop.org
Thu Aug 11 00:06:28 PDT 2011


 .gitignore                    |    1 
 MAINTAINERS                   |   15 -
 Makefile                      |    4 
 Makefile.objs                 |   15 +
 Makefile.target               |    1 
 async.c                       |   98 -------
 balloon.c                     |   61 ++--
 balloon.h                     |   12 
 block.c                       |  310 ++++++++++++++++++++--
 block.h                       |    7 
 block/qcow.c                  |  180 ++++---------
 block/qcow2-cluster.c         |   26 -
 block/qcow2-snapshot.c        |   16 -
 block/qcow2.c                 |  240 ++++++-----------
 block/qcow2.h                 |    5 
 block/qed-table.c             |   14 -
 block/qed.c                   |    4 
 block/raw-posix.c             |   39 +-
 block/raw-win32.c             |   35 --
 block/raw.c                   |    7 
 block/vpc.c                   |    8 
 block_int.h                   |   10 
 blockdev.c                    |   17 -
 bsd-user/main.c               |    3 
 configure                     |   93 ++++--
 coroutine-gthread.c           |  131 +++++++++
 coroutine-ucontext.c          |  230 +++++++++++++++++
 coroutine-win32.c             |   92 ++++++
 cutils.c                      |   16 -
 darwin-user/main.c            |    4 
 darwin-user/signal.c          |    1 
 dma.h                         |    4 
 exec-memory.h                 |    5 
 exec.c                        |   34 ++
 hmp-commands.hx               |    2 
 hw/ac97.c                     |   88 +++---
 hw/apb_pci.c                  |    1 
 hw/axis_dev88.c               |   21 -
 hw/bonito.c                   |    1 
 hw/bt-hid.c                   |   62 +---
 hw/cirrus_vga.c               |  459 ++++++++++------------------------
 hw/cuda.c                     |    6 
 hw/e1000.c                    |  113 +++-----
 hw/eepro100.c                 |  181 ++-----------
 hw/es1370.c                   |   43 +--
 hw/escc.c                     |   42 +--
 hw/escc.h                     |    2 
 hw/etraxfs.c                  |  159 -----------
 hw/etraxfs.h                  |    4 
 hw/etraxfs_eth.c              |   26 +
 hw/fw_cfg.c                   |   13 
 hw/grackle_pci.c              |    8 
 hw/gt64xxx.c                  |    4 
 hw/heathrow_pic.c             |   29 --
 hw/hid.c                      |  403 +++++++++++++++++++++++++++++
 hw/hid.h                      |   58 ++++
 hw/ide.h                      |    2 
 hw/ide/ahci.c                 |   31 --
 hw/ide/ahci.h                 |    2 
 hw/ide/cmd646.c               |  204 +++++++++------
 hw/ide/ich.c                  |    3 
 hw/ide/macio.c                |   36 +-
 hw/ide/pci.c                  |   25 +
 hw/ide/pci.h                  |   19 +
 hw/ide/piix.c                 |   63 +++-
 hw/ide/via.c                  |   64 +++-
 hw/intel-hda.c                |   35 +-
 hw/isa.h                      |    2 
 hw/isa_mmio.c                 |   29 +-
 hw/ivshmem.c                  |  158 ++++-------
 hw/kvmclock.c                 |    7 
 hw/lance.c                    |   31 +-
 hw/lsi53c895a.c               |  257 ++++---------------
 hw/mac_dbdma.c                |   32 +-
 hw/mac_dbdma.h                |    4 
 hw/mac_nvram.c                |   39 +-
 hw/macio.c                    |   73 ++---
 hw/milkymist-softusb.c        |   14 -
 hw/msix.c                     |   64 +---
 hw/msix.h                     |    6 
 hw/ne2000-isa.c               |   13 
 hw/ne2000.c                   |   77 +++--
 hw/ne2000.h                   |    8 
 hw/openpic.c                  |   81 ++----
 hw/openpic.h                  |    2 
 hw/pc.h                       |    4 
 hw/pc_piix.c                  |    6 
 hw/pci.c                      |  139 +++-------
 hw/pci.h                      |   26 -
 hw/pci_host.c                 |   24 +
 hw/pci_host.h                 |    6 
 hw/pci_internals.h            |    3 
 hw/pcie_host.c                |   32 +-
 hw/pcnet-pci.c                |   74 +++--
 hw/pcnet.h                    |    4 
 hw/piix_pci.c                 |   14 -
 hw/ppc4xx_pci.c               |    1 
 hw/ppc_mac.h                  |   27 +-
 hw/ppc_newworld.c             |   34 +-
 hw/ppc_oldworld.c             |   27 +-
 hw/ppc_prep.c                 |    2 
 hw/ppce500_pci.c              |    7 
 hw/prep_pci.c                 |    8 
 hw/prep_pci.h                 |    4 
 hw/qdev.c                     |   14 -
 hw/qxl-render.c               |    6 
 hw/qxl.c                      |  567 +++++++++++++++++++++++++++++++-----------
 hw/qxl.h                      |   40 ++
 hw/rtl8139.c                  |   70 ++---
 hw/scsi-bus.c                 |   74 +++--
 hw/scsi-defs.h                |   62 ++--
 hw/scsi-disk.c                |   79 ++---
 hw/scsi-generic.c             |    2 
 hw/sh_pci.c                   |    4 
 hw/sun4u.c                    |   49 +--
 hw/unin_pci.c                 |   16 -
 hw/usb-bt.c                   |   31 --
 hw/usb-ccid.c                 |   46 +--
 hw/usb-ehci.c                 |  198 +++++---------
 hw/usb-hid.c                  |  519 +++++---------------------------------
 hw/usb-hub.c                  |    8 
 hw/usb-libhw.c                |   63 ++++
 hw/usb-msd.c                  |  109 +++-----
 hw/usb-musb.c                 |   22 -
 hw/usb-net.c                  |   65 +---
 hw/usb-ohci.c                 |   25 -
 hw/usb-serial.c               |   26 +
 hw/usb-uhci.c                 |   92 +++---
 hw/usb-wacom.c                |    6 
 hw/usb.c                      |   86 +++++-
 hw/usb.h                      |   13 
 hw/versatile_pci.c            |    2 
 hw/vga-isa-mm.c               |   46 ++-
 hw/vga-isa.c                  |   10 
 hw/vga-pci.c                  |   27 --
 hw/vga.c                      |  178 ++++---------
 hw/vga_int.h                  |   18 -
 hw/vhost.c                    |    1 
 hw/virtio-balloon.c           |   76 +++--
 hw/virtio-blk.c               |    1 
 hw/virtio-net.c               |    2 
 hw/virtio-pci.c               |  117 ++++----
 hw/virtio-pci.h               |    3 
 hw/virtio.c                   |    1 
 hw/virtio.h                   |    1 
 hw/vmware_vga.c               |  153 +++++------
 hw/wdt_i6300esb.c             |   43 ++-
 hw/xen_platform.c             |   82 +++---
 iov.c                         |   54 ++++
 iov.h                         |    4 
 kvm-all.c                     |    8 
 libcacard/Makefile            |    5 
 linux-aio.c                   |   43 ---
 linux-user/main.c             |    3 
 memory.c                      |   27 +-
 memory.h                      |    2 
 migration.c                   |   19 -
 net.c                         |   19 +
 net/socket.c                  |   10 
 net/tap-bsd.c                 |   26 +
 posix-aio-compat.c            |   30 +-
 qemu-common.h                 |   12 
 qemu-coroutine-int.h          |   49 +++
 qemu-coroutine-lock.c         |  117 ++++++++
 qemu-coroutine.c              |   75 +++++
 qemu-coroutine.h              |  159 +++++++++++
 qemu-doc.texi                 |    8 
 slirp/arp_table.c             |   95 +++++++
 slirp/bootp.c                 |   21 -
 slirp/if.c                    |   22 +
 slirp/main.h                  |    2 
 slirp/mbuf.c                  |    2 
 slirp/mbuf.h                  |    2 
 slirp/slirp.c                 |  138 ++++------
 slirp/slirp.h                 |   47 +++
 target-alpha/cpu.h            |    2 
 target-alpha/helper.c         |    4 
 target-alpha/op_helper.c      |    2 
 target-arm/cpu.h              |    4 
 target-arm/helper.c           |   51 +++
 target-arm/op_helper.c        |    2 
 target-arm/translate.c        |  114 +++++---
 target-cris/cpu.h             |    2 
 target-cris/helper.c          |   11 
 target-cris/op_helper.c       |    2 
 target-i386/cpu.h             |    3 
 target-i386/cpuid.c           |   13 
 target-i386/helper.c          |    8 
 target-i386/kvm.c             |   16 +
 target-i386/op_helper.c       |    2 
 target-lm32/cpu.h             |    2 
 target-lm32/helper.c          |    2 
 target-lm32/op_helper.c       |    2 
 target-m68k/cpu.h             |    2 
 target-m68k/helper.c          |    4 
 target-m68k/op_helper.c       |    2 
 target-microblaze/cpu.h       |    2 
 target-microblaze/helper.c    |    4 
 target-microblaze/op_helper.c |    2 
 target-mips/cpu.h             |    2 
 target-mips/helper.c          |    6 
 target-mips/op_helper.c       |    2 
 target-ppc/cpu.h              |    2 
 target-ppc/helper.c           |    8 
 target-ppc/op_helper.c        |    2 
 target-s390x/cpu.h            |    2 
 target-s390x/helper.c         |   14 -
 target-s390x/op_helper.c      |    2 
 target-sh4/cpu.h              |    2 
 target-sh4/helper.c           |    4 
 target-sh4/op_helper.c        |    2 
 target-sparc/cpu.h            |    2 
 target-sparc/helper.c         |    6 
 target-sparc/op_helper.c      |   27 --
 target-sparc/translate.c      |   30 +-
 target-unicore32/cpu.h        |    2 
 target-unicore32/helper.c     |    2 
 tcg/optimize.c                |   15 -
 tcg/tcg.h                     |    5 
 test-coroutine.c              |  192 ++++++++++++++
 trace-events                  |   16 +
 ui/sdl.c                      |  547 +++++++++++++++++++++++++---------------
 ui/spice-display.c            |   93 ++++++
 ui/spice-display.h            |   28 ++
 usb-bsd.c                     |   14 -
 usb-linux.c                   |   48 ++-
 usb-redir.c                   |   59 ++--
 user-exec.c                   |    2 
 vl.c                          |   14 -
 229 files changed, 6260 insertions(+), 4486 deletions(-)

New commits:
commit b9c6cbff76061537b722d55f0e321dde2a612a23
Merge: 1da005b... a492892...
Author: Edgar E. Iglesias <edgar.iglesias at gmail.com>
Date:   Tue Aug 9 19:16:43 2011 +0200

    Merge remote-tracking branch 'pm-arm/for-upstream' into pm

commit 1da005b37482b51eaa4e5c6fa35d6d50687d83f1
Author: Edgar E. Iglesias <edgar.iglesias at gmail.com>
Date:   Tue Aug 9 12:13:26 2011 +0200

    etrax: Allocate DMA connections at board level.
    
    Signed-off-by: Edgar E. Iglesias <edgar.iglesias at gmail.com>

diff --git a/hw/axis_dev88.c b/hw/axis_dev88.c
index 1c83e93..d9002a5 100644
--- a/hw/axis_dev88.c
+++ b/hw/axis_dev88.c
@@ -255,7 +255,7 @@ void axisdev88_init (ram_addr_t ram_size,
     DriveInfo *nand;
     qemu_irq irq[30], nmi[2], *cpu_irq;
     void *etraxfs_dmac;
-    struct etraxfs_dma_client *eth[2] = {NULL, NULL};
+    struct etraxfs_dma_client *dma_eth;
     int i;
     int nand_regs;
     int gpio_regs;
@@ -315,16 +315,18 @@ void axisdev88_init (ram_addr_t ram_size,
     }
 
     /* Add the two ethernet blocks.  */
-    eth[0] = etraxfs_eth_init(&nd_table[0], 0x30034000, 1);
-    if (nb_nics > 1)
-        eth[1] = etraxfs_eth_init(&nd_table[1], 0x30036000, 2);
+    dma_eth = qemu_mallocz(sizeof dma_eth[0] * 4); /* Allocate 4 channels.  */
+    etraxfs_eth_init(&nd_table[0], 0x30034000, 1, &dma_eth[0], &dma_eth[1]);
+    if (nb_nics > 1) {
+        etraxfs_eth_init(&nd_table[1], 0x30036000, 2, &dma_eth[2], &dma_eth[3]);
+    }
 
     /* The DMA Connector block is missing, hardwire things for now.  */
-    etraxfs_dmac_connect_client(etraxfs_dmac, 0, eth[0]);
-    etraxfs_dmac_connect_client(etraxfs_dmac, 1, eth[0] + 1);
-    if (eth[1]) {
-        etraxfs_dmac_connect_client(etraxfs_dmac, 6, eth[1]);
-        etraxfs_dmac_connect_client(etraxfs_dmac, 7, eth[1] + 1);
+    etraxfs_dmac_connect_client(etraxfs_dmac, 0, &dma_eth[0]);
+    etraxfs_dmac_connect_client(etraxfs_dmac, 1, &dma_eth[1]);
+    if (nb_nics > 1) {
+        etraxfs_dmac_connect_client(etraxfs_dmac, 6, &dma_eth[2]);
+        etraxfs_dmac_connect_client(etraxfs_dmac, 7, &dma_eth[3]);
     }
 
     /* 2 timers.  */
diff --git a/hw/etraxfs.h b/hw/etraxfs.h
index 01fb9d3..5c61f1b 100644
--- a/hw/etraxfs.h
+++ b/hw/etraxfs.h
@@ -25,4 +25,6 @@
 #include "etraxfs_dma.h"
 
 qemu_irq *cris_pic_init_cpu(CPUState *env);
-void *etraxfs_eth_init(NICInfo *nd, target_phys_addr_t base, int phyaddr);
+void etraxfs_eth_init(NICInfo *nd, target_phys_addr_t base, int phyaddr,
+                      struct etraxfs_dma_client *dma_out,
+                      struct etraxfs_dma_client *dma_in);
diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c
index dff5f55..6453077 100644
--- a/hw/etraxfs_eth.c
+++ b/hw/etraxfs_eth.c
@@ -562,7 +562,11 @@ static void eth_cleanup(VLANClientState *nc)
 
         cpu_unregister_io_memory(eth->ethregs);
 
-        qemu_free(eth->dma_out);
+	/* Disconnect the client.  */
+	eth->dma_out->client.push = NULL;
+	eth->dma_out->client.opaque = NULL;
+	eth->dma_in->client.opaque = NULL;
+	eth->dma_in->client.pull = NULL;
         qemu_free(eth);
 }
 
@@ -575,23 +579,23 @@ static NetClientInfo net_etraxfs_info = {
 	.link_status_changed = eth_set_link,
 };
 
-void *etraxfs_eth_init(NICInfo *nd, target_phys_addr_t base, int phyaddr)
+void etraxfs_eth_init(NICInfo *nd, target_phys_addr_t base, int phyaddr,
+                       struct etraxfs_dma_client *dma_out,
+                       struct etraxfs_dma_client *dma_in)
 {
-	struct etraxfs_dma_client *dma = NULL;	
 	struct fs_eth *eth = NULL;
 
 	qemu_check_nic_model(nd, "fseth");
 
-	dma = qemu_mallocz(sizeof *dma * 2);
 	eth = qemu_mallocz(sizeof *eth);
 
-	dma[0].client.push = eth_tx_push;
-	dma[0].client.opaque = eth;
-	dma[1].client.opaque = eth;
-	dma[1].client.pull = NULL;
+	dma_out->client.push = eth_tx_push;
+	dma_out->client.opaque = eth;
+	dma_in->client.opaque = eth;
+	dma_in->client.pull = NULL;
 
-	eth->dma_out = dma;
-	eth->dma_in = dma + 1;
+	eth->dma_out = dma_out;
+	eth->dma_in = dma_in;
 
 	/* Connect the phy.  */
 	eth->phyaddr = phyaddr & 0x1f;
@@ -608,6 +612,4 @@ void *etraxfs_eth_init(NICInfo *nd, target_phys_addr_t base, int phyaddr)
 
 	eth->nic = qemu_new_nic(&net_etraxfs_info, &eth->conf,
 				nd->model, nd->name, eth);
-
-	return dma;
 }
commit bbea04df9811ba3312aab93cbbafff3ff3a9aa02
Author: Edgar E. Iglesias <edgar.iglesias at gmail.com>
Date:   Tue Aug 9 12:18:23 2011 +0200

    etrax: Remove hw/etraxfs.c.
    
    The Bare ETRAX FS board was a fictive machine that I used when
    developing the CRIS system emulation. Since we support the
    real AXIS-dev88 developer boards, there is no reason to
    keep the fictive one around.
    
    This commit also removes the double registration of the axis-dev88
    board.
    
    Signed-off-by: Edgar E. Iglesias <edgar.iglesias at gmail.com>

diff --git a/Makefile.target b/Makefile.target
index 4aacc67..096214a 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -310,7 +310,6 @@ obj-microblaze-$(CONFIG_FDT) += device_tree.o
 # Boards
 obj-cris-y = cris_pic_cpu.o
 obj-cris-y += cris-boot.o
-obj-cris-y += etraxfs.o axis_dev88.o
 obj-cris-y += axis_dev88.o
 
 # IO blocks
diff --git a/hw/axis_dev88.c b/hw/axis_dev88.c
index e0a8c14..1c83e93 100644
--- a/hw/axis_dev88.c
+++ b/hw/axis_dev88.c
@@ -350,6 +350,7 @@ static QEMUMachine axisdev88_machine = {
     .name = "axis-dev88",
     .desc = "AXIS devboard 88",
     .init = axisdev88_init,
+    .is_default = 1,
 };
 
 static void axisdev88_machine_init(void)
diff --git a/hw/etraxfs.c b/hw/etraxfs.c
deleted file mode 100644
index b84d74a..0000000
--- a/hw/etraxfs.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * QEMU ETRAX System Emulator
- *
- * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB.
- *
- * 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 "boards.h"
-#include "net.h"
-#include "flash.h"
-#include "etraxfs.h"
-#include "loader.h"
-#include "elf.h"
-#include "cris-boot.h"
-#include "blockdev.h"
-
-#define FLASH_SIZE 0x2000000
-#define INTMEM_SIZE (128 * 1024)
-
-static struct cris_load_info li;
-
-static void flash_cpu_reset(void *opaque)
-{
-    CPUState *env = opaque;
-    cpu_reset(env);
-}
-
-static
-void bareetraxfs_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;
-    SysBusDevice *s;
-    CPUState *env;
-    qemu_irq irq[30], nmi[2], *cpu_irq; 
-    void *etraxfs_dmac;
-    struct etraxfs_dma_client *eth[2] = {NULL, NULL};
-    DriveInfo *dinfo;
-    int i;
-    ram_addr_t phys_ram;
-    ram_addr_t phys_flash;
-    ram_addr_t phys_intmem;
-
-    /* init CPUs */
-    if (cpu_model == NULL) {
-        cpu_model = "crisv32";
-    }
-    env = cpu_init(cpu_model);
-
-    /* allocate RAM */
-    phys_ram = qemu_ram_alloc(NULL, "etraxfs.ram", ram_size);
-    cpu_register_physical_memory(0x40000000, ram_size, phys_ram | IO_MEM_RAM);
-
-    /* The ETRAX-FS has 128Kb on chip ram, the docs refer to it as the 
-       internal memory.  */
-    phys_intmem = qemu_ram_alloc(NULL, "etraxfs.chipram", INTMEM_SIZE);
-    cpu_register_physical_memory(0x38000000, INTMEM_SIZE,
-                                 phys_intmem | IO_MEM_RAM);
-
-
-    phys_flash = qemu_ram_alloc(NULL, "etraxfs.flash", FLASH_SIZE);
-    dinfo = drive_get(IF_PFLASH, 0, 0);
-    pflash_cfi02_register(0x0, phys_flash,
-                          dinfo ? dinfo->bdrv : NULL, (64 * 1024),
-                          FLASH_SIZE >> 16,
-                          1, 2, 0x0000, 0x0000, 0x0000, 0x0000,
-                          0x555, 0x2aa, 0);
-    cpu_irq = cris_pic_init_cpu(env);
-    dev = qdev_create(NULL, "etraxfs,pic");
-    /* FIXME: Is there a proper way to signal vectors to the CPU core?  */
-    qdev_prop_set_ptr(dev, "interrupt_vector", &env->interrupt_vector);
-    qdev_init_nofail(dev);
-    s = sysbus_from_qdev(dev);
-    sysbus_mmio_map(s, 0, 0x3001c000);
-    sysbus_connect_irq(s, 0, cpu_irq[0]);
-    sysbus_connect_irq(s, 1, cpu_irq[1]);
-    for (i = 0; i < 30; i++) {
-        irq[i] = qdev_get_gpio_in(dev, i);
-    }
-    nmi[0] = qdev_get_gpio_in(dev, 30);
-    nmi[1] = qdev_get_gpio_in(dev, 31);
-
-    etraxfs_dmac = etraxfs_dmac_init(0x30000000, 10);
-    for (i = 0; i < 10; i++) {
-        /* On ETRAX, odd numbered channels are inputs.  */
-        etraxfs_dmac_connect(etraxfs_dmac, i, irq + 7 + i, i & 1);
-    }
-
-    /* Add the two ethernet blocks.  */
-    eth[0] = etraxfs_eth_init(&nd_table[0], 0x30034000, 1);
-    if (nb_nics > 1)
-        eth[1] = etraxfs_eth_init(&nd_table[1], 0x30036000, 2);
-
-    /* The DMA Connector block is missing, hardwire things for now.  */
-    etraxfs_dmac_connect_client(etraxfs_dmac, 0, eth[0]);
-    etraxfs_dmac_connect_client(etraxfs_dmac, 1, eth[0] + 1);
-    if (eth[1]) {
-        etraxfs_dmac_connect_client(etraxfs_dmac, 6, eth[1]);
-        etraxfs_dmac_connect_client(etraxfs_dmac, 7, eth[1] + 1);
-    }
-
-    /* 2 timers.  */
-    sysbus_create_varargs("etraxfs,timer", 0x3001e000, irq[0x1b], nmi[1], NULL);
-    sysbus_create_varargs("etraxfs,timer", 0x3005e000, irq[0x1b], nmi[1], NULL);
-
-    for (i = 0; i < 4; i++) {
-        sysbus_create_simple("etraxfs,serial", 0x30026000 + i * 0x2000,
-                             irq[0x14 + i]); 
-    }
-
-    if (kernel_filename) {
-        li.image_filename = kernel_filename;
-        li.cmdline = kernel_cmdline;
-        cris_load_image(env, &li);
-    } else {
-        if (!dinfo) {
-            fprintf(stderr,
-                    "Provide a kernel image or a flash image to boot from.\n");
-           exit(1);
-        }
-
-        /* Nothing more to do for flash images, those boot from addr 0.  */
-        qemu_register_reset(flash_cpu_reset, env);
-    }
-}
-
-static QEMUMachine bareetraxfs_machine = {
-    .name = "bareetraxfs",
-    .desc = "Bare ETRAX FS board",
-    .init = bareetraxfs_init,
-    .is_default = 1,
-};
-
-static void bareetraxfs_machine_init(void)
-{
-    qemu_register_machine(&bareetraxfs_machine);
-}
-
-machine_init(bareetraxfs_machine_init);
commit 032a7c4e425f1f0b71942768696f53f93947f8fa
Author: Avi Kivity <avi at redhat.com>
Date:   Tue Aug 9 09:54:22 2011 +0300

    lance: unbreak after memory API conversion
    
    The conversion passed the wrong opaque pointer, causing a crash on first use.
    Pass the correct opaque.
    
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Edgar E. Iglesias <edgar.iglesias at gmail.com>

diff --git a/hw/lance.c b/hw/lance.c
index 8e20360..d83e7f5 100644
--- a/hw/lance.c
+++ b/hw/lance.c
@@ -116,7 +116,7 @@ static int lance_init(SysBusDevice *dev)
     SysBusPCNetState *d = FROM_SYSBUS(SysBusPCNetState, dev);
     PCNetState *s = &d->state;
 
-    memory_region_init_io(&s->mmio, &lance_mem_ops, s, "lance-mmio", 4);
+    memory_region_init_io(&s->mmio, &lance_mem_ops, d, "lance-mmio", 4);
 
     qdev_init_gpio_in(&dev->qdev, parent_lance_reset, 1);
 
commit 986563b173ca2d4bd47b10455b19c86e5cd5bba2
Merge: 0395233... ac363c9...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon Aug 8 14:38:42 2011 -0500

    Merge remote-tracking branch 'qemu-kvm/uq/master' into staging

commit 039523397fce67ccb15a9b71ef812f9a69286aa5
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:09:32 2011 +0300

    pci: remove support for pre memory API BARs
    
    Not used anymore.
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/pci.c b/hw/pci.c
index 6547d2b..dc7271a 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -848,18 +848,7 @@ static void pci_unregister_io_regions(PCIDevice *pci_dev)
         r = &pci_dev->io_regions[i];
         if (!r->size || r->addr == PCI_BAR_UNMAPPED)
             continue;
-        if (r->memory) {
-            memory_region_del_subregion(r->address_space, r->memory);
-        } else {
-            if (r->type == PCI_BASE_ADDRESS_SPACE_IO) {
-                isa_unassign_ioport(r->addr, r->filtered_size);
-            } else {
-                cpu_register_physical_memory(pci_to_cpu_addr(pci_dev->bus,
-                                                             r->addr),
-                                             r->filtered_size,
-                                             IO_MEM_UNASSIGNED);
-            }
-        }
+        memory_region_del_subregion(r->address_space, r->memory);
     }
 }
 
@@ -1058,25 +1047,7 @@ static void pci_update_mappings(PCIDevice *d)
 
         /* now do the real mapping */
         if (r->addr != PCI_BAR_UNMAPPED) {
-            if (r->memory) {
-                memory_region_del_subregion(r->address_space, r->memory);
-            } else if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
-                int class;
-                /* NOTE: specific hack for IDE in PC case:
-                   only one byte must be mapped. */
-                class = pci_get_word(d->config + PCI_CLASS_DEVICE);
-                if (class == 0x0101 && r->size == 4) {
-                    isa_unassign_ioport(r->addr + 2, 1);
-                } else {
-                    isa_unassign_ioport(r->addr, r->filtered_size);
-                }
-            } else {
-                cpu_register_physical_memory(pci_to_cpu_addr(d->bus,
-                                                             r->addr),
-                                             r->filtered_size,
-                                             IO_MEM_UNASSIGNED);
-                qemu_unregister_coalesced_mmio(r->addr, r->filtered_size);
-            }
+            memory_region_del_subregion(r->address_space, r->memory);
         }
         r->addr = new_addr;
         r->filtered_size = filtered_size;
commit e824b2cc3b4f6fbcbaa254abd8db55d2fbe8d19e
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:09:31 2011 +0300

    pci: rename pci_register_bar_region() to pci_register_bar()
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/ac97.c b/hw/ac97.c
index 52f0f0d..541d9a4 100644
--- a/hw/ac97.c
+++ b/hw/ac97.c
@@ -1316,9 +1316,8 @@ static int ac97_initfn (PCIDevice *dev)
 
     memory_region_init_io (&s->io_nam, &ac97_io_nam_ops, s, "ac97-nam", 1024);
     memory_region_init_io (&s->io_nabm, &ac97_io_nabm_ops, s, "ac97-nabm", 256);
-    pci_register_bar_region (&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_nam);
-    pci_register_bar_region (&s->dev, 1, PCI_BASE_ADDRESS_SPACE_IO,
-                             &s->io_nabm);
+    pci_register_bar (&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_nam);
+    pci_register_bar (&s->dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->io_nabm);
     qemu_register_reset (ac97_on_reset, s);
     AUD_register_card ("ac97", &s->card);
     ac97_on_reset (s);
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index c9887ac..b489309 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -2948,10 +2948,9 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev)
      /* memory #0 LFB */
      /* memory #1 memory-mapped I/O */
      /* XXX: s->vga.vram_size must be a power of two */
-     pci_register_bar_region(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH,
-                             &s->pci_bar);
+     pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->pci_bar);
      if (device_id == CIRRUS_ID_CLGD5446) {
-         pci_register_bar_region(&d->dev, 1, 0, &s->cirrus_mmio_io);
+         pci_register_bar(&d->dev, 1, 0, &s->cirrus_mmio_io);
      }
      return 0;
 }
diff --git a/hw/e1000.c b/hw/e1000.c
index dfc082b..29b453f 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -1158,10 +1158,9 @@ static int pci_e1000_init(PCIDevice *pci_dev)
 
     e1000_mmio_setup(d);
 
-    pci_register_bar_region(&d->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
-                            &d->mmio);
+    pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
 
-    pci_register_bar_region(&d->dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &d->io);
+    pci_register_bar(&d->dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &d->io);
 
     memmove(d->eeprom_data, e1000_eeprom_template,
         sizeof e1000_eeprom_template);
diff --git a/hw/eepro100.c b/hw/eepro100.c
index 04723f3..a636d30 100644
--- a/hw/eepro100.c
+++ b/hw/eepro100.c
@@ -1879,15 +1879,14 @@ static int e100_nic_init(PCIDevice *pci_dev)
     /* Handler for memory-mapped I/O */
     memory_region_init_io(&s->mmio_bar, &eepro100_ops, s, "eepro100-mmio",
                           PCI_MEM_SIZE);
-    pci_register_bar_region(&s->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH,
-                            &s->mmio_bar);
+    pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->mmio_bar);
     memory_region_init_io(&s->io_bar, &eepro100_ops, s, "eepro100-io",
                           PCI_IO_SIZE);
-    pci_register_bar_region(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->io_bar);
+    pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->io_bar);
     /* FIXME: flash aliases to mmio?! */
     memory_region_init_io(&s->flash_bar, &eepro100_ops, s, "eepro100-flash",
                           PCI_FLASH_SIZE);
-    pci_register_bar_region(&s->dev, 2, 0, &s->flash_bar);
+    pci_register_bar(&s->dev, 2, 0, &s->flash_bar);
 
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
     logout("macaddr: %s\n", nic_dump(&s->conf.macaddr.a[0], 6));
diff --git a/hw/es1370.c b/hw/es1370.c
index 4e43c4a..a9387d1 100644
--- a/hw/es1370.c
+++ b/hw/es1370.c
@@ -1009,7 +1009,7 @@ static int es1370_initfn (PCIDevice *dev)
     c[PCI_MAX_LAT] = 0x80;
 
     memory_region_init_io (&s->io, &es1370_io_ops, s, "es1370", 256);
-    pci_register_bar_region (&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io);
+    pci_register_bar (&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io);
     qemu_register_reset (es1370_on_reset, s);
 
     AUD_register_card ("es1370", &s->card);
diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c
index 13e6f2f..4d91e2c 100644
--- a/hw/ide/cmd646.c
+++ b/hw/ide/cmd646.c
@@ -270,16 +270,12 @@ static int pci_cmd646_ide_initfn(PCIDevice *dev)
 
     setup_cmd646_bar(d, 0);
     setup_cmd646_bar(d, 1);
-    pci_register_bar_region(dev, 0, PCI_BASE_ADDRESS_SPACE_IO,
-                            &d->cmd646_bar[0].data);
-    pci_register_bar_region(dev, 1, PCI_BASE_ADDRESS_SPACE_IO,
-                            &d->cmd646_bar[0].cmd);
-    pci_register_bar_region(dev, 2, PCI_BASE_ADDRESS_SPACE_IO,
-                            &d->cmd646_bar[1].data);
-    pci_register_bar_region(dev, 3, PCI_BASE_ADDRESS_SPACE_IO,
-                            &d->cmd646_bar[1].cmd);
+    pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &d->cmd646_bar[0].data);
+    pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &d->cmd646_bar[0].cmd);
+    pci_register_bar(dev, 2, PCI_BASE_ADDRESS_SPACE_IO, &d->cmd646_bar[1].data);
+    pci_register_bar(dev, 3, PCI_BASE_ADDRESS_SPACE_IO, &d->cmd646_bar[1].cmd);
     bmdma_setup_bar(d);
-    pci_register_bar_region(dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &d->bmdma_bar);
+    pci_register_bar(dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &d->bmdma_bar);
 
     /* TODO: RST# value should be 0 */
     pci_conf[PCI_INTERRUPT_PIN] = 0x01; // interrupt on pin 1
diff --git a/hw/ide/ich.c b/hw/ide/ich.c
index 698b5f6..5278bc4 100644
--- a/hw/ide/ich.c
+++ b/hw/ide/ich.c
@@ -98,7 +98,7 @@ static int pci_ich9_ahci_init(PCIDevice *dev)
     msi_init(dev, 0x50, 1, true, false);
     d->ahci.irq = d->card.irq[0];
 
-    pci_register_bar_region(&d->card, 5, 0, &d->ahci.mem);
+    pci_register_bar(&d->card, 5, 0, &d->ahci.mem);
 
     return 0;
 }
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index 5aa0a30..8525336 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -155,8 +155,7 @@ static int pci_piix_ide_initfn(PCIDevice *dev)
     qemu_register_reset(piix3_reset, d);
 
     bmdma_setup_bar(d);
-    pci_register_bar_region(&d->dev, 4, PCI_BASE_ADDRESS_SPACE_IO,
-                            &d->bmdma_bar);
+    pci_register_bar(&d->dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &d->bmdma_bar);
 
     vmstate_register(&d->dev.qdev, 0, &vmstate_ide_pci, d);
 
diff --git a/hw/ide/via.c b/hw/ide/via.c
index eb6a409..c0b9d43 100644
--- a/hw/ide/via.c
+++ b/hw/ide/via.c
@@ -180,8 +180,7 @@ static int vt82c686b_ide_initfn(PCIDevice *dev)
 
     qemu_register_reset(via_reset, d);
     bmdma_setup_bar(d);
-    pci_register_bar_region(&d->dev, 4, PCI_BASE_ADDRESS_SPACE_IO,
-                            &d->bmdma_bar);
+    pci_register_bar(&d->dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &d->bmdma_bar);
 
     vmstate_register(&dev->qdev, 0, &vmstate_ide_pci, d);
 
diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index 1e4c71e..fa56a92 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -1136,7 +1136,7 @@ static int intel_hda_init(PCIDevice *pci)
 
     memory_region_init_io(&d->mmio, &intel_hda_mmio_ops, d,
                           "intel-hda", 0x4000);
-    pci_register_bar_region(&d->pci, 0, 0, &d->mmio);
+    pci_register_bar(&d->pci, 0, 0, &d->mmio);
     if (d->msi) {
         msi_init(&d->pci, 0x50, 1, true, false);
     }
diff --git a/hw/ivshmem.c b/hw/ivshmem.c
index bacba60..42a5877 100644
--- a/hw/ivshmem.c
+++ b/hw/ivshmem.c
@@ -336,7 +336,7 @@ static void create_shared_memory_BAR(IVShmemState *s, int fd) {
     memory_region_add_subregion(&s->bar, 0, &s->ivshmem);
 
     /* region for shared memory */
-    pci_register_bar_region(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar);
+    pci_register_bar(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar);
 }
 
 static void close_guest_eventfds(IVShmemState *s, int posn)
@@ -543,9 +543,8 @@ static void ivshmem_setup_msi(IVShmemState * s) {
 
     memory_region_init(&s->msix_bar, "ivshmem-msix", 4096);
     if (!msix_init(&s->dev, s->vectors, &s->msix_bar, 1, 0)) {
-        pci_register_bar_region(&s->dev, 1,
-                                PCI_BASE_ADDRESS_SPACE_MEMORY,
-                                &s->msix_bar);
+        pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY,
+                         &s->msix_bar);
         IVSHMEM_DPRINTF("msix initialized (%d vectors)\n", s->vectors);
     } else {
         IVSHMEM_DPRINTF("msix initialization failed\n");
@@ -665,8 +664,8 @@ static int pci_ivshmem_init(PCIDevice *dev)
     }
 
     /* region for registers*/
-    pci_register_bar_region(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
-                            &s->ivshmem_mmio);
+    pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
+                     &s->ivshmem_mmio);
 
     memory_region_init(&s->bar, "ivshmem-bar2-container", s->ivshmem_size);
 
@@ -694,8 +693,8 @@ static int pci_ivshmem_init(PCIDevice *dev)
         /* allocate/initialize space for interrupt handling */
         s->peers = qemu_mallocz(s->nb_peers * sizeof(Peer));
 
-        pci_register_bar_region(&s->dev, 2,
-                                PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ivshmem);
+        pci_register_bar(&s->dev, 2,
+                         PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ivshmem);
 
         s->eventfd_chr = qemu_mallocz(s->vectors * sizeof(CharDriverState *));
 
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index 0ab8c78..d067a02 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -2118,10 +2118,9 @@ static int lsi_scsi_init(PCIDevice *dev)
     memory_region_init_io(&s->ram_io, &lsi_ram_ops, s, "lsi-ram", 0x2000);
     memory_region_init_io(&s->io_io, &lsi_io_ops, s, "lsi-io", 256);
 
-    pci_register_bar_region(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_io);
-    pci_register_bar_region(&s->dev, 1, 0, &s->mmio_io);
-    pci_register_bar_region(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY,
-                            &s->ram_io);
+    pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_io);
+    pci_register_bar(&s->dev, 1, 0, &s->mmio_io);
+    pci_register_bar(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ram_io);
     QTAILQ_INIT(&s->queue);
 
     scsi_bus_new(&s->bus, &dev->qdev, 1, LSI_MAX_DEVS, &lsi_scsi_ops);
diff --git a/hw/macio.c b/hw/macio.c
index 71fa2a8..cc6ae40 100644
--- a/hw/macio.c
+++ b/hw/macio.c
@@ -111,6 +111,5 @@ void macio_init (PCIBus *bus, int device_id, int is_oldworld,
     d->config[0x3d] = 0x01; // interrupt on pin 1
 
     macio_bar_setup(macio_state);
-    pci_register_bar_region(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
-                            &macio_state->bar);
+    pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &macio_state->bar);
 }
diff --git a/hw/ne2000.c b/hw/ne2000.c
index 5b76acf..a035a85 100644
--- a/hw/ne2000.c
+++ b/hw/ne2000.c
@@ -754,7 +754,7 @@ static int pci_ne2000_init(PCIDevice *pci_dev)
 
     s = &d->ne2000;
     ne2000_setup_io(s, 0x100);
-    pci_register_bar_region(&d->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io);
+    pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io);
     s->irq = d->dev.irq[0];
 
     qemu_macaddr_default_if_unset(&s->c.macaddr);
diff --git a/hw/openpic.c b/hw/openpic.c
index c2b04a3..ccd4a14 100644
--- a/hw/openpic.c
+++ b/hw/openpic.c
@@ -1177,8 +1177,8 @@ qemu_irq *openpic_init (PCIBus *bus, MemoryRegion **pmem, int nb_cpus,
 #endif
 
         /* Register I/O spaces */
-        pci_register_bar_region(&opp->pci_dev, 0,
-                                PCI_BASE_ADDRESS_SPACE_MEMORY, &opp->mem);
+        pci_register_bar(&opp->pci_dev, 0,
+                         PCI_BASE_ADDRESS_SPACE_MEMORY, &opp->mem);
     } else {
         opp = qemu_mallocz(sizeof(openpic_t));
         memory_region_init_io(&opp->mem, &openpic_ops, opp, "openpic", 0x40000);
diff --git a/hw/pci.c b/hw/pci.c
index aa17395..6547d2b 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -881,8 +881,8 @@ static int pci_unregister_device(DeviceState *dev)
     return 0;
 }
 
-void pci_register_bar_region(PCIDevice *pci_dev, int region_num,
-                             uint8_t type, MemoryRegion *memory)
+void pci_register_bar(PCIDevice *pci_dev, int region_num,
+                      uint8_t type, MemoryRegion *memory)
 {
     PCIIORegion *r;
     uint32_t addr;
@@ -1956,7 +1956,7 @@ static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom)
 
     qemu_put_ram_ptr(ptr);
 
-    pci_register_bar_region(pdev, PCI_ROM_SLOT, 0, &pdev->rom);
+    pci_register_bar(pdev, PCI_ROM_SLOT, 0, &pdev->rom);
 
     return 0;
 }
diff --git a/hw/pci.h b/hw/pci.h
index 8d1662a..d7ad7fb 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -200,8 +200,8 @@ PCIDevice *pci_register_device(PCIBus *bus, const char *name,
                                PCIConfigReadFunc *config_read,
                                PCIConfigWriteFunc *config_write);
 
-void pci_register_bar_region(PCIDevice *pci_dev, int region_num,
-                             uint8_t attr, MemoryRegion *memory);
+void pci_register_bar(PCIDevice *pci_dev, int region_num,
+                      uint8_t attr, MemoryRegion *memory);
 pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num);
 
 int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c
index a25f565..13d9380 100644
--- a/hw/pcnet-pci.c
+++ b/hw/pcnet-pci.c
@@ -295,9 +295,9 @@ static int pci_pcnet_init(PCIDevice *pci_dev)
 
     memory_region_init_io(&d->io_bar, &pcnet_io_ops, d, "pcnet-io",
                           PCNET_IOPORT_SIZE);
-    pci_register_bar_region(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &d->io_bar);
+    pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &d->io_bar);
 
-    pci_register_bar_region(pci_dev, 1, 0, &s->mmio);
+    pci_register_bar(pci_dev, 1, 0, &s->mmio);
 
     s->irq = pci_dev->irq[0];
     s->phys_mem_read = pci_physical_memory_read;
diff --git a/hw/qxl.c b/hw/qxl.c
index 17c5fc7..db7ae7a 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -1564,17 +1564,17 @@ static int qxl_init_common(PCIQXLDevice *qxl)
     }
 
 
-    pci_register_bar_region(&qxl->pci, QXL_IO_RANGE_INDEX,
-                            PCI_BASE_ADDRESS_SPACE_IO, &qxl->io_bar);
+    pci_register_bar(&qxl->pci, QXL_IO_RANGE_INDEX,
+                     PCI_BASE_ADDRESS_SPACE_IO, &qxl->io_bar);
 
-    pci_register_bar_region(&qxl->pci, QXL_ROM_RANGE_INDEX,
-                            PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->rom_bar);
+    pci_register_bar(&qxl->pci, QXL_ROM_RANGE_INDEX,
+                     PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->rom_bar);
 
-    pci_register_bar_region(&qxl->pci, QXL_RAM_RANGE_INDEX,
-                            PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->vga.vram);
+    pci_register_bar(&qxl->pci, QXL_RAM_RANGE_INDEX,
+                     PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->vga.vram);
 
-    pci_register_bar_region(&qxl->pci, QXL_VRAM_RANGE_INDEX,
-                            PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->vram_bar);
+    pci_register_bar(&qxl->pci, QXL_VRAM_RANGE_INDEX,
+                     PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->vram_bar);
 
     qxl->ssd.qxl.base.sif = &qxl_interface.base;
     qxl->ssd.qxl.id = qxl->id;
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index f07af35..c6cafc2 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -3471,10 +3471,8 @@ static int pci_rtl8139_init(PCIDevice *dev)
 
     memory_region_init_io(&s->bar_io, &rtl8139_io_ops, s, "rtl8139", 0x100);
     memory_region_init_io(&s->bar_mem, &rtl8139_mmio_ops, s, "rtl8139", 0x100);
-    pci_register_bar_region(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO,
-                            &s->bar_io);
-    pci_register_bar_region(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY,
-                            &s->bar_mem);
+    pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->bar_io);
+    pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar_mem);
 
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
 
diff --git a/hw/sun4u.c b/hw/sun4u.c
index cb76031..7b2d0b1 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -554,11 +554,9 @@ pci_ebus_init1(PCIDevice *pci_dev)
     pci_dev->config[0x0D] = 0x0a; // latency_timer
 
     isa_mmio_setup(&s->bar0, 0x1000000);
-    pci_register_bar_region(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
-                            &s->bar0);
+    pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar0);
     isa_mmio_setup(&s->bar1, 0x800000);
-    pci_register_bar_region(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY,
-                            &s->bar1);
+    pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar1);
     return 0;
 }
 
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 6ef7798..c9d0a69 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -2302,7 +2302,7 @@ static int usb_ehci_initfn(PCIDevice *dev)
     qemu_register_reset(ehci_reset, s);
 
     memory_region_init_io(&s->mem, &ehci_mem_ops, s, "ehci", MMIO_SIZE);
-    pci_register_bar_region(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
+    pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
 
     fprintf(stderr, "*** EHCI support is under development ***\n");
 
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index d39bcb0..d30db3f 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -1790,7 +1790,7 @@ static int usb_ohci_initfn_pci(struct PCIDevice *dev)
     ohci->state.irq = ohci->pci_dev.irq[0];
 
     /* TODO: avoid cast below by using dev */
-    pci_register_bar_region(&ohci->pci_dev, 0, 0, &ohci->state.mem);
+    pci_register_bar(&ohci->pci_dev, 0, 0, &ohci->state.mem);
     return 0;
 }
 
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index ea38169..16088d7 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -1159,8 +1159,7 @@ static int usb_uhci_common_initfn(PCIDevice *dev)
     memory_region_init_io(&s->io_bar, &uhci_ioport_ops, s, "uhci", 0x20);
     /* Use region 4 for consistency with real hardware.  BSD guests seem
        to rely on this.  */
-    pci_register_bar_region(&s->dev, 4,
-                            PCI_BASE_ADDRESS_SPACE_IO, &s->io_bar);
+    pci_register_bar(&s->dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &s->io_bar);
 
     return 0;
 }
diff --git a/hw/vga-pci.c b/hw/vga-pci.c
index 7062c4d..c67be0a 100644
--- a/hw/vga-pci.c
+++ b/hw/vga-pci.c
@@ -60,8 +60,7 @@ static int pci_vga_initfn(PCIDevice *dev)
                                   s->screen_dump, s->text_update, s);
 
      /* XXX: VGA_RAM_SIZE must be a power of two */
-     pci_register_bar_region(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH,
-                             &s->vram);
+     pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);
 
      if (!dev->rom_bar) {
          /* compatibility with pc-0.13 and older */
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index 95203c8..df27c19 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -644,9 +644,8 @@ void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev)
     memory_region_init(&proxy->msix_bar, "virtio-msix", 4096);
     if (vdev->nvectors && !msix_init(&proxy->pci_dev, vdev->nvectors,
                                      &proxy->msix_bar, 1, 0)) {
-        pci_register_bar_region(&proxy->pci_dev, 1,
-                                PCI_BASE_ADDRESS_SPACE_MEMORY,
-                                &proxy->msix_bar);
+        pci_register_bar(&proxy->pci_dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY,
+                         &proxy->msix_bar);
     } else
         vdev->nvectors = 0;
 
@@ -658,8 +657,8 @@ void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev)
 
     memory_region_init_io(&proxy->bar, &virtio_pci_config_ops, proxy,
                           "virtio-pci", size);
-    pci_register_bar_region(&proxy->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO,
-                            &proxy->bar);
+    pci_register_bar(&proxy->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO,
+                     &proxy->bar);
 
     if (!kvm_has_many_ioeventfds()) {
         proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD;
diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
index 02b7478..d5cfa70 100644
--- a/hw/vmware_vga.c
+++ b/hw/vmware_vga.c
@@ -1291,13 +1291,13 @@ static int pci_vmsvga_initfn(PCIDevice *dev)
 
     memory_region_init_io(&s->io_bar, &vmsvga_io_ops, &s->chip,
                           "vmsvga-io", 0x10);
-    pci_register_bar_region(&s->card, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_bar);
+    pci_register_bar(&s->card, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_bar);
 
     vmsvga_init(&s->chip, VGA_RAM_SIZE);
 
-    pci_register_bar_region(&s->card, 1, PCI_BASE_ADDRESS_MEM_PREFETCH, iomem);
-    pci_register_bar_region(&s->card, 2, PCI_BASE_ADDRESS_MEM_PREFETCH,
-                            &s->chip.fifo_ram);
+    pci_register_bar(&s->card, 1, PCI_BASE_ADDRESS_MEM_PREFETCH, iomem);
+    pci_register_bar(&s->card, 2, PCI_BASE_ADDRESS_MEM_PREFETCH,
+                     &s->chip.fifo_ram);
 
     if (!dev->rom_bar) {
         /* compatibility with pc-0.13 and older */
diff --git a/hw/wdt_i6300esb.c b/hw/wdt_i6300esb.c
index abc2e17..20d8673 100644
--- a/hw/wdt_i6300esb.c
+++ b/hw/wdt_i6300esb.c
@@ -405,7 +405,7 @@ static int i6300esb_init(PCIDevice *dev)
     d->previous_reboot_flag = 0;
 
     memory_region_init_io(&d->io_mem, &i6300esb_ops, d, "i6300esb", 0x10);
-    pci_register_bar_region(&d->dev, 0, 0, &d->io_mem);
+    pci_register_bar(&d->dev, 0, 0, &d->io_mem);
     /* qemu_register_coalesced_mmio (addr, 0x10); ? */
 
     return 0;
diff --git a/hw/xen_platform.c b/hw/xen_platform.c
index 0b89075..6e3ba8b 100644
--- a/hw/xen_platform.c
+++ b/hw/xen_platform.c
@@ -353,13 +353,12 @@ static int xen_platform_initfn(PCIDevice *dev)
     pci_conf[PCI_INTERRUPT_PIN] = 1;
 
     platform_ioport_bar_setup(d);
-    pci_register_bar_region(&d->pci_dev, 0,
-                            PCI_BASE_ADDRESS_SPACE_IO, &d->bar);
+    pci_register_bar(&d->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &d->bar);
 
     /* reserve 16MB mmio address for share memory*/
     platform_mmio_setup(d);
-    pci_register_bar_region(&d->pci_dev, 1,
-                            PCI_BASE_ADDRESS_MEM_PREFETCH, &d->mmio_bar);
+    pci_register_bar(&d->pci_dev, 1, PCI_BASE_ADDRESS_MEM_PREFETCH,
+                     &d->mmio_bar);
 
     platform_fixed_ioport_init(d);
 
commit 50181f10dae755aad2b4f4f486d18e48dd66ea37
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:09:30 2011 +0300

    pci: fold BAR mapping function into its caller
    
    There is only one function, so no need for a function pointer.
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/pci.c b/hw/pci.c
index 62b34d4..aa17395 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -881,18 +881,6 @@ static int pci_unregister_device(DeviceState *dev)
     return 0;
 }
 
-static void pci_simple_bar_mapfunc_region(PCIDevice *pci_dev, int region_num,
-                                          pcibus_t addr, pcibus_t size,
-                                          int type)
-{
-    PCIIORegion *r = &pci_dev->io_regions[region_num];
-
-    memory_region_add_subregion_overlap(r->address_space,
-                                        addr,
-                                        r->memory,
-                                        1);
-}
-
 void pci_register_bar_region(PCIDevice *pci_dev, int region_num,
                              uint8_t type, MemoryRegion *memory)
 {
@@ -914,7 +902,6 @@ void pci_register_bar_region(PCIDevice *pci_dev, int region_num,
     r->size = size;
     r->filtered_size = size;
     r->type = type;
-    r->map_func = pci_simple_bar_mapfunc_region;
     r->memory = NULL;
 
     wmask = ~(size - 1);
@@ -1102,10 +1089,16 @@ static void pci_update_mappings(PCIDevice *d)
              * addr & (size - 1) != 0.
              */
             if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
-                r->map_func(d, i, r->addr, r->filtered_size, r->type);
+                memory_region_add_subregion_overlap(r->address_space,
+                                                    r->addr,
+                                                    r->memory,
+                                                    1);
             } else {
-                r->map_func(d, i, pci_to_cpu_addr(d->bus, r->addr),
-                            r->filtered_size, r->type);
+                memory_region_add_subregion_overlap(r->address_space,
+                                                    pci_to_cpu_addr(d->bus,
+                                                                    r->addr),
+                                                    r->memory,
+                                                    1);
             }
         }
     }
diff --git a/hw/pci.h b/hw/pci.h
index 8028176..8d1662a 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -92,7 +92,6 @@ typedef struct PCIIORegion {
     pcibus_t size;
     pcibus_t filtered_size;
     uint8_t type;
-    PCIMapIORegionFunc *map_func;
     MemoryRegion *memory;
     MemoryRegion *address_space;
 } PCIIORegion;
commit cfc0be257ca75abf357757661d4950aeeb4a8835
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:09:29 2011 +0300

    pci: remove pci_register_bar()
    
    Superceded by pci_register_bar_region().  The implementations
    are folded together.
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/pci.c b/hw/pci.c
index f885d4e..62b34d4 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -881,13 +881,25 @@ static int pci_unregister_device(DeviceState *dev)
     return 0;
 }
 
-void pci_register_bar(PCIDevice *pci_dev, int region_num,
-                            pcibus_t size, uint8_t type,
-                            PCIMapIORegionFunc *map_func)
+static void pci_simple_bar_mapfunc_region(PCIDevice *pci_dev, int region_num,
+                                          pcibus_t addr, pcibus_t size,
+                                          int type)
+{
+    PCIIORegion *r = &pci_dev->io_regions[region_num];
+
+    memory_region_add_subregion_overlap(r->address_space,
+                                        addr,
+                                        r->memory,
+                                        1);
+}
+
+void pci_register_bar_region(PCIDevice *pci_dev, int region_num,
+                             uint8_t type, MemoryRegion *memory)
 {
     PCIIORegion *r;
     uint32_t addr;
     uint64_t wmask;
+    pcibus_t size = memory_region_size(memory);
 
     assert(region_num >= 0);
     assert(region_num < PCI_NUM_REGIONS);
@@ -902,7 +914,7 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
     r->size = size;
     r->filtered_size = size;
     r->type = type;
-    r->map_func = map_func;
+    r->map_func = pci_simple_bar_mapfunc_region;
     r->memory = NULL;
 
     wmask = ~(size - 1);
@@ -920,29 +932,9 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
         pci_set_long(pci_dev->wmask + addr, wmask & 0xffffffff);
         pci_set_long(pci_dev->cmask + addr, 0xffffffff);
     }
-}
-
-static void pci_simple_bar_mapfunc_region(PCIDevice *pci_dev, int region_num,
-                                          pcibus_t addr, pcibus_t size,
-                                          int type)
-{
-    PCIIORegion *r = &pci_dev->io_regions[region_num];
-
-    memory_region_add_subregion_overlap(r->address_space,
-                                        addr,
-                                        r->memory,
-                                        1);
-}
-
-void pci_register_bar_region(PCIDevice *pci_dev, int region_num,
-                             uint8_t attr, MemoryRegion *memory)
-{
-    pci_register_bar(pci_dev, region_num, memory_region_size(memory),
-                     attr,
-                     pci_simple_bar_mapfunc_region);
     pci_dev->io_regions[region_num].memory = memory;
     pci_dev->io_regions[region_num].address_space
-        = attr & PCI_BASE_ADDRESS_SPACE_IO
+        = type & PCI_BASE_ADDRESS_SPACE_IO
         ? pci_dev->bus->address_space_io
         : pci_dev->bus->address_space_mem;
 }
diff --git a/hw/pci.h b/hw/pci.h
index 6e2bcea..8028176 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -201,9 +201,6 @@ PCIDevice *pci_register_device(PCIBus *bus, const char *name,
                                PCIConfigReadFunc *config_read,
                                PCIConfigWriteFunc *config_write);
 
-void pci_register_bar(PCIDevice *pci_dev, int region_num,
-                            pcibus_t size, uint8_t type,
-                            PCIMapIORegionFunc *map_func);
 void pci_register_bar_region(PCIDevice *pci_dev, int region_num,
                              uint8_t attr, MemoryRegion *memory);
 pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num);
commit 14caaf7f422b412b55d8cde06767ced003fc31c3
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:09:28 2011 +0300

    pci: convert pci rom to memory API
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/pci.c b/hw/pci.c
index 7a70037..f885d4e 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -1855,11 +1855,6 @@ static uint8_t pci_find_capability_list(PCIDevice *pdev, uint8_t cap_id,
     return next;
 }
 
-static void pci_map_option_rom(PCIDevice *pdev, int region_num, pcibus_t addr, pcibus_t size, int type)
-{
-    cpu_register_physical_memory(addr, size, pdev->rom_offset);
-}
-
 /* Patch the PCI vendor and device ids in a PCI rom image if necessary.
    This is needed for an option rom which is used for more than one device. */
 static void pci_patch_ids(PCIDevice *pdev, uint8_t *ptr, int size)
@@ -1963,9 +1958,9 @@ static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom)
         snprintf(name, sizeof(name), "%s.rom", pdev->qdev.info->vmsd->name);
     else
         snprintf(name, sizeof(name), "%s.rom", pdev->qdev.info->name);
-    pdev->rom_offset = qemu_ram_alloc(&pdev->qdev, name, size);
-
-    ptr = qemu_get_ram_ptr(pdev->rom_offset);
+    pdev->has_rom = true;
+    memory_region_init_ram(&pdev->rom, &pdev->qdev, name, size);
+    ptr = memory_region_get_ram_ptr(&pdev->rom);
     load_image(path, ptr);
     qemu_free(path);
 
@@ -1976,19 +1971,18 @@ static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom)
 
     qemu_put_ram_ptr(ptr);
 
-    pci_register_bar(pdev, PCI_ROM_SLOT, size,
-                     0, pci_map_option_rom);
+    pci_register_bar_region(pdev, PCI_ROM_SLOT, 0, &pdev->rom);
 
     return 0;
 }
 
 static void pci_del_option_rom(PCIDevice *pdev)
 {
-    if (!pdev->rom_offset)
+    if (!pdev->has_rom)
         return;
 
-    qemu_ram_free(pdev->rom_offset);
-    pdev->rom_offset = 0;
+    memory_region_destroy(&pdev->rom);
+    pdev->has_rom = false;
 }
 
 /*
diff --git a/hw/pci.h b/hw/pci.h
index 25e28b1..6e2bcea 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -191,7 +191,8 @@ struct PCIDevice {
 
     /* Location of option rom */
     char *romfile;
-    ram_addr_t rom_offset;
+    bool has_rom;
+    MemoryRegion rom;
     uint32_t rom_bar;
 };
 
commit fa6c606589a908a4254e61571296e77593763bfa
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:09:27 2011 +0300

    pci: remove pci_register_bar_simple()
    
    Superceded by pci_register_bar_region().
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/pci.c b/hw/pci.c
index c00cbf8..7a70037 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -903,7 +903,6 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
     r->filtered_size = size;
     r->type = type;
     r->map_func = map_func;
-    r->ram_addr = IO_MEM_UNASSIGNED;
     r->memory = NULL;
 
     wmask = ~(size - 1);
@@ -923,13 +922,6 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
     }
 }
 
-static void pci_simple_bar_mapfunc(PCIDevice *pci_dev, int region_num,
-                                   pcibus_t addr, pcibus_t size, int type)
-{
-    cpu_register_physical_memory(addr, size,
-                                 pci_dev->io_regions[region_num].ram_addr);
-}
-
 static void pci_simple_bar_mapfunc_region(PCIDevice *pci_dev, int region_num,
                                           pcibus_t addr, pcibus_t size,
                                           int type)
@@ -942,15 +934,6 @@ static void pci_simple_bar_mapfunc_region(PCIDevice *pci_dev, int region_num,
                                         1);
 }
 
-void pci_register_bar_simple(PCIDevice *pci_dev, int region_num,
-                             pcibus_t size,  uint8_t attr, ram_addr_t ram_addr)
-{
-    pci_register_bar(pci_dev, region_num, size,
-                     PCI_BASE_ADDRESS_SPACE_MEMORY | attr,
-                     pci_simple_bar_mapfunc);
-    pci_dev->io_regions[region_num].ram_addr = ram_addr;
-}
-
 void pci_register_bar_region(PCIDevice *pci_dev, int region_num,
                              uint8_t attr, MemoryRegion *memory)
 {
diff --git a/hw/pci.h b/hw/pci.h
index a95e2ad..25e28b1 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -93,7 +93,6 @@ typedef struct PCIIORegion {
     pcibus_t filtered_size;
     uint8_t type;
     PCIMapIORegionFunc *map_func;
-    ram_addr_t ram_addr;
     MemoryRegion *memory;
     MemoryRegion *address_space;
 } PCIIORegion;
@@ -204,8 +203,6 @@ PCIDevice *pci_register_device(PCIBus *bus, const char *name,
 void pci_register_bar(PCIDevice *pci_dev, int region_num,
                             pcibus_t size, uint8_t type,
                             PCIMapIORegionFunc *map_func);
-void pci_register_bar_simple(PCIDevice *pci_dev, int region_num,
-                             pcibus_t size, uint8_t attr, ram_addr_t ram_addr);
 void pci_register_bar_region(PCIDevice *pci_dev, int region_num,
                              uint8_t attr, MemoryRegion *memory);
 pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num);
commit 95524ae8dc8f06da0d6ba37703038238e3b27066
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:09:26 2011 +0300

    msix: convert to memory API
    
    The msix table is defined as a subregion, to allow for a BAR that
    mixes device specific regions with the msix table.
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/ivshmem.c b/hw/ivshmem.c
index f80e7b6..bacba60 100644
--- a/hw/ivshmem.c
+++ b/hw/ivshmem.c
@@ -65,6 +65,7 @@ typedef struct IVShmemState {
      */
     MemoryRegion bar;
     MemoryRegion ivshmem;
+    MemoryRegion msix_bar;
     uint64_t ivshmem_size; /* size of shared memory region */
     int shm_fd; /* shared memory file descriptor */
 
@@ -540,11 +541,11 @@ static void ivshmem_setup_msi(IVShmemState * s) {
 
     /* 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);
+    memory_region_init(&s->msix_bar, "ivshmem-msix", 4096);
+    if (!msix_init(&s->dev, s->vectors, &s->msix_bar, 1, 0)) {
+        pci_register_bar_region(&s->dev, 1,
+                                PCI_BASE_ADDRESS_SPACE_MEMORY,
+                                &s->msix_bar);
         IVSHMEM_DPRINTF("msix initialized (%d vectors)\n", s->vectors);
     } else {
         IVSHMEM_DPRINTF("msix initialization failed\n");
diff --git a/hw/msix.c b/hw/msix.c
index e67e700..8536c3f 100644
--- a/hw/msix.c
+++ b/hw/msix.c
@@ -82,7 +82,8 @@ static int msix_add_config(struct PCIDevice *pdev, unsigned short nentries,
     return 0;
 }
 
-static uint32_t msix_mmio_readl(void *opaque, target_phys_addr_t addr)
+static uint64_t msix_mmio_read(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
 {
     PCIDevice *dev = opaque;
     unsigned int offset = addr & (MSIX_PAGE_SIZE - 1) & ~0x3;
@@ -91,12 +92,6 @@ static uint32_t msix_mmio_readl(void *opaque, target_phys_addr_t addr)
     return pci_get_long(page + offset);
 }
 
-static uint32_t msix_mmio_read_unallowed(void *opaque, target_phys_addr_t addr)
-{
-    fprintf(stderr, "MSI-X: only dword read is allowed!\n");
-    return 0;
-}
-
 static uint8_t msix_pending_mask(int vector)
 {
     return 1 << (vector % 8);
@@ -169,8 +164,8 @@ void msix_write_config(PCIDevice *dev, uint32_t addr,
     }
 }
 
-static void msix_mmio_writel(void *opaque, target_phys_addr_t addr,
-                             uint32_t val)
+static void msix_mmio_write(void *opaque, target_phys_addr_t addr,
+                            uint64_t val, unsigned size)
 {
     PCIDevice *dev = opaque;
     unsigned int offset = addr & (MSIX_PAGE_SIZE - 1) & ~0x3;
@@ -179,37 +174,25 @@ static void msix_mmio_writel(void *opaque, target_phys_addr_t addr,
     msix_handle_mask_update(dev, vector);
 }
 
-static void msix_mmio_write_unallowed(void *opaque, target_phys_addr_t addr,
-                                      uint32_t val)
-{
-    fprintf(stderr, "MSI-X: only dword write is allowed!\n");
-}
-
-static CPUWriteMemoryFunc * const msix_mmio_write[] = {
-    msix_mmio_write_unallowed, msix_mmio_write_unallowed, msix_mmio_writel
-};
-
-static CPUReadMemoryFunc * const msix_mmio_read[] = {
-    msix_mmio_read_unallowed, msix_mmio_read_unallowed, msix_mmio_readl
+static const MemoryRegionOps msix_mmio_ops = {
+    .read = msix_mmio_read,
+    .write = msix_mmio_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
 };
 
-/* Should be called from device's map method. */
-void msix_mmio_map(PCIDevice *d, int region_num,
-                   pcibus_t addr, pcibus_t size, int type)
+static void msix_mmio_setup(PCIDevice *d, MemoryRegion *bar)
 {
     uint8_t *config = d->config + d->msix_cap;
     uint32_t table = pci_get_long(config + PCI_MSIX_TABLE);
     uint32_t offset = table & ~(MSIX_PAGE_SIZE - 1);
     /* TODO: for assigned devices, we'll want to make it possible to map
      * pending bits separately in case they are in a separate bar. */
-    int table_bir = table & PCI_MSIX_FLAGS_BIRMASK;
 
-    if (table_bir != region_num)
-        return;
-    if (size <= offset)
-        return;
-    cpu_register_physical_memory(addr + offset, size - offset,
-                                 d->msix_mmio_index);
+    memory_region_add_subregion(bar, offset, &d->msix_mmio);
 }
 
 static void msix_mask_all(struct PCIDevice *dev, unsigned nentries)
@@ -225,6 +208,7 @@ static void msix_mask_all(struct PCIDevice *dev, unsigned nentries)
 /* Initialize the MSI-X structures. Note: if MSI-X is supported, BAR size is
  * modified, it should be retrieved with msix_bar_size. */
 int msix_init(struct PCIDevice *dev, unsigned short nentries,
+              MemoryRegion *bar,
               unsigned bar_nr, unsigned bar_size)
 {
     int ret;
@@ -241,13 +225,8 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries,
     dev->msix_table_page = qemu_mallocz(MSIX_PAGE_SIZE);
     msix_mask_all(dev, nentries);
 
-    dev->msix_mmio_index = cpu_register_io_memory(msix_mmio_read,
-                                                  msix_mmio_write, dev,
-                                                  DEVICE_NATIVE_ENDIAN);
-    if (dev->msix_mmio_index == -1) {
-        ret = -EBUSY;
-        goto err_index;
-    }
+    memory_region_init_io(&dev->msix_mmio, &msix_mmio_ops, dev,
+                          "msix", MSIX_PAGE_SIZE);
 
     dev->msix_entries_nr = nentries;
     ret = msix_add_config(dev, nentries, bar_nr, bar_size);
@@ -255,12 +234,12 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries,
         goto err_config;
 
     dev->cap_present |= QEMU_PCI_CAP_MSIX;
+    msix_mmio_setup(dev, bar);
     return 0;
 
 err_config:
     dev->msix_entries_nr = 0;
-    cpu_unregister_io_memory(dev->msix_mmio_index);
-err_index:
+    memory_region_destroy(&dev->msix_mmio);
     qemu_free(dev->msix_table_page);
     dev->msix_table_page = NULL;
     qemu_free(dev->msix_entry_used);
@@ -279,7 +258,7 @@ static void msix_free_irq_entries(PCIDevice *dev)
 }
 
 /* Clean up resources for the device. */
-int msix_uninit(PCIDevice *dev)
+int msix_uninit(PCIDevice *dev, MemoryRegion *bar)
 {
     if (!(dev->cap_present & QEMU_PCI_CAP_MSIX))
         return 0;
@@ -287,7 +266,8 @@ int msix_uninit(PCIDevice *dev)
     dev->msix_cap = 0;
     msix_free_irq_entries(dev);
     dev->msix_entries_nr = 0;
-    cpu_unregister_io_memory(dev->msix_mmio_index);
+    memory_region_del_subregion(bar, &dev->msix_mmio);
+    memory_region_destroy(&dev->msix_mmio);
     qemu_free(dev->msix_table_page);
     dev->msix_table_page = NULL;
     qemu_free(dev->msix_entry_used);
diff --git a/hw/msix.h b/hw/msix.h
index a9f7993..7e04336 100644
--- a/hw/msix.h
+++ b/hw/msix.h
@@ -5,15 +5,13 @@
 #include "pci.h"
 
 int msix_init(PCIDevice *pdev, unsigned short nentries,
+              MemoryRegion *bar,
               unsigned bar_nr, unsigned bar_size);
 
 void msix_write_config(PCIDevice *pci_dev, uint32_t address,
                        uint32_t val, int len);
 
-void msix_mmio_map(PCIDevice *pci_dev, int region_num,
-                   pcibus_t addr, pcibus_t size, int type);
-
-int msix_uninit(PCIDevice *d);
+int msix_uninit(PCIDevice *d, MemoryRegion *bar);
 
 void msix_save(PCIDevice *dev, QEMUFile *f);
 void msix_load(PCIDevice *dev, QEMUFile *f);
diff --git a/hw/pci.h b/hw/pci.h
index 928e96c..a95e2ad 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -176,7 +176,7 @@ struct PCIDevice {
     /* Space to store MSIX table */
     uint8_t *msix_table_page;
     /* MMIO index used to map MSIX table and pending bit entries. */
-    int msix_mmio_index;
+    MemoryRegion msix_mmio;
     /* Reference-count for entries actually in use by driver. */
     unsigned *msix_entry_used;
     /* Region including the MSI-X table */
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index 86c3229..95203c8 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -641,11 +641,12 @@ void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev)
     pci_set_word(config + 0x2e, vdev->device_id);
     config[0x3d] = 1;
 
-    if (vdev->nvectors && !msix_init(&proxy->pci_dev, vdev->nvectors, 1, 0)) {
-        pci_register_bar(&proxy->pci_dev, 1,
-                         msix_bar_size(&proxy->pci_dev),
-                         PCI_BASE_ADDRESS_SPACE_MEMORY,
-                         msix_mmio_map);
+    memory_region_init(&proxy->msix_bar, "virtio-msix", 4096);
+    if (vdev->nvectors && !msix_init(&proxy->pci_dev, vdev->nvectors,
+                                     &proxy->msix_bar, 1, 0)) {
+        pci_register_bar_region(&proxy->pci_dev, 1,
+                                PCI_BASE_ADDRESS_SPACE_MEMORY,
+                                &proxy->msix_bar);
     } else
         vdev->nvectors = 0;
 
@@ -694,9 +695,12 @@ static int virtio_blk_init_pci(PCIDevice *pci_dev)
 static int virtio_exit_pci(PCIDevice *pci_dev)
 {
     VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+    int r;
 
     memory_region_destroy(&proxy->bar);
-    return msix_uninit(pci_dev);
+    r = msix_uninit(pci_dev, &proxy->msix_bar);
+    memory_region_destroy(&proxy->msix_bar);
+    return r;
 }
 
 static int virtio_blk_exit_pci(PCIDevice *pci_dev)
diff --git a/hw/virtio-pci.h b/hw/virtio-pci.h
index 5af1c8c..14c10f7 100644
--- a/hw/virtio-pci.h
+++ b/hw/virtio-pci.h
@@ -22,6 +22,7 @@ typedef struct {
     PCIDevice pci_dev;
     VirtIODevice *vdev;
     MemoryRegion bar;
+    MemoryRegion msix_bar;
     uint32_t flags;
     uint32_t class_code;
     uint32_t nvectors;
commit de00982e9e14e2d6ba3d148f02c5a1e94deaa985
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:09:25 2011 +0300

    xen-platform: convert to memory API
    
    Since this device bypasses PCI and registers I/O ports directly with
    the system bus, it needs further attention.
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/xen_platform.c b/hw/xen_platform.c
index fb6be6a..0b89075 100644
--- a/hw/xen_platform.c
+++ b/hw/xen_platform.c
@@ -32,8 +32,8 @@
 #include "xen_common.h"
 #include "net.h"
 #include "xen_backend.h"
-#include "rwhandler.h"
 #include "trace.h"
+#include "exec-memory.h"
 
 #include <xenguest.h>
 
@@ -51,6 +51,9 @@
 
 typedef struct PCIXenPlatformState {
     PCIDevice  pci_dev;
+    MemoryRegion fixed_io;
+    MemoryRegion bar;
+    MemoryRegion mmio_bar;
     uint8_t flags; /* used only for version_id == 2 */
     int drivers_blacklisted;
     uint16_t driver_product_version;
@@ -221,21 +224,32 @@ static void platform_fixed_ioport_reset(void *opaque)
     platform_fixed_ioport_writeb(s, XEN_PLATFORM_IOPORT, 0);
 }
 
+const MemoryRegionPortio xen_platform_ioport[] = {
+    { 0, 16, 4, .write = platform_fixed_ioport_writel, },
+    { 0, 16, 2, .write = platform_fixed_ioport_writew, },
+    { 0, 16, 1, .write = platform_fixed_ioport_writeb, },
+    { 0, 16, 2, .read = platform_fixed_ioport_readw, },
+    { 0, 16, 1, .read = platform_fixed_ioport_readb, },
+    PORTIO_END_OF_LIST()
+};
+
+static const MemoryRegionOps platform_fixed_io_ops = {
+    .old_portio = xen_platform_ioport,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
 static void platform_fixed_ioport_init(PCIXenPlatformState* s)
 {
-    register_ioport_write(XEN_PLATFORM_IOPORT, 16, 4, platform_fixed_ioport_writel, s);
-    register_ioport_write(XEN_PLATFORM_IOPORT, 16, 2, platform_fixed_ioport_writew, s);
-    register_ioport_write(XEN_PLATFORM_IOPORT, 16, 1, platform_fixed_ioport_writeb, s);
-    register_ioport_read(XEN_PLATFORM_IOPORT, 16, 2, platform_fixed_ioport_readw, s);
-    register_ioport_read(XEN_PLATFORM_IOPORT, 16, 1, platform_fixed_ioport_readb, s);
+    memory_region_init_io(&s->fixed_io, &platform_fixed_io_ops, s,
+                          "xen-fixed", 16);
+    memory_region_add_subregion(get_system_io(), XEN_PLATFORM_IOPORT,
+                                &s->fixed_io);
 }
 
 /* Xen Platform PCI Device */
 
 static uint32_t xen_platform_ioport_readb(void *opaque, uint32_t addr)
 {
-    addr &= 0xff;
-
     if (addr == 0) {
         return platform_fixed_ioport_readb(opaque, XEN_PLATFORM_IOPORT);
     } else {
@@ -247,9 +261,6 @@ static void xen_platform_ioport_writeb(void *opaque, uint32_t addr, uint32_t val
 {
     PCIXenPlatformState *s = opaque;
 
-    addr &= 0xff;
-    val  &= 0xff;
-
     switch (addr) {
     case 0: /* Platform flags */
         platform_fixed_ioport_writeb(opaque, XEN_PLATFORM_IOPORT, val);
@@ -262,15 +273,23 @@ static void xen_platform_ioport_writeb(void *opaque, uint32_t addr, uint32_t val
     }
 }
 
-static void platform_ioport_map(PCIDevice *pci_dev, int region_num, pcibus_t addr, pcibus_t size, int type)
-{
-    PCIXenPlatformState *d = DO_UPCAST(PCIXenPlatformState, pci_dev, pci_dev);
+static MemoryRegionPortio xen_pci_portio[] = {
+    { 0, 0x100, 1, .read = xen_platform_ioport_readb, },
+    { 0, 0x100, 1, .write = xen_platform_ioport_writeb, },
+    PORTIO_END_OF_LIST()
+};
+
+static const MemoryRegionOps xen_pci_io_ops = {
+    .old_portio = xen_pci_portio,
+};
 
-    register_ioport_write(addr, size, 1, xen_platform_ioport_writeb, d);
-    register_ioport_read(addr, size, 1, xen_platform_ioport_readb, d);
+static void platform_ioport_bar_setup(PCIXenPlatformState *d)
+{
+    memory_region_init_io(&d->bar, &xen_pci_io_ops, d, "xen-pci", 0x100);
 }
 
-static uint32_t platform_mmio_read(ReadWriteHandler *handler, pcibus_t addr, int len)
+static uint64_t platform_mmio_read(void *opaque, target_phys_addr_t addr,
+                                   unsigned size)
 {
     DPRINTF("Warning: attempted read from physical address "
             "0x" TARGET_FMT_plx " in xen platform mmio space\n", addr);
@@ -278,28 +297,24 @@ static uint32_t platform_mmio_read(ReadWriteHandler *handler, pcibus_t addr, int
     return 0;
 }
 
-static void platform_mmio_write(ReadWriteHandler *handler, pcibus_t addr,
-                                uint32_t val, int len)
+static void platform_mmio_write(void *opaque, target_phys_addr_t addr,
+                                uint64_t val, unsigned size)
 {
-    DPRINTF("Warning: attempted write of 0x%x to physical "
+    DPRINTF("Warning: attempted write of 0x%"PRIx64" to physical "
             "address 0x" TARGET_FMT_plx " in xen platform mmio space\n",
             val, addr);
 }
 
-static ReadWriteHandler platform_mmio_handler = {
+static const MemoryRegionOps platform_mmio_handler = {
     .read = &platform_mmio_read,
     .write = &platform_mmio_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static void platform_mmio_map(PCIDevice *d, int region_num,
-                              pcibus_t addr, pcibus_t size, int type)
+static void platform_mmio_setup(PCIXenPlatformState *d)
 {
-    int mmio_io_addr;
-
-    mmio_io_addr = cpu_register_io_memory_simple(&platform_mmio_handler,
-                                                 DEVICE_NATIVE_ENDIAN);
-
-    cpu_register_physical_memory(addr, size, mmio_io_addr);
+    memory_region_init_io(&d->mmio_bar, &platform_mmio_handler, d,
+                          "xen-mmio", 0x1000000);
 }
 
 static int xen_platform_post_load(void *opaque, int version_id)
@@ -337,12 +352,14 @@ static int xen_platform_initfn(PCIDevice *dev)
 
     pci_conf[PCI_INTERRUPT_PIN] = 1;
 
-    pci_register_bar(&d->pci_dev, 0, 0x100,
-            PCI_BASE_ADDRESS_SPACE_IO, platform_ioport_map);
+    platform_ioport_bar_setup(d);
+    pci_register_bar_region(&d->pci_dev, 0,
+                            PCI_BASE_ADDRESS_SPACE_IO, &d->bar);
 
     /* reserve 16MB mmio address for share memory*/
-    pci_register_bar(&d->pci_dev, 1, 0x1000000,
-            PCI_BASE_ADDRESS_MEM_PREFETCH, platform_mmio_map);
+    platform_mmio_setup(d);
+    pci_register_bar_region(&d->pci_dev, 1,
+                            PCI_BASE_ADDRESS_MEM_PREFETCH, &d->mmio_bar);
 
     platform_fixed_ioport_init(d);
 
commit a03f66e4ac5711109cf958952e132c1eb3704b73
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:09:24 2011 +0300

    uhci: convert to memory API
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index 824e3a5..ea38169 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -129,6 +129,7 @@ typedef struct UHCIPort {
 
 struct UHCIState {
     PCIDevice dev;
+    MemoryRegion io_bar;
     USBBus bus; /* Note unused when we're a companion controller */
     uint16_t cmd; /* cmd register */
     uint16_t status;
@@ -1096,18 +1097,19 @@ static void uhci_frame_timer(void *opaque)
     qemu_mod_timer(s->frame_timer, s->expire_time);
 }
 
-static void uhci_map(PCIDevice *pci_dev, int region_num,
-                    pcibus_t addr, pcibus_t size, int type)
-{
-    UHCIState *s = (UHCIState *)pci_dev;
-
-    register_ioport_write(addr, 32, 2, uhci_ioport_writew, s);
-    register_ioport_read(addr, 32, 2, uhci_ioport_readw, s);
-    register_ioport_write(addr, 32, 4, uhci_ioport_writel, s);
-    register_ioport_read(addr, 32, 4, uhci_ioport_readl, s);
-    register_ioport_write(addr, 32, 1, uhci_ioport_writeb, s);
-    register_ioport_read(addr, 32, 1, uhci_ioport_readb, s);
-}
+static const MemoryRegionPortio uhci_portio[] = {
+    { 0, 32, 2, .write = uhci_ioport_writew, },
+    { 0, 32, 2, .read = uhci_ioport_readw, },
+    { 0, 32, 4, .write = uhci_ioport_writel, },
+    { 0, 32, 4, .read = uhci_ioport_readl, },
+    { 0, 32, 1, .write = uhci_ioport_writeb, },
+    { 0, 32, 1, .read = uhci_ioport_readb, },
+    PORTIO_END_OF_LIST()
+};
+
+static const MemoryRegionOps uhci_ioport_ops = {
+    .old_portio = uhci_portio,
+};
 
 static USBPortOps uhci_port_ops = {
     .attach = uhci_attach,
@@ -1154,10 +1156,11 @@ static int usb_uhci_common_initfn(PCIDevice *dev)
 
     qemu_register_reset(uhci_reset, s);
 
+    memory_region_init_io(&s->io_bar, &uhci_ioport_ops, s, "uhci", 0x20);
     /* Use region 4 for consistency with real hardware.  BSD guests seem
        to rely on this.  */
-    pci_register_bar(&s->dev, 4, 0x20,
-                           PCI_BASE_ADDRESS_SPACE_IO, uhci_map);
+    pci_register_bar_region(&s->dev, 4,
+                            PCI_BASE_ADDRESS_SPACE_IO, &s->io_bar);
 
     return 0;
 }
@@ -1177,6 +1180,14 @@ static int usb_uhci_vt82c686b_initfn(PCIDevice *dev)
     return usb_uhci_common_initfn(dev);
 }
 
+static int usb_uhci_exit(PCIDevice *dev)
+{
+    UHCIState *s = DO_UPCAST(UHCIState, dev, dev);
+
+    memory_region_destroy(&s->io_bar);
+    return 0;
+}
+
 static Property uhci_properties[] = {
     DEFINE_PROP_STRING("masterbus", UHCIState, masterbus),
     DEFINE_PROP_UINT32("firstport", UHCIState, firstport, 0),
@@ -1189,6 +1200,7 @@ static PCIDeviceInfo uhci_info[] = {
         .qdev.size    = sizeof(UHCIState),
         .qdev.vmsd    = &vmstate_uhci,
         .init         = usb_uhci_common_initfn,
+        .exit         = usb_uhci_exit,
         .vendor_id    = PCI_VENDOR_ID_INTEL,
         .device_id    = PCI_DEVICE_ID_INTEL_82371SB_2,
         .revision     = 0x01,
@@ -1199,6 +1211,7 @@ static PCIDeviceInfo uhci_info[] = {
         .qdev.size    = sizeof(UHCIState),
         .qdev.vmsd    = &vmstate_uhci,
         .init         = usb_uhci_common_initfn,
+        .exit         = usb_uhci_exit,
         .vendor_id    = PCI_VENDOR_ID_INTEL,
         .device_id    = PCI_DEVICE_ID_INTEL_82371AB_2,
         .revision     = 0x01,
@@ -1209,6 +1222,7 @@ static PCIDeviceInfo uhci_info[] = {
         .qdev.size    = sizeof(UHCIState),
         .qdev.vmsd    = &vmstate_uhci,
         .init         = usb_uhci_vt82c686b_initfn,
+        .exit         = usb_uhci_exit,
         .vendor_id    = PCI_VENDOR_ID_VIA,
         .device_id    = PCI_DEVICE_ID_VIA_UHCI,
         .revision     = 0x01,
commit e57964f5b32e499354533c4012d78f7a8c1a8bb7
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:09:23 2011 +0300

    ehci: convert to memory API
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 2b43895..6ef7798 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -370,8 +370,7 @@ struct EHCIState {
     PCIDevice dev;
     USBBus bus;
     qemu_irq irq;
-    target_phys_addr_t mem_base;
-    int mem;
+    MemoryRegion mem;
     int companion_count;
 
     /* properties */
@@ -2179,29 +2178,15 @@ static void ehci_frame_timer(void *opaque)
     qemu_mod_timer(ehci->frame_timer, expire_time);
 }
 
-static CPUReadMemoryFunc *ehci_readfn[3]={
-    ehci_mem_readb,
-    ehci_mem_readw,
-    ehci_mem_readl
-};
 
-static CPUWriteMemoryFunc *ehci_writefn[3]={
-    ehci_mem_writeb,
-    ehci_mem_writew,
-    ehci_mem_writel
+static const MemoryRegionOps ehci_mem_ops = {
+    .old_mmio = {
+        .read = { ehci_mem_readb, ehci_mem_readw, ehci_mem_readl },
+        .write = { ehci_mem_writeb, ehci_mem_writew, ehci_mem_writel },
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
-static void ehci_map(PCIDevice *pci_dev, int region_num,
-                     pcibus_t addr, pcibus_t size, int type)
-{
-    EHCIState *s =(EHCIState *)pci_dev;
-
-    DPRINTF("ehci_map: region %d, addr %08" PRIx64 ", size %" PRId64 ", s->mem %08X\n",
-            region_num, addr, size, s->mem);
-    s->mem_base = addr;
-    cpu_register_physical_memory(addr, size, s->mem);
-}
-
 static int usb_ehci_initfn(PCIDevice *dev);
 
 static USBPortOps ehci_port_ops = {
@@ -2316,11 +2301,8 @@ static int usb_ehci_initfn(PCIDevice *dev)
 
     qemu_register_reset(ehci_reset, s);
 
-    s->mem = cpu_register_io_memory(ehci_readfn, ehci_writefn, s,
-                                    DEVICE_LITTLE_ENDIAN);
-
-    pci_register_bar(&s->dev, 0, MMIO_SIZE, PCI_BASE_ADDRESS_SPACE_MEMORY,
-                                                            ehci_map);
+    memory_region_init_io(&s->mem, &ehci_mem_ops, s, "ehci", MMIO_SIZE);
+    pci_register_bar_region(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
 
     fprintf(stderr, "*** EHCI support is under development ***\n");
 
commit c5e6fb7e4ac6e7083682e7f45d27d1e73b3a1a97
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:09:22 2011 +0300

    sun4u: convert to memory API
    
    fixes memory leak on repeated BAR map/unmap
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/sun4u.c b/hw/sun4u.c
index d7dcaf0..cb76031 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -91,6 +91,12 @@ struct hwdef {
     uint64_t console_serial_base;
 };
 
+typedef struct EbusState {
+    PCIDevice pci_dev;
+    MemoryRegion bar0;
+    MemoryRegion bar1;
+} EbusState;
+
 int DMA_get_channel_mode (int nchan)
 {
     return 0;
@@ -518,21 +524,6 @@ void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit)
     }
 }
 
-static void ebus_mmio_mapfunc(PCIDevice *pci_dev, int region_num,
-                              pcibus_t addr, pcibus_t size, int type)
-{
-    EBUS_DPRINTF("Mapping region %d registers at %" FMT_PCIBUS "\n",
-                 region_num, addr);
-    switch (region_num) {
-    case 0:
-        isa_mmio_init(addr, 0x1000000);
-        break;
-    case 1:
-        isa_mmio_init(addr, 0x800000);
-        break;
-    }
-}
-
 static void dummy_isa_irq_handler(void *opaque, int n, int level)
 {
 }
@@ -549,27 +540,31 @@ pci_ebus_init(PCIBus *bus, int devfn)
 }
 
 static int
-pci_ebus_init1(PCIDevice *s)
+pci_ebus_init1(PCIDevice *pci_dev)
 {
-    isa_bus_new(&s->qdev);
+    EbusState *s = DO_UPCAST(EbusState, pci_dev, pci_dev);
+
+    isa_bus_new(&pci_dev->qdev);
 
-    s->config[0x04] = 0x06; // command = bus master, pci mem
-    s->config[0x05] = 0x00;
-    s->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
-    s->config[0x07] = 0x03; // status = medium devsel
-    s->config[0x09] = 0x00; // programming i/f
-    s->config[0x0D] = 0x0a; // latency_timer
+    pci_dev->config[0x04] = 0x06; // command = bus master, pci mem
+    pci_dev->config[0x05] = 0x00;
+    pci_dev->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
+    pci_dev->config[0x07] = 0x03; // status = medium devsel
+    pci_dev->config[0x09] = 0x00; // programming i/f
+    pci_dev->config[0x0D] = 0x0a; // latency_timer
 
-    pci_register_bar(s, 0, 0x1000000, PCI_BASE_ADDRESS_SPACE_MEMORY,
-                           ebus_mmio_mapfunc);
-    pci_register_bar(s, 1, 0x800000,  PCI_BASE_ADDRESS_SPACE_MEMORY,
-                           ebus_mmio_mapfunc);
+    isa_mmio_setup(&s->bar0, 0x1000000);
+    pci_register_bar_region(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
+                            &s->bar0);
+    isa_mmio_setup(&s->bar1, 0x800000);
+    pci_register_bar_region(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY,
+                            &s->bar1);
     return 0;
 }
 
 static PCIDeviceInfo ebus_info = {
     .qdev.name = "ebus",
-    .qdev.size = sizeof(PCIDevice),
+    .qdev.size = sizeof(EbusState),
     .init = pci_ebus_init1,
     .vendor_id = PCI_VENDOR_ID_SUN,
     .device_id = PCI_DEVICE_ID_SUN_EBUS,
commit af956cadc3c9f5e8cc96ea5b2f6e9f6852941f42
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:09:21 2011 +0300

    isa-mmio: convert to memory API
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/isa.h b/hw/isa.h
index d2b6126..f1f2181 100644
--- a/hw/isa.h
+++ b/hw/isa.h
@@ -4,6 +4,7 @@
 /* ISA bus */
 
 #include "ioport.h"
+#include "memory.h"
 #include "qdev.h"
 
 typedef struct ISABus ISABus;
@@ -37,6 +38,7 @@ ISADevice *isa_create_simple(const char *name);
 
 extern target_phys_addr_t isa_mem_base;
 
+void isa_mmio_setup(MemoryRegion *mr, target_phys_addr_t size);
 void isa_mmio_init(target_phys_addr_t base, target_phys_addr_t size);
 
 /* dma.c */
diff --git a/hw/isa_mmio.c b/hw/isa_mmio.c
index ca957fb..3d2af1a 100644
--- a/hw/isa_mmio.c
+++ b/hw/isa_mmio.c
@@ -24,6 +24,7 @@
 
 #include "hw.h"
 #include "isa.h"
+#include "exec-memory.h"
 
 static void isa_mmio_writeb (void *opaque, target_phys_addr_t addr,
                                   uint32_t val)
@@ -58,25 +59,23 @@ static uint32_t isa_mmio_readl(void *opaque, target_phys_addr_t addr)
     return cpu_inl(addr & IOPORTS_MASK);
 }
 
-static CPUWriteMemoryFunc * const isa_mmio_write[] = {
-    &isa_mmio_writeb,
-    &isa_mmio_writew,
-    &isa_mmio_writel,
+static const MemoryRegionOps isa_mmio_ops = {
+    .old_mmio = {
+        .write = { isa_mmio_writeb, isa_mmio_writew, isa_mmio_writel },
+        .read = { isa_mmio_readb, isa_mmio_readw, isa_mmio_readl, },
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
-static CPUReadMemoryFunc * const isa_mmio_read[] = {
-    &isa_mmio_readb,
-    &isa_mmio_readw,
-    &isa_mmio_readl,
-};
+void isa_mmio_setup(MemoryRegion *mr, target_phys_addr_t size)
+{
+    memory_region_init_io(mr, &isa_mmio_ops, NULL, "isa-mmio", size);
+}
 
 void isa_mmio_init(target_phys_addr_t base, target_phys_addr_t size)
 {
-    int isa_mmio_iomemtype;
+    MemoryRegion *mr = qemu_malloc(sizeof(*mr));
 
-    isa_mmio_iomemtype = cpu_register_io_memory(isa_mmio_read,
-                                                isa_mmio_write,
-                                                NULL,
-                                                DEVICE_LITTLE_ENDIAN);
-    cpu_register_physical_memory(base, size, isa_mmio_iomemtype);
+    isa_mmio_setup(mr, size);
+    memory_region_add_subregion(get_system_memory(), base, mr);
 }
commit d9c6ebd1c1d579dbbc566527a76cb7ab389b54bf
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:09:20 2011 +0300

    i6300esb: convert to memory API
    
    Also add missing destructor.
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/wdt_i6300esb.c b/hw/wdt_i6300esb.c
index 53786ce..abc2e17 100644
--- a/hw/wdt_i6300esb.c
+++ b/hw/wdt_i6300esb.c
@@ -66,6 +66,7 @@
 /* Device state. */
 struct I6300State {
     PCIDevice dev;
+    MemoryRegion io_mem;
 
     int reboot_enabled;         /* "Reboot" on timer expiry.  The real action
                                  * performed depends on the -watchdog-action
@@ -355,6 +356,22 @@ static void i6300esb_mem_writel(void *vp, target_phys_addr_t addr, uint32_t val)
     }
 }
 
+static const MemoryRegionOps i6300esb_ops = {
+    .old_mmio = {
+        .read = {
+            i6300esb_mem_readb,
+            i6300esb_mem_readw,
+            i6300esb_mem_readl,
+        },
+        .write = {
+            i6300esb_mem_writeb,
+            i6300esb_mem_writew,
+            i6300esb_mem_writel,
+        },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
 static const VMStateDescription vmstate_i6300esb = {
     .name = "i6300esb_wdt",
     .version_id = sizeof(I6300State),
@@ -381,31 +398,28 @@ static const VMStateDescription vmstate_i6300esb = {
 static int i6300esb_init(PCIDevice *dev)
 {
     I6300State *d = DO_UPCAST(I6300State, dev, dev);
-    int io_mem;
-    static CPUReadMemoryFunc * const mem_read[3] = {
-        i6300esb_mem_readb,
-        i6300esb_mem_readw,
-        i6300esb_mem_readl,
-    };
-    static CPUWriteMemoryFunc * const mem_write[3] = {
-        i6300esb_mem_writeb,
-        i6300esb_mem_writew,
-        i6300esb_mem_writel,
-    };
 
     i6300esb_debug("I6300State = %p\n", d);
 
     d->timer = qemu_new_timer_ns(vm_clock, i6300esb_timer_expired, d);
     d->previous_reboot_flag = 0;
 
-    io_mem = cpu_register_io_memory(mem_read, mem_write, d,
-                                    DEVICE_NATIVE_ENDIAN);
-    pci_register_bar_simple(&d->dev, 0, 0x10, 0, io_mem);
+    memory_region_init_io(&d->io_mem, &i6300esb_ops, d, "i6300esb", 0x10);
+    pci_register_bar_region(&d->dev, 0, 0, &d->io_mem);
     /* qemu_register_coalesced_mmio (addr, 0x10); ? */
 
     return 0;
 }
 
+static int i6300esb_exit(PCIDevice *dev)
+{
+    I6300State *d = DO_UPCAST(I6300State, dev, dev);
+
+    memory_region_destroy(&d->io_mem);
+
+    return 0;
+}
+
 static WatchdogTimerModel model = {
     .wdt_name = "i6300esb",
     .wdt_description = "Intel 6300ESB",
@@ -419,6 +433,7 @@ static PCIDeviceInfo i6300esb_info = {
     .config_read  = i6300esb_config_read,
     .config_write = i6300esb_config_write,
     .init         = i6300esb_init,
+    .exit         = i6300esb_exit,
     .vendor_id    = PCI_VENDOR_ID_INTEL,
     .device_id    = PCI_DEVICE_ID_INTEL_ESB_9,
     .class_id     = PCI_CLASS_SYSTEM_OTHER,
commit bd8d6f7cadb6ace98c779135217a4ed7b5fccc23
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:09:19 2011 +0300

    pcnet: convert to memory API
    
    Also related chips.
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/lance.c b/hw/lance.c
index ddb1cbb..8e20360 100644
--- a/hw/lance.c
+++ b/hw/lance.c
@@ -55,8 +55,8 @@ static void parent_lance_reset(void *opaque, int irq, int level)
         pcnet_h_reset(&d->state);
 }
 
-static void lance_mem_writew(void *opaque, target_phys_addr_t addr,
-                             uint32_t val)
+static void lance_mem_write(void *opaque, target_phys_addr_t addr,
+                            uint64_t val, unsigned size)
 {
     SysBusPCNetState *d = opaque;
 
@@ -64,7 +64,8 @@ static void lance_mem_writew(void *opaque, target_phys_addr_t addr,
     pcnet_ioport_writew(&d->state, addr, val & 0xffff);
 }
 
-static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr)
+static uint64_t lance_mem_read(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
 {
     SysBusPCNetState *d = opaque;
     uint32_t val;
@@ -74,16 +75,14 @@ static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr)
     return val & 0xffff;
 }
 
-static CPUReadMemoryFunc * const lance_mem_read[3] = {
-    NULL,
-    lance_mem_readw,
-    NULL,
-};
-
-static CPUWriteMemoryFunc * const lance_mem_write[3] = {
-    NULL,
-    lance_mem_writew,
-    NULL,
+static const MemoryRegionOps lance_mem_ops = {
+    .read = lance_mem_read,
+    .write = lance_mem_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 2,
+        .max_access_size = 2,
+    },
 };
 
 static void lance_cleanup(VLANClientState *nc)
@@ -117,13 +116,11 @@ static int lance_init(SysBusDevice *dev)
     SysBusPCNetState *d = FROM_SYSBUS(SysBusPCNetState, dev);
     PCNetState *s = &d->state;
 
-    s->mmio_index =
-        cpu_register_io_memory(lance_mem_read, lance_mem_write, d,
-                               DEVICE_NATIVE_ENDIAN);
+    memory_region_init_io(&s->mmio, &lance_mem_ops, s, "lance-mmio", 4);
 
     qdev_init_gpio_in(&dev->qdev, parent_lance_reset, 1);
 
-    sysbus_init_mmio(dev, 4, s->mmio_index);
+    sysbus_init_mmio_region(dev, &s->mmio);
 
     sysbus_init_irq(dev, &s->irq);
 
diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c
index 216cf81..a25f565 100644
--- a/hw/pcnet-pci.c
+++ b/hw/pcnet-pci.c
@@ -46,6 +46,7 @@
 typedef struct {
     PCIDevice pci_dev;
     PCNetState state;
+    MemoryRegion io_bar;
 } PCIPCNetState;
 
 static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val)
@@ -69,25 +70,41 @@ static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr)
     return val;
 }
 
-static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num,
-                             pcibus_t addr, pcibus_t size, int type)
+static uint64_t pcnet_ioport_read(void *opaque, target_phys_addr_t addr,
+                                  unsigned size)
 {
-    PCNetState *d = &DO_UPCAST(PCIPCNetState, pci_dev, pci_dev)->state;
+    PCNetState *d = opaque;
 
-#ifdef PCNET_DEBUG_IO
-    printf("pcnet_ioport_map addr=0x%04"FMT_PCIBUS" size=0x%04"FMT_PCIBUS"\n",
-           addr, size);
-#endif
+    if (addr < 16 && size == 1) {
+        return pcnet_aprom_readb(d, addr);
+    } else if (addr >= 0x10 && addr < 0x20 && size == 2) {
+        return pcnet_ioport_readw(d, addr);
+    } else if (addr >= 0x10 && addr < 0x20 && size == 4) {
+        return pcnet_ioport_readl(d, addr);
+    }
+    return ((uint64_t)1 << (size * 8)) - 1;
+}
 
-    register_ioport_write(addr, 16, 1, pcnet_aprom_writeb, d);
-    register_ioport_read(addr, 16, 1, pcnet_aprom_readb, d);
+static void pcnet_ioport_write(void *opaque, target_phys_addr_t addr,
+                               uint64_t data, unsigned size)
+{
+    PCNetState *d = opaque;
 
-    register_ioport_write(addr + 0x10, 0x10, 2, pcnet_ioport_writew, d);
-    register_ioport_read(addr + 0x10, 0x10, 2, pcnet_ioport_readw, d);
-    register_ioport_write(addr + 0x10, 0x10, 4, pcnet_ioport_writel, d);
-    register_ioport_read(addr + 0x10, 0x10, 4, pcnet_ioport_readl, d);
+    if (addr < 16 && size == 1) {
+        return pcnet_aprom_writeb(d, addr, data);
+    } else if (addr >= 0x10 && addr < 0x20 && size == 2) {
+        return pcnet_ioport_writew(d, addr, data);
+    } else if (addr >= 0x10 && addr < 0x20 && size == 4) {
+        return pcnet_ioport_writel(d, addr, data);
+    }
 }
 
+static const MemoryRegionOps pcnet_io_ops = {
+    .read = pcnet_ioport_read,
+    .write = pcnet_ioport_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
 static void pcnet_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
     PCNetState *d = opaque;
@@ -202,16 +219,12 @@ static const VMStateDescription vmstate_pci_pcnet = {
 
 /* PCI interface */
 
-static CPUWriteMemoryFunc * const pcnet_mmio_write[] = {
-    &pcnet_mmio_writeb,
-    &pcnet_mmio_writew,
-    &pcnet_mmio_writel
-};
-
-static CPUReadMemoryFunc * const pcnet_mmio_read[] = {
-    &pcnet_mmio_readb,
-    &pcnet_mmio_readw,
-    &pcnet_mmio_readl
+static const MemoryRegionOps pcnet_mmio_ops = {
+    .old_mmio = {
+        .read = { pcnet_mmio_readb, pcnet_mmio_readw, pcnet_mmio_readl },
+        .write = { pcnet_mmio_writeb, pcnet_mmio_writew, pcnet_mmio_writel },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void pci_physical_memory_write(void *dma_opaque, target_phys_addr_t addr,
@@ -237,7 +250,8 @@ static int pci_pcnet_uninit(PCIDevice *dev)
 {
     PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, dev);
 
-    cpu_unregister_io_memory(d->state.mmio_index);
+    memory_region_destroy(&d->state.mmio);
+    memory_region_destroy(&d->io_bar);
     qemu_del_timer(d->state.poll_timer);
     qemu_free_timer(d->state.poll_timer);
     qemu_del_vlan_client(&d->state.nic->nc);
@@ -276,14 +290,14 @@ static int pci_pcnet_init(PCIDevice *pci_dev)
     pci_conf[PCI_MAX_LAT] = 0xff;
 
     /* Handler for memory-mapped I/O */
-    s->mmio_index =
-      cpu_register_io_memory(pcnet_mmio_read, pcnet_mmio_write, &d->state,
-                             DEVICE_NATIVE_ENDIAN);
+    memory_region_init_io(&d->state.mmio, &pcnet_mmio_ops, d, "pcnet-mmio",
+                          PCNET_PNPMMIO_SIZE);
 
-    pci_register_bar(pci_dev, 0, PCNET_IOPORT_SIZE,
-                           PCI_BASE_ADDRESS_SPACE_IO, pcnet_ioport_map);
+    memory_region_init_io(&d->io_bar, &pcnet_io_ops, d, "pcnet-io",
+                          PCNET_IOPORT_SIZE);
+    pci_register_bar_region(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &d->io_bar);
 
-    pci_register_bar_simple(pci_dev, 1, PCNET_PNPMMIO_SIZE, 0, s->mmio_index);
+    pci_register_bar_region(pci_dev, 1, 0, &s->mmio);
 
     s->irq = pci_dev->irq[0];
     s->phys_mem_read = pci_physical_memory_read;
diff --git a/hw/pcnet.h b/hw/pcnet.h
index 534bdf9..7e1c685 100644
--- a/hw/pcnet.h
+++ b/hw/pcnet.h
@@ -4,6 +4,7 @@
 #define PCNET_LOOPTEST_CRC	1
 #define PCNET_LOOPTEST_NOCRC	2
 
+#include "memory.h"
 
 typedef struct PCNetState_st PCNetState;
 
@@ -17,7 +18,8 @@ struct PCNetState_st {
     uint16_t csr[128];
     uint16_t bcr[32];
     uint64_t timer;
-    int mmio_index, xmit_pos;
+    MemoryRegion mmio;
+    int xmit_pos;
     uint8_t buffer[4096];
     int tx_busy;
     qemu_irq irq;
commit 1ec4e1ddc900f4293cd66e17485c8075a3551fed
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:09:18 2011 +0300

    ne2000: convert to memory API
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/ne2000-isa.c b/hw/ne2000-isa.c
index e41dbba..756ed5c 100644
--- a/hw/ne2000-isa.c
+++ b/hw/ne2000-isa.c
@@ -27,6 +27,7 @@
 #include "qdev.h"
 #include "net.h"
 #include "ne2000.h"
+#include "exec-memory.h"
 
 typedef struct ISANE2000State {
     ISADevice dev;
@@ -66,19 +67,11 @@ static int isa_ne2000_initfn(ISADevice *dev)
     ISANE2000State *isa = DO_UPCAST(ISANE2000State, dev, dev);
     NE2000State *s = &isa->ne2000;
 
-    register_ioport_write(isa->iobase, 16, 1, ne2000_ioport_write, s);
-    register_ioport_read(isa->iobase, 16, 1, ne2000_ioport_read, s);
+    ne2000_setup_io(s, 0x20);
     isa_init_ioport_range(dev, isa->iobase, 16);
-
-    register_ioport_write(isa->iobase + 0x10, 1, 1, ne2000_asic_ioport_write, s);
-    register_ioport_read(isa->iobase + 0x10, 1, 1, ne2000_asic_ioport_read, s);
-    register_ioport_write(isa->iobase + 0x10, 2, 2, ne2000_asic_ioport_write, s);
-    register_ioport_read(isa->iobase + 0x10, 2, 2, ne2000_asic_ioport_read, s);
     isa_init_ioport_range(dev, isa->iobase + 0x10, 2);
-
-    register_ioport_write(isa->iobase + 0x1f, 1, 1, ne2000_reset_ioport_write, s);
-    register_ioport_read(isa->iobase + 0x1f, 1, 1, ne2000_reset_ioport_read, s);
     isa_init_ioport(dev, isa->iobase + 0x1f);
+    memory_region_add_subregion(get_system_io(), isa->iobase, &s->io);
 
     isa_init_irq(dev, &s->irq, isa->isairq);
 
diff --git a/hw/ne2000.c b/hw/ne2000.c
index f8acaae..5b76acf 100644
--- a/hw/ne2000.c
+++ b/hw/ne2000.c
@@ -297,7 +297,7 @@ ssize_t ne2000_receive(VLANClientState *nc, const uint8_t *buf, size_t size_)
     return size_;
 }
 
-void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 {
     NE2000State *s = opaque;
     int offset, page, index;
@@ -394,7 +394,7 @@ void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val)
     }
 }
 
-uint32_t ne2000_ioport_read(void *opaque, uint32_t addr)
+static uint32_t ne2000_ioport_read(void *opaque, uint32_t addr)
 {
     NE2000State *s = opaque;
     int offset, page, ret;
@@ -544,7 +544,7 @@ static inline void ne2000_dma_update(NE2000State *s, int len)
     }
 }
 
-void ne2000_asic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+static void ne2000_asic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 {
     NE2000State *s = opaque;
 
@@ -564,7 +564,7 @@ void ne2000_asic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
     }
 }
 
-uint32_t ne2000_asic_ioport_read(void *opaque, uint32_t addr)
+static uint32_t ne2000_asic_ioport_read(void *opaque, uint32_t addr)
 {
     NE2000State *s = opaque;
     int ret;
@@ -612,12 +612,12 @@ static uint32_t ne2000_asic_ioport_readl(void *opaque, uint32_t addr)
     return ret;
 }
 
-void ne2000_reset_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+static void ne2000_reset_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 {
     /* nothing to do (end of reset pulse) */
 }
 
-uint32_t ne2000_reset_ioport_read(void *opaque, uint32_t addr)
+static uint32_t ne2000_reset_ioport_read(void *opaque, uint32_t addr)
 {
     NE2000State *s = opaque;
     ne2000_reset(s);
@@ -676,27 +676,55 @@ static const VMStateDescription vmstate_pci_ne2000 = {
     }
 };
 
-/***********************************************************/
-/* PCI NE2000 definitions */
+static uint64_t ne2000_read(void *opaque, target_phys_addr_t addr,
+                            unsigned size)
+{
+    NE2000State *s = opaque;
 
-static void ne2000_map(PCIDevice *pci_dev, int region_num,
-                       pcibus_t addr, pcibus_t size, int type)
+    if (addr < 0x10 && size == 1) {
+        return ne2000_ioport_read(s, addr);
+    } else if (addr == 0x10) {
+        if (size <= 2) {
+            return ne2000_asic_ioport_read(s, addr);
+        } else {
+            return ne2000_asic_ioport_readl(s, addr);
+        }
+    } else if (addr == 0x1f && size == 1) {
+        return ne2000_reset_ioport_read(s, addr);
+    }
+    return ((uint64_t)1 << (size * 8)) - 1;
+}
+
+static void ne2000_write(void *opaque, target_phys_addr_t addr,
+                         uint64_t data, unsigned size)
 {
-    PCINE2000State *d = DO_UPCAST(PCINE2000State, dev, pci_dev);
-    NE2000State *s = &d->ne2000;
+    NE2000State *s = opaque;
+
+    if (addr < 0x10 && size == 1) {
+        return ne2000_ioport_write(s, addr, data);
+    } else if (addr == 0x10) {
+        if (size <= 2) {
+            return ne2000_asic_ioport_write(s, addr, data);
+        } else {
+            return ne2000_asic_ioport_writel(s, addr, data);
+        }
+    } else if (addr == 0x1f && size == 1) {
+        return ne2000_reset_ioport_write(s, addr, data);
+    }
+}
 
-    register_ioport_write(addr, 16, 1, ne2000_ioport_write, s);
-    register_ioport_read(addr, 16, 1, ne2000_ioport_read, s);
+static const MemoryRegionOps ne2000_ops = {
+    .read = ne2000_read,
+    .write = ne2000_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
 
-    register_ioport_write(addr + 0x10, 1, 1, ne2000_asic_ioport_write, s);
-    register_ioport_read(addr + 0x10, 1, 1, ne2000_asic_ioport_read, s);
-    register_ioport_write(addr + 0x10, 2, 2, ne2000_asic_ioport_write, s);
-    register_ioport_read(addr + 0x10, 2, 2, ne2000_asic_ioport_read, s);
-    register_ioport_write(addr + 0x10, 4, 4, ne2000_asic_ioport_writel, s);
-    register_ioport_read(addr + 0x10, 4, 4, ne2000_asic_ioport_readl, s);
+/***********************************************************/
+/* PCI NE2000 definitions */
 
-    register_ioport_write(addr + 0x1f, 1, 1, ne2000_reset_ioport_write, s);
-    register_ioport_read(addr + 0x1f, 1, 1, ne2000_reset_ioport_read, s);
+void ne2000_setup_io(NE2000State *s, unsigned size)
+{
+    memory_region_init_io(&s->io, &ne2000_ops, s, "ne2000", size);
 }
 
 static void ne2000_cleanup(VLANClientState *nc)
@@ -724,9 +752,9 @@ static int pci_ne2000_init(PCIDevice *pci_dev)
     /* TODO: RST# value should be 0. PCI spec 6.2.4 */
     pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0
 
-    pci_register_bar(&d->dev, 0, 0x100,
-                           PCI_BASE_ADDRESS_SPACE_IO, ne2000_map);
     s = &d->ne2000;
+    ne2000_setup_io(s, 0x100);
+    pci_register_bar_region(&d->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io);
     s->irq = d->dev.irq[0];
 
     qemu_macaddr_default_if_unset(&s->c.macaddr);
@@ -754,6 +782,7 @@ static int pci_ne2000_exit(PCIDevice *pci_dev)
     PCINE2000State *d = DO_UPCAST(PCINE2000State, dev, pci_dev);
     NE2000State *s = &d->ne2000;
 
+    memory_region_destroy(&s->io);
     qemu_del_vlan_client(&s->nic->nc);
     return 0;
 }
diff --git a/hw/ne2000.h b/hw/ne2000.h
index 54fdfca..5fee052 100644
--- a/hw/ne2000.h
+++ b/hw/ne2000.h
@@ -4,6 +4,7 @@
 #define NE2000_MEM_SIZE     NE2000_PMEM_END
 
 typedef struct NE2000State {
+    MemoryRegion io;
     uint8_t cmd;
     uint32_t start;
     uint32_t stop;
@@ -27,12 +28,7 @@ typedef struct NE2000State {
     uint8_t mem[NE2000_MEM_SIZE];
 } NE2000State;
 
-void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val);
-uint32_t ne2000_ioport_read(void *opaque, uint32_t addr);
-void ne2000_asic_ioport_write(void *opaque, uint32_t addr, uint32_t val);
-uint32_t ne2000_asic_ioport_read(void *opaque, uint32_t addr);
-void ne2000_reset_ioport_write(void *opaque, uint32_t addr, uint32_t val);
-uint32_t ne2000_reset_ioport_read(void *opaque, uint32_t addr);
+void ne2000_setup_io(NE2000State *s, unsigned size);
 extern const VMStateDescription vmstate_ne2000;
 void ne2000_reset(NE2000State *s);
 int ne2000_can_receive(VLANClientState *vc);
commit 23c5e4cab2d64e00b6000f4a360c87f65e003545
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:09:17 2011 +0300

    ppc: convert to memory API
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/cuda.c b/hw/cuda.c
index 065c362..5c92d81 100644
--- a/hw/cuda.c
+++ b/hw/cuda.c
@@ -117,6 +117,7 @@ typedef struct CUDATimer {
 } CUDATimer;
 
 typedef struct CUDAState {
+    MemoryRegion mem;
     /* cuda registers */
     uint8_t b;      /* B-side data */
     uint8_t a;      /* A-side data */
@@ -722,7 +723,7 @@ static void cuda_reset(void *opaque)
     set_counter(s, &s->timers[1], 0xffff);
 }
 
-void cuda_init (int *cuda_mem_index, qemu_irq irq)
+void cuda_init (MemoryRegion **cuda_mem, qemu_irq irq)
 {
     struct tm tm;
     CUDAState *s = &cuda_state;
@@ -738,8 +739,9 @@ void cuda_init (int *cuda_mem_index, qemu_irq irq)
     s->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET;
 
     s->adb_poll_timer = qemu_new_timer_ns(vm_clock, cuda_adb_poll, s);
-    *cuda_mem_index = cpu_register_io_memory(cuda_read, cuda_write, s,
+    cpu_register_io_memory(cuda_read, cuda_write, s,
                                              DEVICE_NATIVE_ENDIAN);
+    *cuda_mem = &s->mem;
     vmstate_register(NULL, -1, &vmstate_cuda, s);
     qemu_register_reset(cuda_reset, s);
 }
diff --git a/hw/escc.c b/hw/escc.c
index f6fd919..bea5873 100644
--- a/hw/escc.c
+++ b/hw/escc.c
@@ -126,7 +126,7 @@ struct SerialState {
     SysBusDevice busdev;
     struct ChannelState chn[2];
     uint32_t it_shift;
-    int mmio_index;
+    MemoryRegion mmio;
     uint32_t disabled;
     uint32_t frequency;
 };
@@ -490,7 +490,8 @@ static void escc_update_parameters(ChannelState *s)
     qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
 }
 
-static void escc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+static void escc_mem_write(void *opaque, target_phys_addr_t addr,
+                           uint64_t val, unsigned size)
 {
     SerialState *serial = opaque;
     ChannelState *s;
@@ -592,7 +593,8 @@ static void escc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
     }
 }
 
-static uint32_t escc_mem_readb(void *opaque, target_phys_addr_t addr)
+static uint64_t escc_mem_read(void *opaque, target_phys_addr_t addr,
+                              unsigned size)
 {
     SerialState *serial = opaque;
     ChannelState *s;
@@ -627,6 +629,16 @@ static uint32_t escc_mem_readb(void *opaque, target_phys_addr_t addr)
     return 0;
 }
 
+static const MemoryRegionOps escc_mem_ops = {
+    .read = escc_mem_read,
+    .write = escc_mem_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
 static int serial_can_receive(void *opaque)
 {
     ChannelState *s = opaque;
@@ -668,18 +680,6 @@ static void serial_event(void *opaque, int event)
         serial_receive_break(s);
 }
 
-static CPUReadMemoryFunc * const escc_mem_read[3] = {
-    escc_mem_readb,
-    NULL,
-    NULL,
-};
-
-static CPUWriteMemoryFunc * const escc_mem_write[3] = {
-    escc_mem_writeb,
-    NULL,
-    NULL,
-};
-
 static const VMStateDescription vmstate_escc_chn = {
     .name ="escc_chn",
     .version_id = 2,
@@ -712,7 +712,7 @@ static const VMStateDescription vmstate_escc = {
     }
 };
 
-int escc_init(target_phys_addr_t base, qemu_irq irqA, qemu_irq irqB,
+MemoryRegion *escc_init(target_phys_addr_t base, qemu_irq irqA, qemu_irq irqB,
               CharDriverState *chrA, CharDriverState *chrB,
               int clock, int it_shift)
 {
@@ -737,7 +737,7 @@ int escc_init(target_phys_addr_t base, qemu_irq irqA, qemu_irq irqB,
     }
 
     d = FROM_SYSBUS(SerialState, s);
-    return d->mmio_index;
+    return &d->mmio;
 }
 
 static const uint8_t keycodes[128] = {
@@ -901,7 +901,6 @@ void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq,
 static int escc_init1(SysBusDevice *dev)
 {
     SerialState *s = FROM_SYSBUS(SerialState, dev);
-    int io;
     unsigned int i;
 
     s->chn[0].disabled = s->disabled;
@@ -918,10 +917,9 @@ static int escc_init1(SysBusDevice *dev)
     s->chn[0].otherchn = &s->chn[1];
     s->chn[1].otherchn = &s->chn[0];
 
-    io = cpu_register_io_memory(escc_mem_read, escc_mem_write, s,
-                                DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, ESCC_SIZE << s->it_shift, io);
-    s->mmio_index = io;
+    memory_region_init_io(&s->mmio, &escc_mem_ops, s, "escc",
+                          ESCC_SIZE << s->it_shift);
+    sysbus_init_mmio_region(dev, &s->mmio);
 
     if (s->chn[0].type == mouse) {
         qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0,
diff --git a/hw/escc.h b/hw/escc.h
index 015b9d0..d1da46f 100644
--- a/hw/escc.h
+++ b/hw/escc.h
@@ -1,6 +1,6 @@
 /* escc.c */
 #define ESCC_SIZE 4
-int escc_init(target_phys_addr_t base, qemu_irq irqA, qemu_irq irqB,
+MemoryRegion *escc_init(target_phys_addr_t base, qemu_irq irqA, qemu_irq irqB,
               CharDriverState *chrA, CharDriverState *chrB,
               int clock, int it_shift);
 
diff --git a/hw/heathrow_pic.c b/hw/heathrow_pic.c
index 5fd71a0..3ba0b0e 100644
--- a/hw/heathrow_pic.c
+++ b/hw/heathrow_pic.c
@@ -43,6 +43,7 @@ typedef struct HeathrowPIC {
 } HeathrowPIC;
 
 typedef struct HeathrowPICS {
+    MemoryRegion mem;
     HeathrowPIC pics[2];
     qemu_irq *irqs;
 } HeathrowPICS;
@@ -62,7 +63,8 @@ static void heathrow_pic_update(HeathrowPICS *s)
     }
 }
 
-static void pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+static void pic_write(void *opaque, target_phys_addr_t addr,
+                      uint64_t value, unsigned size)
 {
     HeathrowPICS *s = opaque;
     HeathrowPIC *pic;
@@ -89,7 +91,8 @@ static void pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
     }
 }
 
-static uint32_t pic_readl (void *opaque, target_phys_addr_t addr)
+static uint64_t pic_read(void *opaque, target_phys_addr_t addr,
+                         unsigned size)
 {
     HeathrowPICS *s = opaque;
     HeathrowPIC *pic;
@@ -120,19 +123,12 @@ static uint32_t pic_readl (void *opaque, target_phys_addr_t addr)
     return value;
 }
 
-static CPUWriteMemoryFunc * const pic_write[] = {
-    &pic_writel,
-    &pic_writel,
-    &pic_writel,
+static const MemoryRegionOps heathrow_pic_ops = {
+    .read = pic_read,
+    .write = pic_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUReadMemoryFunc * const pic_read[] = {
-    &pic_readl,
-    &pic_readl,
-    &pic_readl,
-};
-
-
 static void heathrow_pic_set_irq(void *opaque, int num, int level)
 {
     HeathrowPICS *s = opaque;
@@ -201,7 +197,7 @@ static void heathrow_pic_reset(void *opaque)
     s->pics[1].level_triggered = 0x1ff00000;
 }
 
-qemu_irq *heathrow_pic_init(int *pmem_index,
+qemu_irq *heathrow_pic_init(MemoryRegion **pmem,
                             int nb_cpus, qemu_irq **irqs)
 {
     HeathrowPICS *s;
@@ -209,8 +205,9 @@ qemu_irq *heathrow_pic_init(int *pmem_index,
     s = qemu_mallocz(sizeof(HeathrowPICS));
     /* only 1 CPU */
     s->irqs = irqs[0];
-    *pmem_index = cpu_register_io_memory(pic_read, pic_write, s,
-                                         DEVICE_LITTLE_ENDIAN);
+    memory_region_init_io(&s->mem, &heathrow_pic_ops, s,
+                          "heathrow-pic", 0x1000);
+    *pmem = &s->mem;
 
     vmstate_register(NULL, -1, &vmstate_heathrow_pic, s);
     qemu_register_reset(heathrow_pic_reset, s);
diff --git a/hw/ide.h b/hw/ide.h
index a490cbb..9059aae 100644
--- a/hw/ide.h
+++ b/hw/ide.h
@@ -19,7 +19,7 @@ PCIDevice *pci_piix4_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
 void vt82c686b_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
 
 /* ide-macio.c */
-int pmac_ide_init (DriveInfo **hd_table, qemu_irq irq,
+MemoryRegion *pmac_ide_init (DriveInfo **hd_table, qemu_irq irq,
 		   void *dbdma, int channel, qemu_irq dma_irq);
 
 /* ide-mmio.c */
diff --git a/hw/ide/macio.c b/hw/ide/macio.c
index 7daeb31..7ee35e9 100644
--- a/hw/ide/macio.c
+++ b/hw/ide/macio.c
@@ -35,6 +35,7 @@
 /* MacIO based PowerPC IDE */
 
 typedef struct MACIOIDEState {
+    MemoryRegion mem;
     IDEBus bus;
     BlockDriverAIOCB *aiocb;
 } MACIOIDEState;
@@ -281,16 +282,20 @@ static uint32_t pmac_ide_readl (void *opaque,target_phys_addr_t addr)
     return retval;
 }
 
-static CPUWriteMemoryFunc * const pmac_ide_write[] = {
-    pmac_ide_writeb,
-    pmac_ide_writew,
-    pmac_ide_writel,
-};
-
-static CPUReadMemoryFunc * const pmac_ide_read[] = {
-    pmac_ide_readb,
-    pmac_ide_readw,
-    pmac_ide_readl,
+static MemoryRegionOps pmac_ide_ops = {
+    .old_mmio = {
+        .write = {
+            pmac_ide_writeb,
+            pmac_ide_writew,
+            pmac_ide_writel,
+        },
+        .read = {
+            pmac_ide_readb,
+            pmac_ide_readw,
+            pmac_ide_readl,
+        },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static const VMStateDescription vmstate_pmac = {
@@ -315,11 +320,10 @@ static void pmac_ide_reset(void *opaque)
 /* hd_table must contain 4 block drivers */
 /* PowerMac uses memory mapped registers, not I/O. Return the memory
    I/O index to access the ide. */
-int pmac_ide_init (DriveInfo **hd_table, qemu_irq irq,
-		   void *dbdma, int channel, qemu_irq dma_irq)
+MemoryRegion *pmac_ide_init (DriveInfo **hd_table, qemu_irq irq,
+                             void *dbdma, int channel, qemu_irq dma_irq)
 {
     MACIOIDEState *d;
-    int pmac_ide_memory;
 
     d = qemu_mallocz(sizeof(MACIOIDEState));
     ide_init2_with_non_qdev_drives(&d->bus, hd_table[0], hd_table[1], irq);
@@ -327,11 +331,9 @@ int pmac_ide_init (DriveInfo **hd_table, qemu_irq irq,
     if (dbdma)
         DBDMA_register_channel(dbdma, channel, dma_irq, pmac_ide_transfer, pmac_ide_flush, d);
 
-    pmac_ide_memory = cpu_register_io_memory(pmac_ide_read,
-                                             pmac_ide_write, d,
-                                             DEVICE_NATIVE_ENDIAN);
+    memory_region_init_io(&d->mem, &pmac_ide_ops, d, "pmac-ide", 0x1000);
     vmstate_register(NULL, 0, &vmstate_pmac, d);
     qemu_register_reset(pmac_ide_reset, d);
 
-    return pmac_ide_memory;
+    return &d->mem;
 }
diff --git a/hw/mac_dbdma.c b/hw/mac_dbdma.c
index ed4458e..350d901 100644
--- a/hw/mac_dbdma.c
+++ b/hw/mac_dbdma.c
@@ -166,6 +166,7 @@ typedef struct DBDMA_channel {
 } DBDMA_channel;
 
 typedef struct {
+    MemoryRegion mem;
     DBDMA_channel channels[DBDMA_CHANNELS];
 } DBDMAState;
 
@@ -703,8 +704,8 @@ dbdma_control_write(DBDMA_channel *ch)
         ch->flush(&ch->io);
 }
 
-static void dbdma_writel (void *opaque,
-                          target_phys_addr_t addr, uint32_t value)
+static void dbdma_write(void *opaque, target_phys_addr_t addr,
+                        uint64_t value, unsigned size)
 {
     int channel = addr >> DBDMA_CHANNEL_SHIFT;
     DBDMAState *s = opaque;
@@ -753,7 +754,8 @@ static void dbdma_writel (void *opaque,
     }
 }
 
-static uint32_t dbdma_readl (void *opaque, target_phys_addr_t addr)
+static uint64_t dbdma_read(void *opaque, target_phys_addr_t addr,
+                           unsigned size)
 {
     uint32_t value;
     int channel = addr >> DBDMA_CHANNEL_SHIFT;
@@ -798,16 +800,14 @@ static uint32_t dbdma_readl (void *opaque, target_phys_addr_t addr)
     return value;
 }
 
-static CPUWriteMemoryFunc * const dbdma_write[] = {
-    NULL,
-    NULL,
-    dbdma_writel,
-};
-
-static CPUReadMemoryFunc * const dbdma_read[] = {
-    NULL,
-    NULL,
-    dbdma_readl,
+static const MemoryRegionOps dbdma_ops = {
+    .read = dbdma_read,
+    .write = dbdma_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
 };
 
 static const VMStateDescription vmstate_dbdma_channel = {
@@ -842,14 +842,14 @@ static void dbdma_reset(void *opaque)
         memset(s->channels[i].regs, 0, DBDMA_SIZE);
 }
 
-void* DBDMA_init (int *dbdma_mem_index)
+void* DBDMA_init (MemoryRegion **dbdma_mem)
 {
     DBDMAState *s;
 
     s = qemu_mallocz(sizeof(DBDMAState));
 
-    *dbdma_mem_index = cpu_register_io_memory(dbdma_read, dbdma_write, s,
-                                              DEVICE_LITTLE_ENDIAN);
+    memory_region_init_io(&s->mem, &dbdma_ops, s, "dbdma", 0x1000);
+    *dbdma_mem = &s->mem;
     vmstate_register(NULL, -1, &vmstate_dbdma, s);
     qemu_register_reset(dbdma_reset, s);
 
diff --git a/hw/mac_dbdma.h b/hw/mac_dbdma.h
index d236c5b..933e17c 100644
--- a/hw/mac_dbdma.h
+++ b/hw/mac_dbdma.h
@@ -20,6 +20,8 @@
  * THE SOFTWARE.
  */
 
+#include "memory.h"
+
 typedef struct DBDMA_io DBDMA_io;
 
 typedef void (*DBDMA_flush)(DBDMA_io *io);
@@ -40,4 +42,4 @@ void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
                             DBDMA_rw rw, DBDMA_flush flush,
                             void *opaque);
 void DBDMA_schedule(void);
-void* DBDMA_init (int *dbdma_mem_index);
+void* DBDMA_init (MemoryRegion **dbdma_mem);
diff --git a/hw/mac_nvram.c b/hw/mac_nvram.c
index 61e53d2..ced1e58 100644
--- a/hw/mac_nvram.c
+++ b/hw/mac_nvram.c
@@ -39,7 +39,7 @@
 
 struct MacIONVRAMState {
     uint32_t size;
-    int mem_index;
+    MemoryRegion mem;
     unsigned int it_shift;
     uint8_t *data;
 };
@@ -71,8 +71,8 @@ void macio_nvram_write (void *opaque, uint32_t addr, uint32_t val)
 }
 
 /* macio style NVRAM device */
-static void macio_nvram_writeb (void *opaque,
-                                target_phys_addr_t addr, uint32_t value)
+static void macio_nvram_writeb(void *opaque, target_phys_addr_t addr,
+                               uint64_t value, unsigned size)
 {
     MacIONVRAMState *s = opaque;
 
@@ -81,7 +81,8 @@ static void macio_nvram_writeb (void *opaque,
     NVR_DPRINTF("writeb addr %04x val %x\n", (int)addr, value);
 }
 
-static uint32_t macio_nvram_readb (void *opaque, target_phys_addr_t addr)
+static uint64_t macio_nvram_readb(void *opaque, target_phys_addr_t addr,
+                                  unsigned size)
 {
     MacIONVRAMState *s = opaque;
     uint32_t value;
@@ -93,16 +94,10 @@ static uint32_t macio_nvram_readb (void *opaque, target_phys_addr_t addr)
     return value;
 }
 
-static CPUWriteMemoryFunc * const nvram_write[] = {
-    &macio_nvram_writeb,
-    &macio_nvram_writeb,
-    &macio_nvram_writeb,
-};
-
-static CPUReadMemoryFunc * const nvram_read[] = {
-    &macio_nvram_readb,
-    &macio_nvram_readb,
-    &macio_nvram_readb,
+static const MemoryRegionOps macio_nvram_ops = {
+    .read = macio_nvram_readb,
+    .write = macio_nvram_writeb,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static const VMStateDescription vmstate_macio_nvram = {
@@ -121,7 +116,7 @@ static void macio_nvram_reset(void *opaque)
 {
 }
 
-MacIONVRAMState *macio_nvram_init (int *mem_index, target_phys_addr_t size,
+MacIONVRAMState *macio_nvram_init (target_phys_addr_t size,
                                    unsigned int it_shift)
 {
     MacIONVRAMState *s;
@@ -131,22 +126,18 @@ MacIONVRAMState *macio_nvram_init (int *mem_index, target_phys_addr_t size,
     s->size = size;
     s->it_shift = it_shift;
 
-    s->mem_index = cpu_register_io_memory(nvram_read, nvram_write, s,
-                                          DEVICE_NATIVE_ENDIAN);
-    *mem_index = s->mem_index;
+    memory_region_init_io(&s->mem, &macio_nvram_ops, s, "macio-nvram",
+                          size << it_shift);
     vmstate_register(NULL, -1, &vmstate_macio_nvram, s);
     qemu_register_reset(macio_nvram_reset, s);
 
     return s;
 }
 
-void macio_nvram_map (void *opaque, target_phys_addr_t mem_base)
+void macio_nvram_setup_bar(MacIONVRAMState *s, MemoryRegion *bar,
+                           target_phys_addr_t mem_base)
 {
-    MacIONVRAMState *s;
-
-    s = opaque;
-    cpu_register_physical_memory(mem_base, s->size << s->it_shift,
-                                 s->mem_index);
+    memory_region_add_subregion(bar, mem_base, &s->mem);
 }
 
 /* Set up a system OpenBIOS NVRAM partition */
diff --git a/hw/macio.c b/hw/macio.c
index 789ca55..71fa2a8 100644
--- a/hw/macio.c
+++ b/hw/macio.c
@@ -30,58 +30,55 @@
 typedef struct macio_state_t macio_state_t;
 struct macio_state_t {
     int is_oldworld;
-    int pic_mem_index;
-    int dbdma_mem_index;
-    int cuda_mem_index;
-    int escc_mem_index;
+    MemoryRegion bar;
+    MemoryRegion *pic_mem;
+    MemoryRegion *dbdma_mem;
+    MemoryRegion *cuda_mem;
+    MemoryRegion *escc_mem;
     void *nvram;
     int nb_ide;
-    int ide_mem_index[4];
+    MemoryRegion *ide_mem[4];
 };
 
-static void macio_map (PCIDevice *pci_dev, int region_num,
-                       pcibus_t addr, pcibus_t size, int type)
+static void macio_bar_setup(macio_state_t *macio_state)
 {
-    macio_state_t *macio_state;
     int i;
+    MemoryRegion *bar = &macio_state->bar;
 
-    macio_state = (macio_state_t *)(pci_dev + 1);
-    if (macio_state->pic_mem_index >= 0) {
+    memory_region_init(bar, "macio", 0x80000);
+    if (macio_state->pic_mem) {
         if (macio_state->is_oldworld) {
             /* Heathrow PIC */
-            cpu_register_physical_memory(addr + 0x00000, 0x1000,
-                                         macio_state->pic_mem_index);
+            memory_region_add_subregion(bar, 0x00000, macio_state->pic_mem);
         } else {
             /* OpenPIC */
-            cpu_register_physical_memory(addr + 0x40000, 0x40000,
-                                         macio_state->pic_mem_index);
+            memory_region_add_subregion(bar, 0x40000, macio_state->pic_mem);
         }
     }
-    if (macio_state->dbdma_mem_index >= 0) {
-        cpu_register_physical_memory(addr + 0x08000, 0x1000,
-                                     macio_state->dbdma_mem_index);
+    if (macio_state->dbdma_mem) {
+        memory_region_add_subregion(bar, 0x08000, macio_state->dbdma_mem);
     }
-    if (macio_state->escc_mem_index >= 0) {
-        cpu_register_physical_memory(addr + 0x13000, ESCC_SIZE << 4,
-                                     macio_state->escc_mem_index);
+    if (macio_state->escc_mem) {
+        memory_region_add_subregion(bar, 0x13000, macio_state->escc_mem);
     }
-    if (macio_state->cuda_mem_index >= 0) {
-        cpu_register_physical_memory(addr + 0x16000, 0x2000,
-                                     macio_state->cuda_mem_index);
+    if (macio_state->cuda_mem) {
+        memory_region_add_subregion(bar, 0x16000, macio_state->cuda_mem);
     }
     for (i = 0; i < macio_state->nb_ide; i++) {
-        if (macio_state->ide_mem_index[i] >= 0) {
-            cpu_register_physical_memory(addr + 0x1f000 + (i * 0x1000), 0x1000,
-                                         macio_state->ide_mem_index[i]);
+        if (macio_state->ide_mem[i]) {
+            memory_region_add_subregion(bar, 0x1f000 + (i * 0x1000),
+                                        macio_state->ide_mem[i]);
         }
     }
     if (macio_state->nvram != NULL)
-        macio_nvram_map(macio_state->nvram, addr + 0x60000);
+        macio_nvram_setup_bar(macio_state->nvram, bar, 0x60000);
 }
 
-void macio_init (PCIBus *bus, int device_id, int is_oldworld, int pic_mem_index,
-                 int dbdma_mem_index, int cuda_mem_index, void *nvram,
-                 int nb_ide, int *ide_mem_index, int escc_mem_index)
+void macio_init (PCIBus *bus, int device_id, int is_oldworld,
+                 MemoryRegion *pic_mem, MemoryRegion *dbdma_mem,
+                 MemoryRegion *cuda_mem, void *nvram,
+                 int nb_ide, MemoryRegion **ide_mem,
+                 MemoryRegion *escc_mem)
 {
     PCIDevice *d;
     macio_state_t *macio_state;
@@ -92,18 +89,18 @@ void macio_init (PCIBus *bus, int device_id, int is_oldworld, int pic_mem_index,
                             -1, NULL, NULL);
     macio_state = (macio_state_t *)(d + 1);
     macio_state->is_oldworld = is_oldworld;
-    macio_state->pic_mem_index = pic_mem_index;
-    macio_state->dbdma_mem_index = dbdma_mem_index;
-    macio_state->cuda_mem_index = cuda_mem_index;
-    macio_state->escc_mem_index = escc_mem_index;
+    macio_state->pic_mem = pic_mem;
+    macio_state->dbdma_mem = dbdma_mem;
+    macio_state->cuda_mem = cuda_mem;
+    macio_state->escc_mem = escc_mem;
     macio_state->nvram = nvram;
     if (nb_ide > 4)
         nb_ide = 4;
     macio_state->nb_ide = nb_ide;
     for (i = 0; i < nb_ide; i++)
-        macio_state->ide_mem_index[i] = ide_mem_index[i];
+        macio_state->ide_mem[i] = ide_mem[i];
     for (; i < 4; i++)
-        macio_state->ide_mem_index[i] = -1;
+        macio_state->ide_mem[i] = NULL;
     /* Note: this code is strongly inspirated from the corresponding code
        in PearPC */
 
@@ -113,6 +110,7 @@ void macio_init (PCIBus *bus, int device_id, int is_oldworld, int pic_mem_index,
 
     d->config[0x3d] = 0x01; // interrupt on pin 1
 
-    pci_register_bar(d, 0, 0x80000,
-                           PCI_BASE_ADDRESS_SPACE_MEMORY, macio_map);
+    macio_bar_setup(macio_state);
+    pci_register_bar_region(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
+                            &macio_state->bar);
 }
diff --git a/hw/openpic.c b/hw/openpic.c
index 6d2cf99..c2b04a3 100644
--- a/hw/openpic.c
+++ b/hw/openpic.c
@@ -205,7 +205,7 @@ typedef struct IRQ_dst_t {
 
 typedef struct openpic_t {
     PCIDevice pci_dev;
-    int mem_index;
+    MemoryRegion mem;
     /* Global registers */
     uint32_t frep; /* Feature reporting register */
     uint32_t glbc; /* Global configuration register  */
@@ -984,47 +984,34 @@ static uint32_t openpic_readl (void *opaque,target_phys_addr_t addr)
     return retval;
 }
 
-static CPUWriteMemoryFunc * const openpic_write[] = {
-    &openpic_buggy_write,
-    &openpic_buggy_write,
-    &openpic_writel,
-};
+static uint64_t openpic_read(void *opaque, target_phys_addr_t addr,
+                             unsigned size)
+{
+    openpic_t *opp = opaque;
 
-static CPUReadMemoryFunc * const openpic_read[] = {
-    &openpic_buggy_read,
-    &openpic_buggy_read,
-    &openpic_readl,
-};
+    switch (size) {
+    case 4: return openpic_readl(opp, addr);
+    default: return openpic_buggy_read(opp, addr);
+    }
+}
 
-static void openpic_map(PCIDevice *pci_dev, int region_num,
-                        pcibus_t addr, pcibus_t size, int type)
+static void openpic_write(void *opaque, target_phys_addr_t addr,
+                          uint64_t data, unsigned size)
 {
-    openpic_t *opp;
+    openpic_t *opp = opaque;
 
-    DPRINTF("Map OpenPIC\n");
-    opp = (openpic_t *)pci_dev;
-    /* Global registers */
-    DPRINTF("Register OPENPIC gbl   %08x => %08x\n",
-            addr + 0x1000, addr + 0x1000 + 0x100);
-    /* Timer registers */
-    DPRINTF("Register OPENPIC timer %08x => %08x\n",
-            addr + 0x1100, addr + 0x1100 + 0x40 * MAX_TMR);
-    /* Interrupt source registers */
-    DPRINTF("Register OPENPIC src   %08x => %08x\n",
-            addr + 0x10000, addr + 0x10000 + 0x20 * (OPENPIC_EXT_IRQ + 2));
-    /* Per CPU registers */
-    DPRINTF("Register OPENPIC dst   %08x => %08x\n",
-            addr + 0x20000, addr + 0x20000 + 0x1000 * MAX_CPU);
-    cpu_register_physical_memory(addr, 0x40000, opp->mem_index);
-#if 0 // Don't implement ISU for now
-    opp_io_memory = cpu_register_io_memory(openpic_src_read,
-                                           openpic_src_write, NULL
-                                           DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(isu_base, 0x20 * (EXT_IRQ + 2),
-                                 opp_io_memory);
-#endif
+    switch (size) {
+    case 4: return openpic_writel(opp, addr, data);
+    default: return openpic_buggy_write(opp, addr, data);
+    }
 }
 
+static const MemoryRegionOps openpic_ops = {
+    .read = openpic_read,
+    .write = openpic_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
 static void openpic_save_IRQ_queue(QEMUFile* f, IRQ_queue_t *q)
 {
     unsigned int i;
@@ -1161,7 +1148,7 @@ static void openpic_irq_raise(openpic_t *opp, int n_CPU, IRQ_src_t *src)
     qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
 }
 
-qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
+qemu_irq *openpic_init (PCIBus *bus, MemoryRegion **pmem, int nb_cpus,
                         qemu_irq **irqs, qemu_irq irq_out)
 {
     openpic_t *opp;
@@ -1180,14 +1167,22 @@ qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
         pci_config_set_class(pci_conf, PCI_CLASS_SYSTEM_OTHER); // FIXME?
         pci_conf[0x3d] = 0x00; // no interrupt pin
 
+        memory_region_init_io(&opp->mem, &openpic_ops, opp, "openpic", 0x40000);
+#if 0 // Don't implement ISU for now
+        opp_io_memory = cpu_register_io_memory(openpic_src_read,
+                                               openpic_src_write, NULL
+                                               DEVICE_NATIVE_ENDIAN);
+        cpu_register_physical_memory(isu_base, 0x20 * (EXT_IRQ + 2),
+                                     opp_io_memory);
+#endif
+
         /* Register I/O spaces */
-        pci_register_bar(&opp->pci_dev, 0, 0x40000,
-                               PCI_BASE_ADDRESS_SPACE_MEMORY, &openpic_map);
+        pci_register_bar_region(&opp->pci_dev, 0,
+                                PCI_BASE_ADDRESS_SPACE_MEMORY, &opp->mem);
     } else {
         opp = qemu_mallocz(sizeof(openpic_t));
+        memory_region_init_io(&opp->mem, &openpic_ops, opp, "openpic", 0x40000);
     }
-    opp->mem_index = cpu_register_io_memory(openpic_read, openpic_write, opp,
-                                            DEVICE_LITTLE_ENDIAN);
 
     //    isu_base &= 0xFFFC0000;
     opp->nb_cpus = nb_cpus;
@@ -1223,8 +1218,8 @@ qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
     opp->irq_raise = openpic_irq_raise;
     opp->reset = openpic_reset;
 
-    if (pmem_index)
-        *pmem_index = opp->mem_index;
+    if (pmem)
+        *pmem = &opp->mem;
 
     return qemu_allocate_irqs(openpic_set_irq, opp, opp->max_irq);
 }
diff --git a/hw/openpic.h b/hw/openpic.h
index 0957c1f..75de361 100644
--- a/hw/openpic.h
+++ b/hw/openpic.h
@@ -11,7 +11,7 @@ enum {
     OPENPIC_OUTPUT_NB,
 };
 
-qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
+qemu_irq *openpic_init (PCIBus *bus, MemoryRegion **pmem, int nb_cpus,
                         qemu_irq **irqs, qemu_irq irq_out);
 qemu_irq *mpic_init (target_phys_addr_t base, int nb_cpus,
                         qemu_irq **irqs, qemu_irq irq_out);
diff --git a/hw/ppc_mac.h b/hw/ppc_mac.h
index 25a2274..7351bb6 100644
--- a/hw/ppc_mac.h
+++ b/hw/ppc_mac.h
@@ -42,15 +42,16 @@
 #define ESCC_CLOCK 3686400
 
 /* Cuda */
-void cuda_init (int *cuda_mem_index, qemu_irq irq);
+void cuda_init (MemoryRegion **cuda_mem, qemu_irq irq);
 
 /* MacIO */
-void macio_init (PCIBus *bus, int device_id, int is_oldworld, int pic_mem_index,
-                 int dbdma_mem_index, int cuda_mem_index, void *nvram,
-                 int nb_ide, int *ide_mem_index, int escc_mem_index);
+void macio_init (PCIBus *bus, int device_id, int is_oldworld,
+                 MemoryRegion *pic_mem, MemoryRegion *dbdma_mem,
+                 MemoryRegion *cuda_mem, void *nvram,
+                 int nb_ide, MemoryRegion **ide_mem, MemoryRegion *escc_mem);
 
 /* Heathrow PIC */
-qemu_irq *heathrow_pic_init(int *pmem_index,
+qemu_irq *heathrow_pic_init(MemoryRegion **pmem,
                             int nb_cpus, qemu_irq **irqs);
 
 /* Grackle PCI */
@@ -69,9 +70,10 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic,
 /* Mac NVRAM */
 typedef struct MacIONVRAMState MacIONVRAMState;
 
-MacIONVRAMState *macio_nvram_init (int *mem_index, target_phys_addr_t size,
+MacIONVRAMState *macio_nvram_init (target_phys_addr_t size,
                                    unsigned int it_shift);
-void macio_nvram_map (void *opaque, target_phys_addr_t mem_base);
+void macio_nvram_setup_bar(MacIONVRAMState *s, MemoryRegion *bar,
+                           target_phys_addr_t mem_base);
 void pmac_format_nvram_partition (MacIONVRAMState *nvr, int len);
 uint32_t macio_nvram_read (void *opaque, uint32_t addr);
 void macio_nvram_write (void *opaque, uint32_t addr, uint32_t val);
diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c
index 94a21f9..3039022 100644
--- a/hw/ppc_newworld.c
+++ b/hw/ppc_newworld.c
@@ -144,10 +144,9 @@ static void ppc_core99_init (ram_addr_t ram_size,
     long kernel_size, initrd_size;
     PCIBus *pci_bus;
     MacIONVRAMState *nvr;
-    int nvram_mem_index;
     int bios_size;
-    int pic_mem_index, dbdma_mem_index, cuda_mem_index, escc_mem_index;
-    int ide_mem_index[3];
+    MemoryRegion *pic_mem, *dbdma_mem, *cuda_mem, *escc_mem;
+    MemoryRegion *ide_mem[3];
     int ppc_boot_device;
     DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
     void *fw_cfg;
@@ -315,7 +314,7 @@ static void ppc_core99_init (ram_addr_t ram_size,
             exit(1);
         }
     }
-    pic = openpic_init(NULL, &pic_mem_index, smp_cpus, openpic_irqs, NULL);
+    pic = openpic_init(NULL, &pic_mem, smp_cpus, openpic_irqs, NULL);
     if (PPC_INPUT(env) == PPC_FLAGS_INPUT_970) {
         /* 970 gets a U3 bus */
         pci_bus = pci_pmac_u3_init(pic, get_system_memory(), get_system_io());
@@ -327,32 +326,31 @@ static void ppc_core99_init (ram_addr_t ram_size,
     /* init basic PC hardware */
     pci_vga_init(pci_bus);
 
-    escc_mem_index = escc_init(0x80013000, pic[0x25], pic[0x24],
-                               serial_hds[0], serial_hds[1], ESCC_CLOCK, 4);
+    escc_mem = escc_init(0x80013000, pic[0x25], pic[0x24],
+                         serial_hds[0], serial_hds[1], ESCC_CLOCK, 4);
 
     for(i = 0; i < nb_nics; i++)
         pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL);
 
     ide_drive_get(hd, MAX_IDE_BUS);
-    dbdma = DBDMA_init(&dbdma_mem_index);
+    dbdma = DBDMA_init(&dbdma_mem);
 
     /* We only emulate 2 out of 3 IDE controllers for now */
-    ide_mem_index[0] = -1;
-    ide_mem_index[1] = pmac_ide_init(hd, pic[0x0d], dbdma, 0x16, pic[0x02]);
-    ide_mem_index[2] = pmac_ide_init(&hd[MAX_IDE_DEVS], pic[0x0e], dbdma, 0x1a, pic[0x02]);
+    ide_mem[0] = NULL;
+    ide_mem[1] = pmac_ide_init(hd, pic[0x0d], dbdma, 0x16, pic[0x02]);
+    ide_mem[2] = pmac_ide_init(&hd[MAX_IDE_DEVS], pic[0x0e], dbdma, 0x1a, pic[0x02]);
 
     /* cuda also initialize ADB */
     if (machine_arch == ARCH_MAC99_U3) {
         usb_enabled = 1;
     }
-    cuda_init(&cuda_mem_index, pic[0x19]);
+    cuda_init(&cuda_mem, pic[0x19]);
 
     adb_kbd_init(&adb_bus);
     adb_mouse_init(&adb_bus);
 
-    macio_init(pci_bus, PCI_DEVICE_ID_APPLE_UNI_N_KEYL, 0, pic_mem_index,
-               dbdma_mem_index, cuda_mem_index, NULL, 3, ide_mem_index,
-               escc_mem_index);
+    macio_init(pci_bus, PCI_DEVICE_ID_APPLE_UNI_N_KEYL, 0, pic_mem,
+               dbdma_mem, cuda_mem, NULL, 3, ide_mem, escc_mem);
 
     if (usb_enabled) {
         usb_ohci_init_pci(pci_bus, -1);
@@ -369,9 +367,9 @@ static void ppc_core99_init (ram_addr_t ram_size,
         graphic_depth = 15;
 
     /* The NewWorld NVRAM is not located in the MacIO device */
-    nvr = macio_nvram_init(&nvram_mem_index, 0x2000, 1);
+    nvr = macio_nvram_init(0x2000, 1);
     pmac_format_nvram_partition(nvr, 0x2000);
-    macio_nvram_map(nvr, 0xFFF04000);
+    macio_nvram_setup_bar(nvr, get_system_memory(), 0xFFF04000);
     /* No PCI init: the BIOS will do it */
 
     fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2);
diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c
index 0f99eef..41703a7 100644
--- a/hw/ppc_oldworld.c
+++ b/hw/ppc_oldworld.c
@@ -82,8 +82,8 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
     PCIBus *pci_bus;
     MacIONVRAMState *nvr;
     int bios_size;
-    int pic_mem_index, nvram_mem_index, dbdma_mem_index, cuda_mem_index;
-    int escc_mem_index, ide_mem_index[2];
+    MemoryRegion *pic_mem, *dbdma_mem, *cuda_mem;
+    MemoryRegion *escc_mem, *ide_mem[2];
     uint16_t ppc_boot_device;
     DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
     void *fw_cfg;
@@ -233,13 +233,13 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
     if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) {
         hw_error("Only 6xx bus is supported on heathrow machine\n");
     }
-    pic = heathrow_pic_init(&pic_mem_index, 1, heathrow_irqs);
+    pic = heathrow_pic_init(&pic_mem, 1, heathrow_irqs);
     pci_bus = pci_grackle_init(0xfec00000, pic,
                                get_system_memory(),
                                get_system_io());
     pci_vga_init(pci_bus);
 
-    escc_mem_index = escc_init(0x80013000, pic[0x0f], pic[0x10], serial_hds[0],
+    escc_mem = escc_init(0x80013000, pic[0x0f], pic[0x10], serial_hds[0],
                                serial_hds[1], ESCC_CLOCK, 4);
 
     for(i = 0; i < nb_nics; i++)
@@ -249,9 +249,9 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
     ide_drive_get(hd, MAX_IDE_BUS);
 
     /* First IDE channel is a MAC IDE on the MacIO bus */
-    dbdma = DBDMA_init(&dbdma_mem_index);
-    ide_mem_index[0] = -1;
-    ide_mem_index[1] = pmac_ide_init(hd, pic[0x0D], dbdma, 0x16, pic[0x02]);
+    dbdma = DBDMA_init(&dbdma_mem);
+    ide_mem[0] = NULL;
+    ide_mem[1] = pmac_ide_init(hd, pic[0x0D], dbdma, 0x16, pic[0x02]);
 
     /* Second IDE channel is a CMD646 on the PCI bus */
     hd[0] = hd[MAX_IDE_DEVS];
@@ -260,17 +260,16 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
     pci_cmd646_ide_init(pci_bus, hd, 0);
 
     /* cuda also initialize ADB */
-    cuda_init(&cuda_mem_index, pic[0x12]);
+    cuda_init(&cuda_mem, pic[0x12]);
 
     adb_kbd_init(&adb_bus);
     adb_mouse_init(&adb_bus);
 
-    nvr = macio_nvram_init(&nvram_mem_index, 0x2000, 4);
+    nvr = macio_nvram_init(0x2000, 4);
     pmac_format_nvram_partition(nvr, 0x2000);
 
-    macio_init(pci_bus, PCI_DEVICE_ID_APPLE_343S1201, 1, pic_mem_index,
-               dbdma_mem_index, cuda_mem_index, nvr, 2, ide_mem_index,
-               escc_mem_index);
+    macio_init(pci_bus, PCI_DEVICE_ID_APPLE_343S1201, 1, pic_mem,
+               dbdma_mem, cuda_mem, nvr, 2, ide_mem, escc_mem);
 
     if (usb_enabled) {
         usb_ohci_init_pci(pci_bus, -1);
commit b0ce84e50bd232db4f6fb0f3572d2e274d1787b0
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:09:16 2011 +0300

    lsi53c895a: convert to memory API
    
    An optimization that fast-pathed DMA reads from the SCRIPTS memory
    was removed int the process.  Likely it breaks with iommus anyway.
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index e9904c4..0ab8c78 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -185,9 +185,9 @@ typedef struct lsi_request {
 
 typedef struct {
     PCIDevice dev;
-    int mmio_io_addr;
-    int ram_io_addr;
-    uint32_t script_ram_base;
+    MemoryRegion mmio_io;
+    MemoryRegion ram_io;
+    MemoryRegion io_io;
 
     int carry; /* ??? Should this be an a visible register somewhere?  */
     int status;
@@ -391,10 +391,9 @@ static inline uint32_t read_dword(LSIState *s, uint32_t addr)
 {
     uint32_t buf;
 
-    /* Optimize reading from SCRIPTS RAM.  */
-    if ((addr & 0xffffe000) == s->script_ram_base) {
-        return s->script_ram[(addr & 0x1fff) >> 2];
-    }
+    /* XXX: an optimization here used to fast-path the read from scripts
+     * memory.  But that bypasses any iommu.
+     */
     cpu_physical_memory_read(addr, (uint8_t *)&buf, 4);
     return cpu_to_le32(buf);
 }
@@ -1899,232 +1898,90 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
 #undef CASE_SET_REG32
 }
 
-static void lsi_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+static void lsi_mmio_write(void *opaque, target_phys_addr_t addr,
+                           uint64_t val, unsigned size)
 {
     LSIState *s = opaque;
 
     lsi_reg_writeb(s, addr & 0xff, val);
 }
 
-static void lsi_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    LSIState *s = opaque;
-
-    addr &= 0xff;
-    lsi_reg_writeb(s, addr, val & 0xff);
-    lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff);
-}
-
-static void lsi_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    LSIState *s = opaque;
-
-    addr &= 0xff;
-    lsi_reg_writeb(s, addr, val & 0xff);
-    lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff);
-    lsi_reg_writeb(s, addr + 2, (val >> 16) & 0xff);
-    lsi_reg_writeb(s, addr + 3, (val >> 24) & 0xff);
-}
-
-static uint32_t lsi_mmio_readb(void *opaque, target_phys_addr_t addr)
+static uint64_t lsi_mmio_read(void *opaque, target_phys_addr_t addr,
+                              unsigned size)
 {
     LSIState *s = opaque;
 
     return lsi_reg_readb(s, addr & 0xff);
 }
 
-static uint32_t lsi_mmio_readw(void *opaque, target_phys_addr_t addr)
-{
-    LSIState *s = opaque;
-    uint32_t val;
-
-    addr &= 0xff;
-    val = lsi_reg_readb(s, addr);
-    val |= lsi_reg_readb(s, addr + 1) << 8;
-    return val;
-}
-
-static uint32_t lsi_mmio_readl(void *opaque, target_phys_addr_t addr)
-{
-    LSIState *s = opaque;
-    uint32_t val;
-    addr &= 0xff;
-    val = lsi_reg_readb(s, addr);
-    val |= lsi_reg_readb(s, addr + 1) << 8;
-    val |= lsi_reg_readb(s, addr + 2) << 16;
-    val |= lsi_reg_readb(s, addr + 3) << 24;
-    return val;
-}
-
-static CPUReadMemoryFunc * const lsi_mmio_readfn[3] = {
-    lsi_mmio_readb,
-    lsi_mmio_readw,
-    lsi_mmio_readl,
-};
-
-static CPUWriteMemoryFunc * const lsi_mmio_writefn[3] = {
-    lsi_mmio_writeb,
-    lsi_mmio_writew,
-    lsi_mmio_writel,
+static const MemoryRegionOps lsi_mmio_ops = {
+    .read = lsi_mmio_read,
+    .write = lsi_mmio_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
 };
 
-static void lsi_ram_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+static void lsi_ram_write(void *opaque, target_phys_addr_t addr,
+                          uint64_t val, unsigned size)
 {
     LSIState *s = opaque;
     uint32_t newval;
+    uint32_t mask;
     int shift;
 
-    addr &= 0x1fff;
     newval = s->script_ram[addr >> 2];
     shift = (addr & 3) * 8;
-    newval &= ~(0xff << shift);
+    mask = ((uint64_t)1 << (size * 8)) - 1;
+    newval &= ~(mask << shift);
     newval |= val << shift;
     s->script_ram[addr >> 2] = newval;
 }
 
-static void lsi_ram_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    LSIState *s = opaque;
-    uint32_t newval;
-
-    addr &= 0x1fff;
-    newval = s->script_ram[addr >> 2];
-    if (addr & 2) {
-        newval = (newval & 0xffff) | (val << 16);
-    } else {
-        newval = (newval & 0xffff0000) | val;
-    }
-    s->script_ram[addr >> 2] = newval;
-}
-
-
-static void lsi_ram_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    LSIState *s = opaque;
-
-    addr &= 0x1fff;
-    s->script_ram[addr >> 2] = val;
-}
-
-static uint32_t lsi_ram_readb(void *opaque, target_phys_addr_t addr)
+static uint64_t lsi_ram_read(void *opaque, target_phys_addr_t addr,
+                             unsigned size)
 {
     LSIState *s = opaque;
     uint32_t val;
+    uint32_t mask;
 
-    addr &= 0x1fff;
     val = s->script_ram[addr >> 2];
+    mask = ((uint64_t)1 << (size * 8)) - 1;
     val >>= (addr & 3) * 8;
-    return val & 0xff;
-}
-
-static uint32_t lsi_ram_readw(void *opaque, target_phys_addr_t addr)
-{
-    LSIState *s = opaque;
-    uint32_t val;
-
-    addr &= 0x1fff;
-    val = s->script_ram[addr >> 2];
-    if (addr & 2)
-        val >>= 16;
-    return val;
-}
-
-static uint32_t lsi_ram_readl(void *opaque, target_phys_addr_t addr)
-{
-    LSIState *s = opaque;
-
-    addr &= 0x1fff;
-    return s->script_ram[addr >> 2];
+    return val & mask;
 }
 
-static CPUReadMemoryFunc * const lsi_ram_readfn[3] = {
-    lsi_ram_readb,
-    lsi_ram_readw,
-    lsi_ram_readl,
+static const MemoryRegionOps lsi_ram_ops = {
+    .read = lsi_ram_read,
+    .write = lsi_ram_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const lsi_ram_writefn[3] = {
-    lsi_ram_writeb,
-    lsi_ram_writew,
-    lsi_ram_writel,
-};
-
-static uint32_t lsi_io_readb(void *opaque, uint32_t addr)
+static uint64_t lsi_io_read(void *opaque, target_phys_addr_t addr,
+                            unsigned size)
 {
     LSIState *s = opaque;
     return lsi_reg_readb(s, addr & 0xff);
 }
 
-static uint32_t lsi_io_readw(void *opaque, uint32_t addr)
-{
-    LSIState *s = opaque;
-    uint32_t val;
-    addr &= 0xff;
-    val = lsi_reg_readb(s, addr);
-    val |= lsi_reg_readb(s, addr + 1) << 8;
-    return val;
-}
-
-static uint32_t lsi_io_readl(void *opaque, uint32_t addr)
-{
-    LSIState *s = opaque;
-    uint32_t val;
-    addr &= 0xff;
-    val = lsi_reg_readb(s, addr);
-    val |= lsi_reg_readb(s, addr + 1) << 8;
-    val |= lsi_reg_readb(s, addr + 2) << 16;
-    val |= lsi_reg_readb(s, addr + 3) << 24;
-    return val;
-}
-
-static void lsi_io_writeb(void *opaque, uint32_t addr, uint32_t val)
+static void lsi_io_write(void *opaque, target_phys_addr_t addr,
+                         uint64_t val, unsigned size)
 {
     LSIState *s = opaque;
     lsi_reg_writeb(s, addr & 0xff, val);
 }
 
-static void lsi_io_writew(void *opaque, uint32_t addr, uint32_t val)
-{
-    LSIState *s = opaque;
-    addr &= 0xff;
-    lsi_reg_writeb(s, addr, val & 0xff);
-    lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff);
-}
-
-static void lsi_io_writel(void *opaque, uint32_t addr, uint32_t val)
-{
-    LSIState *s = opaque;
-    addr &= 0xff;
-    lsi_reg_writeb(s, addr, val & 0xff);
-    lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff);
-    lsi_reg_writeb(s, addr + 2, (val >> 16) & 0xff);
-    lsi_reg_writeb(s, addr + 3, (val >> 24) & 0xff);
-}
-
-static void lsi_io_mapfunc(PCIDevice *pci_dev, int region_num,
-                           pcibus_t addr, pcibus_t size, int type)
-{
-    LSIState *s = DO_UPCAST(LSIState, dev, pci_dev);
-
-    DPRINTF("Mapping IO at %08"FMT_PCIBUS"\n", addr);
-
-    register_ioport_write(addr, 256, 1, lsi_io_writeb, s);
-    register_ioport_read(addr, 256, 1, lsi_io_readb, s);
-    register_ioport_write(addr, 256, 2, lsi_io_writew, s);
-    register_ioport_read(addr, 256, 2, lsi_io_readw, s);
-    register_ioport_write(addr, 256, 4, lsi_io_writel, s);
-    register_ioport_read(addr, 256, 4, lsi_io_readl, s);
-}
-
-static void lsi_ram_mapfunc(PCIDevice *pci_dev, int region_num,
-                            pcibus_t addr, pcibus_t size, int type)
-{
-    LSIState *s = DO_UPCAST(LSIState, dev, pci_dev);
-
-    DPRINTF("Mapping ram at %08"FMT_PCIBUS"\n", addr);
-    s->script_ram_base = addr;
-    cpu_register_physical_memory(addr + 0, 0x2000, s->ram_io_addr);
-}
+static const MemoryRegionOps lsi_io_ops = {
+    .read = lsi_io_read,
+    .write = lsi_io_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
 
 static void lsi_scsi_reset(DeviceState *dev)
 {
@@ -2231,8 +2088,9 @@ static int lsi_scsi_uninit(PCIDevice *d)
 {
     LSIState *s = DO_UPCAST(LSIState, dev, d);
 
-    cpu_unregister_io_memory(s->mmio_io_addr);
-    cpu_unregister_io_memory(s->ram_io_addr);
+    memory_region_destroy(&s->mmio_io);
+    memory_region_destroy(&s->ram_io);
+    memory_region_destroy(&s->io_io);
 
     return 0;
 }
@@ -2256,18 +2114,14 @@ static int lsi_scsi_init(PCIDevice *dev)
     /* Interrupt pin 1 */
     pci_conf[PCI_INTERRUPT_PIN] = 0x01;
 
-    s->mmio_io_addr = cpu_register_io_memory(lsi_mmio_readfn,
-                                             lsi_mmio_writefn, s,
-                                             DEVICE_NATIVE_ENDIAN);
-    s->ram_io_addr = cpu_register_io_memory(lsi_ram_readfn,
-                                            lsi_ram_writefn, s,
-                                            DEVICE_NATIVE_ENDIAN);
-
-    pci_register_bar(&s->dev, 0, 256,
-                           PCI_BASE_ADDRESS_SPACE_IO, lsi_io_mapfunc);
-    pci_register_bar_simple(&s->dev, 1, 0x400, 0, s->mmio_io_addr);
-    pci_register_bar(&s->dev, 2, 0x2000,
-                           PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_ram_mapfunc);
+    memory_region_init_io(&s->mmio_io, &lsi_mmio_ops, s, "lsi-mmio", 0x400);
+    memory_region_init_io(&s->ram_io, &lsi_ram_ops, s, "lsi-ram", 0x2000);
+    memory_region_init_io(&s->io_io, &lsi_io_ops, s, "lsi-io", 256);
+
+    pci_register_bar_region(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_io);
+    pci_register_bar_region(&s->dev, 1, 0, &s->mmio_io);
+    pci_register_bar_region(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY,
+                            &s->ram_io);
     QTAILQ_INIT(&s->queue);
 
     scsi_bus_new(&s->bus, &dev->qdev, 1, LSI_MAX_DEVS, &lsi_scsi_ops);
commit 234bbdf1c03b353ef97b5d5fbdfb911c3f99d80e
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:09:15 2011 +0300

    intel-hda: convert to memory API
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index 5a2bc3a..1e4c71e 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -177,7 +177,7 @@ struct IntelHDAState {
     IntelHDAStream st[8];
 
     /* state */
-    int mmio_addr;
+    MemoryRegion mmio;
     uint32_t rirb_count;
     int64_t wall_base_ns;
 
@@ -1084,16 +1084,20 @@ static uint32_t intel_hda_mmio_readl(void *opaque, target_phys_addr_t addr)
     return intel_hda_reg_read(d, reg, 0xffffffff);
 }
 
-static CPUReadMemoryFunc * const intel_hda_mmio_read[3] = {
-    intel_hda_mmio_readb,
-    intel_hda_mmio_readw,
-    intel_hda_mmio_readl,
-};
-
-static CPUWriteMemoryFunc * const intel_hda_mmio_write[3] = {
-    intel_hda_mmio_writeb,
-    intel_hda_mmio_writew,
-    intel_hda_mmio_writel,
+static const MemoryRegionOps intel_hda_mmio_ops = {
+    .old_mmio = {
+        .read = {
+            intel_hda_mmio_readb,
+            intel_hda_mmio_readw,
+            intel_hda_mmio_readl,
+        },
+        .write = {
+            intel_hda_mmio_writeb,
+            intel_hda_mmio_writew,
+            intel_hda_mmio_writel,
+        },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 /* --------------------------------------------------------------------- */
@@ -1130,10 +1134,9 @@ static int intel_hda_init(PCIDevice *pci)
     /* HDCTL off 0x40 bit 0 selects signaling mode (1-HDA, 0 - Ac97) 18.1.19 */
     conf[0x40] = 0x01;
 
-    d->mmio_addr = cpu_register_io_memory(intel_hda_mmio_read,
-                                          intel_hda_mmio_write, d,
-                                          DEVICE_NATIVE_ENDIAN);
-    pci_register_bar_simple(&d->pci, 0, 0x4000, 0, d->mmio_addr);
+    memory_region_init_io(&d->mmio, &intel_hda_mmio_ops, d,
+                          "intel-hda", 0x4000);
+    pci_register_bar_region(&d->pci, 0, 0, &d->mmio);
     if (d->msi) {
         msi_init(&d->pci, 0x50, 1, true, false);
     }
@@ -1149,7 +1152,7 @@ static int intel_hda_exit(PCIDevice *pci)
     IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
 
     msi_uninit(&d->pci);
-    cpu_unregister_io_memory(d->mmio_addr);
+    memory_region_destroy(&d->mmio);
     return 0;
 }
 
commit 67e576c262d1368ba3e9c7037c0e71027e21c534
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:09:14 2011 +0300

    ahci: convert to memory API
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 1f008a3..e207ca0 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -276,12 +276,12 @@ static void  ahci_port_write(AHCIState *s, int port, int offset, uint32_t val)
     }
 }
 
-static uint32_t ahci_mem_readl(void *ptr, target_phys_addr_t addr)
+static uint64_t ahci_mem_read(void *opaque, target_phys_addr_t addr,
+                              unsigned size)
 {
-    AHCIState *s = ptr;
+    AHCIState *s = opaque;
     uint32_t val = 0;
 
-    addr = addr & 0xfff;
     if (addr < AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR) {
         switch (addr) {
         case HOST_CAP:
@@ -314,10 +314,10 @@ static uint32_t ahci_mem_readl(void *ptr, target_phys_addr_t addr)
 
 
 
-static void ahci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
+static void ahci_mem_write(void *opaque, target_phys_addr_t addr,
+                           uint64_t val, unsigned size)
 {
-    AHCIState *s = ptr;
-    addr = addr & 0xfff;
+    AHCIState *s = opaque;
 
     /* Only aligned reads are allowed on AHCI */
     if (addr & 3) {
@@ -364,16 +364,10 @@ static void ahci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
 
 }
 
-static CPUReadMemoryFunc * const ahci_readfn[3]={
-    ahci_mem_readl,
-    ahci_mem_readl,
-    ahci_mem_readl
-};
-
-static CPUWriteMemoryFunc * const ahci_writefn[3]={
-    ahci_mem_writel,
-    ahci_mem_writel,
-    ahci_mem_writel
+static MemoryRegionOps ahci_mem_ops = {
+    .read = ahci_mem_read,
+    .write = ahci_mem_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
 static void ahci_reg_init(AHCIState *s)
@@ -1131,8 +1125,8 @@ void ahci_init(AHCIState *s, DeviceState *qdev, int ports)
     s->ports = ports;
     s->dev = qemu_mallocz(sizeof(AHCIDevice) * ports);
     ahci_reg_init(s);
-    s->mem = cpu_register_io_memory(ahci_readfn, ahci_writefn, s,
-                                    DEVICE_LITTLE_ENDIAN);
+    /* XXX BAR size should be 1k, but that breaks, so bump it to 4k for now */
+    memory_region_init_io(&s->mem, &ahci_mem_ops, s, "ahci", 0x1000);
     irqs = qemu_allocate_irqs(ahci_irq_set, s, s->ports);
 
     for (i = 0; i < s->ports; i++) {
@@ -1151,6 +1145,7 @@ void ahci_init(AHCIState *s, DeviceState *qdev, int ports)
 
 void ahci_uninit(AHCIState *s)
 {
+    memory_region_destroy(&s->mem);
     qemu_free(s->dev);
 }
 
diff --git a/hw/ide/ahci.h b/hw/ide/ahci.h
index dc86951..e456193 100644
--- a/hw/ide/ahci.h
+++ b/hw/ide/ahci.h
@@ -289,7 +289,7 @@ struct AHCIDevice {
 typedef struct AHCIState {
     AHCIDevice *dev;
     AHCIControlRegs control_regs;
-    int mem;
+    MemoryRegion mem;
     int ports;
     qemu_irq irq;
 } AHCIState;
diff --git a/hw/ide/ich.c b/hw/ide/ich.c
index d241ea8..698b5f6 100644
--- a/hw/ide/ich.c
+++ b/hw/ide/ich.c
@@ -98,8 +98,7 @@ static int pci_ich9_ahci_init(PCIDevice *dev)
     msi_init(dev, 0x50, 1, true, false);
     d->ahci.irq = d->card.irq[0];
 
-    /* XXX BAR size should be 1k, but that breaks, so bump it to 4k for now */
-    pci_register_bar_simple(&d->card, 5, 0x1000, 0, d->ahci.mem);
+    pci_register_bar_region(&d->card, 5, 0, &d->ahci.mem);
 
     return 0;
 }
commit da146d0aadd8438a068886f3f1bc98d20adaaaf3
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:09:13 2011 +0300

    virtio-pci: convert to memory API
    
    except msix.
    
    [jan: fix build]
    [aliguori: fix build]
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index f3b3293..86c3229 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -162,7 +162,8 @@ static int virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy,
 {
     VirtQueue *vq = virtio_get_queue(proxy->vdev, n);
     EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
-    int r;
+    int r = 0;
+
     if (assign) {
         r = event_notifier_init(notifier, 1);
         if (r < 0) {
@@ -170,24 +171,11 @@ static int virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy,
                          __func__, r);
             return r;
         }
-        r = kvm_set_ioeventfd_pio_word(event_notifier_get_fd(notifier),
-                                       proxy->addr + VIRTIO_PCI_QUEUE_NOTIFY,
-                                       n, assign);
-        if (r < 0) {
-            error_report("%s: unable to map ioeventfd: %d",
-                         __func__, r);
-            event_notifier_cleanup(notifier);
-        }
+        memory_region_add_eventfd(&proxy->bar, VIRTIO_PCI_QUEUE_NOTIFY, 2,
+                                  true, n, event_notifier_get_fd(notifier));
     } else {
-        r = kvm_set_ioeventfd_pio_word(event_notifier_get_fd(notifier),
-                                       proxy->addr + VIRTIO_PCI_QUEUE_NOTIFY,
-                                       n, assign);
-        if (r < 0) {
-            error_report("%s: unable to unmap ioeventfd: %d",
-                         __func__, r);
-            return r;
-        }
-
+        memory_region_del_eventfd(&proxy->bar, VIRTIO_PCI_QUEUE_NOTIFY, 2,
+                                  true, n, event_notifier_get_fd(notifier));
         /* Handle the race condition where the guest kicked and we deassigned
          * before we got around to handling the kick.
          */
@@ -424,7 +412,6 @@ static uint32_t virtio_pci_config_readb(void *opaque, uint32_t addr)
 {
     VirtIOPCIProxy *proxy = opaque;
     uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
-    addr -= proxy->addr;
     if (addr < config)
         return virtio_ioport_read(proxy, addr);
     addr -= config;
@@ -435,7 +422,6 @@ static uint32_t virtio_pci_config_readw(void *opaque, uint32_t addr)
 {
     VirtIOPCIProxy *proxy = opaque;
     uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
-    addr -= proxy->addr;
     if (addr < config)
         return virtio_ioport_read(proxy, addr);
     addr -= config;
@@ -446,7 +432,6 @@ static uint32_t virtio_pci_config_readl(void *opaque, uint32_t addr)
 {
     VirtIOPCIProxy *proxy = opaque;
     uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
-    addr -= proxy->addr;
     if (addr < config)
         return virtio_ioport_read(proxy, addr);
     addr -= config;
@@ -457,7 +442,6 @@ static void virtio_pci_config_writeb(void *opaque, uint32_t addr, uint32_t val)
 {
     VirtIOPCIProxy *proxy = opaque;
     uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
-    addr -= proxy->addr;
     if (addr < config) {
         virtio_ioport_write(proxy, addr, val);
         return;
@@ -470,7 +454,6 @@ static void virtio_pci_config_writew(void *opaque, uint32_t addr, uint32_t val)
 {
     VirtIOPCIProxy *proxy = opaque;
     uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
-    addr -= proxy->addr;
     if (addr < config) {
         virtio_ioport_write(proxy, addr, val);
         return;
@@ -483,7 +466,6 @@ static void virtio_pci_config_writel(void *opaque, uint32_t addr, uint32_t val)
 {
     VirtIOPCIProxy *proxy = opaque;
     uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
-    addr -= proxy->addr;
     if (addr < config) {
         virtio_ioport_write(proxy, addr, val);
         return;
@@ -492,25 +474,20 @@ static void virtio_pci_config_writel(void *opaque, uint32_t addr, uint32_t val)
     virtio_config_writel(proxy->vdev, addr, val);
 }
 
-static void virtio_map(PCIDevice *pci_dev, int region_num,
-                       pcibus_t addr, pcibus_t size, int type)
-{
-    VirtIOPCIProxy *proxy = container_of(pci_dev, VirtIOPCIProxy, pci_dev);
-    VirtIODevice *vdev = proxy->vdev;
-    unsigned config_len = VIRTIO_PCI_REGION_SIZE(pci_dev) + vdev->config_len;
-
-    proxy->addr = addr;
-
-    register_ioport_write(addr, config_len, 1, virtio_pci_config_writeb, proxy);
-    register_ioport_write(addr, config_len, 2, virtio_pci_config_writew, proxy);
-    register_ioport_write(addr, config_len, 4, virtio_pci_config_writel, proxy);
-    register_ioport_read(addr, config_len, 1, virtio_pci_config_readb, proxy);
-    register_ioport_read(addr, config_len, 2, virtio_pci_config_readw, proxy);
-    register_ioport_read(addr, config_len, 4, virtio_pci_config_readl, proxy);
+const MemoryRegionPortio virtio_portio[] = {
+    { 0, 0x10000, 1, .write = virtio_pci_config_writeb, },
+    { 0, 0x10000, 2, .write = virtio_pci_config_writew, },
+    { 0, 0x10000, 4, .write = virtio_pci_config_writel, },
+    { 0, 0x10000, 1, .read = virtio_pci_config_readb, },
+    { 0, 0x10000, 2, .read = virtio_pci_config_readw, },
+    { 0, 0x10000, 4, .read = virtio_pci_config_readl, },
+    PORTIO_END_OF_LIST()
+};
 
-    if (vdev->config_len)
-        vdev->get_config(vdev, vdev->config);
-}
+static const MemoryRegionOps virtio_pci_config_ops = {
+    .old_portio = virtio_portio,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
 
 static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
                                 uint32_t val, int len)
@@ -678,8 +655,10 @@ void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev)
     if (size & (size-1))
         size = 1 << qemu_fls(size);
 
-    pci_register_bar(&proxy->pci_dev, 0, size, PCI_BASE_ADDRESS_SPACE_IO,
-                           virtio_map);
+    memory_region_init_io(&proxy->bar, &virtio_pci_config_ops, proxy,
+                          "virtio-pci", size);
+    pci_register_bar_region(&proxy->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO,
+                            &proxy->bar);
 
     if (!kvm_has_many_ioeventfds()) {
         proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD;
@@ -714,6 +693,9 @@ static int virtio_blk_init_pci(PCIDevice *pci_dev)
 
 static int virtio_exit_pci(PCIDevice *pci_dev)
 {
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+
+    memory_region_destroy(&proxy->bar);
     return msix_uninit(pci_dev);
 }
 
diff --git a/hw/virtio-pci.h b/hw/virtio-pci.h
index 1f0de56..5af1c8c 100644
--- a/hw/virtio-pci.h
+++ b/hw/virtio-pci.h
@@ -21,8 +21,8 @@
 typedef struct {
     PCIDevice pci_dev;
     VirtIODevice *vdev;
+    MemoryRegion bar;
     uint32_t flags;
-    uint32_t addr;
     uint32_t class_code;
     uint32_t nvectors;
     BlockConf block;
commit cb06608e17f8308b45768eaa76a21ecc48e76305
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:09:12 2011 +0300

    ivshmem: convert to memory API
    
    excluding msix.
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/ivshmem.c b/hw/ivshmem.c
index 3055dd2..f80e7b6 100644
--- a/hw/ivshmem.c
+++ b/hw/ivshmem.c
@@ -56,11 +56,15 @@ typedef struct IVShmemState {
 
     CharDriverState **eventfd_chr;
     CharDriverState *server_chr;
-    int ivshmem_mmio_io_addr;
+    MemoryRegion ivshmem_mmio;
 
     pcibus_t mmio_addr;
-    pcibus_t shm_pci_addr;
-    uint64_t ivshmem_offset;
+    /* We might need to register the BAR before we actually have the memory.
+     * So prepare a container MemoryRegion for the BAR immediately and
+     * add a subregion when we have the memory.
+     */
+    MemoryRegion bar;
+    MemoryRegion ivshmem;
     uint64_t ivshmem_size; /* size of shared memory region */
     int shm_fd; /* shared memory file descriptor */
 
@@ -96,23 +100,6 @@ 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)
 {
@@ -168,15 +155,8 @@ static uint32_t ivshmem_IntrStatus_read(IVShmemState *s)
     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)
+static void ivshmem_io_write(void *opaque, target_phys_addr_t addr,
+                             uint64_t val, unsigned size)
 {
     IVShmemState *s = opaque;
 
@@ -219,20 +199,8 @@ static void ivshmem_io_writel(void *opaque, target_phys_addr_t addr,
     }
 }
 
-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)
+static uint64_t ivshmem_io_read(void *opaque, target_phys_addr_t addr,
+                                unsigned size)
 {
 
     IVShmemState *s = opaque;
@@ -265,23 +233,14 @@ static uint32_t ivshmem_io_readl(void *opaque, target_phys_addr_t addr)
     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 const MemoryRegionOps ivshmem_mmio_ops = {
+    .read = ivshmem_io_read,
+    .write = ivshmem_io_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
 };
 
 static void ivshmem_receive(void *opaque, const uint8_t *buf, int size)
@@ -371,12 +330,12 @@ static void create_shared_memory_BAR(IVShmemState *s, int 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);
+    memory_region_init_ram_ptr(&s->ivshmem, &s->dev.qdev, "ivshmem.bar2",
+                               s->ivshmem_size, ptr);
+    memory_region_add_subregion(&s->bar, 0, &s->ivshmem);
 
     /* region for shared memory */
-    pci_register_bar(&s->dev, 2, s->ivshmem_size,
-                                PCI_BASE_ADDRESS_SPACE_MEMORY, ivshmem_map);
+    pci_register_bar_region(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar);
 }
 
 static void close_guest_eventfds(IVShmemState *s, int posn)
@@ -401,8 +360,12 @@ static void setup_ioeventfds(IVShmemState *s) {
 
     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);
+            memory_region_add_eventfd(&s->ivshmem_mmio,
+                                      DOORBELL,
+                                      4,
+                                      true,
+                                      (i << 16) | j,
+                                      s->peers[i].eventfds[j]);
         }
     }
 }
@@ -483,18 +446,13 @@ static void ivshmem_read(void *opaque, const uint8_t * buf, int flags)
         /* 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);
+        memory_region_init_ram_ptr(&s->ivshmem, &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,
+        IVSHMEM_DPRINTF("guest h/w addr = %" PRIu64 ", size = %" PRIu64 "\n",
                          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);
-        }
+        memory_region_add_subregion(&s->bar, 0, &s->ivshmem);
 
         /* only store the fd if it is successfully mapped */
         s->shm_fd = incoming_fd;
@@ -549,20 +507,6 @@ static void ivshmem_reset(DeviceState *d)
     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;
@@ -710,15 +654,20 @@ static int pci_ivshmem_init(PCIDevice *dev)
 
     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, DEVICE_NATIVE_ENDIAN);
+    memory_region_init_io(&s->ivshmem_mmio, &ivshmem_mmio_ops, s,
+                          "ivshmem-mmio", IVSHMEM_REG_BAR_SIZE);
+
+    if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
+        setup_ioeventfds(s);
+    }
+
     /* region for registers*/
-    pci_register_bar(&s->dev, 0, IVSHMEM_REG_BAR_SIZE,
-                           PCI_BASE_ADDRESS_SPACE_MEMORY, ivshmem_mmio_map);
+    pci_register_bar_region(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
+                            &s->ivshmem_mmio);
+
+    memory_region_init(&s->bar, "ivshmem-bar2-container", s->ivshmem_size);
 
     if ((s->server_chr != NULL) &&
                         (strncmp(s->server_chr->filename, "unix:", 5) == 0)) {
@@ -744,8 +693,8 @@ static int pci_ivshmem_init(PCIDevice *dev)
         /* 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);
+        pci_register_bar_region(&s->dev, 2,
+                                PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ivshmem);
 
         s->eventfd_chr = qemu_mallocz(s->vectors * sizeof(CharDriverState *));
 
@@ -792,7 +741,10 @@ static int pci_ivshmem_uninit(PCIDevice *dev)
 {
     IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev);
 
-    cpu_unregister_io_memory(s->ivshmem_mmio_io_addr);
+    memory_region_destroy(&s->ivshmem_mmio);
+    memory_region_del_subregion(&s->bar, &s->ivshmem);
+    memory_region_destroy(&s->ivshmem);
+    memory_region_destroy(&s->bar);
     unregister_savevm(&dev->qdev, "ivshmem", s);
 
     return 0;
commit a9deb8c69abdc7ff85ec81920cbc350437fc8a2f
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:09:11 2011 +0300

    ide: convert to memory API
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c
index 56302b5..13e6f2f 100644
--- a/hw/ide/cmd646.c
+++ b/hw/ide/cmd646.c
@@ -44,35 +44,95 @@
 
 static void cmd646_update_irq(PCIIDEState *d);
 
-static void ide_map(PCIDevice *pci_dev, int region_num,
-                    pcibus_t addr, pcibus_t size, int type)
+static uint64_t cmd646_cmd_read(void *opaque, target_phys_addr_t addr,
+                                unsigned size)
 {
-    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev);
-    IDEBus *bus;
-
-    if (region_num <= 3) {
-        bus = &d->bus[(region_num >> 1)];
-        if (region_num & 1) {
-            register_ioport_read(addr + 2, 1, 1, ide_status_read, bus);
-            register_ioport_write(addr + 2, 1, 1, ide_cmd_write, bus);
+    CMD646BAR *cmd646bar = opaque;
+
+    if (addr != 2 || size != 1) {
+        return ((uint64_t)1 << (size * 8)) - 1;
+    }
+    return ide_status_read(cmd646bar->bus, addr + 2);
+}
+
+static void cmd646_cmd_write(void *opaque, target_phys_addr_t addr,
+                             uint64_t data, unsigned size)
+{
+    CMD646BAR *cmd646bar = opaque;
+
+    if (addr != 2 || size != 1) {
+        return;
+    }
+    ide_cmd_write(cmd646bar->bus, addr + 2, data);
+}
+
+static MemoryRegionOps cmd646_cmd_ops = {
+    .read = cmd646_cmd_read,
+    .write = cmd646_cmd_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static uint64_t cmd646_data_read(void *opaque, target_phys_addr_t addr,
+                                 unsigned size)
+{
+    CMD646BAR *cmd646bar = opaque;
+
+    if (size == 1) {
+        return ide_ioport_read(cmd646bar->bus, addr);
+    } else if (addr == 0) {
+        if (size == 2) {
+            return ide_data_readw(cmd646bar->bus, addr);
         } else {
-            register_ioport_write(addr, 8, 1, ide_ioport_write, bus);
-            register_ioport_read(addr, 8, 1, ide_ioport_read, bus);
-
-            /* data ports */
-            register_ioport_write(addr, 2, 2, ide_data_writew, bus);
-            register_ioport_read(addr, 2, 2, ide_data_readw, bus);
-            register_ioport_write(addr, 4, 4, ide_data_writel, bus);
-            register_ioport_read(addr, 4, 4, ide_data_readl, bus);
+            return ide_data_readl(cmd646bar->bus, addr);
         }
     }
+    return ((uint64_t)1 << (size * 8)) - 1;
 }
 
-static uint32_t bmdma_readb_common(PCIIDEState *pci_dev, BMDMAState *bm,
-                                   uint32_t addr)
+static void cmd646_data_write(void *opaque, target_phys_addr_t addr,
+                             uint64_t data, unsigned size)
 {
+    CMD646BAR *cmd646bar = opaque;
+
+    if (size == 1) {
+        return ide_ioport_write(cmd646bar->bus, addr, data);
+    } else if (addr == 0) {
+        if (size == 2) {
+            return ide_data_writew(cmd646bar->bus, addr, data);
+        } else {
+            return ide_data_writel(cmd646bar->bus, addr, data);
+        }
+    }
+}
+
+static MemoryRegionOps cmd646_data_ops = {
+    .read = cmd646_data_read,
+    .write = cmd646_data_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void setup_cmd646_bar(PCIIDEState *d, int bus_num)
+{
+    IDEBus *bus = &d->bus[bus_num];
+    CMD646BAR *bar = &d->cmd646_bar[bus_num];
+
+    bar->bus = bus;
+    bar->pci_dev = d;
+    memory_region_init_io(&bar->cmd, &cmd646_cmd_ops, bar, "cmd646-cmd", 4);
+    memory_region_init_io(&bar->data, &cmd646_data_ops, bar, "cmd646-data", 8);
+}
+
+static uint64_t bmdma_read(void *opaque, target_phys_addr_t addr,
+                           unsigned size)
+{
+    BMDMAState *bm = opaque;
+    PCIIDEState *pci_dev = bm->pci_dev;
     uint32_t val;
 
+    if (size != 1) {
+        return ((uint64_t)1 << (size * 8)) - 1;
+    }
+
     switch(addr & 3) {
     case 0:
         val = bm->cmd;
@@ -100,31 +160,22 @@ static uint32_t bmdma_readb_common(PCIIDEState *pci_dev, BMDMAState *bm,
     return val;
 }
 
-static uint32_t bmdma_readb_0(void *opaque, uint32_t addr)
+static void bmdma_write(void *opaque, target_phys_addr_t addr,
+                        uint64_t val, unsigned size)
 {
-    PCIIDEState *pci_dev = opaque;
-    BMDMAState *bm = &pci_dev->bmdma[0];
-
-    return bmdma_readb_common(pci_dev, bm, addr);
-}
+    BMDMAState *bm = opaque;
+    PCIIDEState *pci_dev = bm->pci_dev;
 
-static uint32_t bmdma_readb_1(void *opaque, uint32_t addr)
-{
-    PCIIDEState *pci_dev = opaque;
-    BMDMAState *bm = &pci_dev->bmdma[1];
-
-    return bmdma_readb_common(pci_dev, bm, addr);
-}
+    if (size != 1) {
+        return;
+    }
 
-static void bmdma_writeb_common(PCIIDEState *pci_dev, BMDMAState *bm,
-                                uint32_t addr, uint32_t val)
-{
 #ifdef DEBUG_IDE
     printf("bmdma: writeb 0x%02x : 0x%02x\n", addr, val);
 #endif
     switch(addr & 3) {
     case 0:
-        bmdma_cmd_writeb(bm, addr, val);
+        bmdma_cmd_writeb(bm, val);
         break;
     case 1:
         pci_dev->dev.config[MRDMODE] =
@@ -143,42 +194,25 @@ static void bmdma_writeb_common(PCIIDEState *pci_dev, BMDMAState *bm,
     }
 }
 
-static void bmdma_writeb_0(void *opaque, uint32_t addr, uint32_t val)
-{
-    PCIIDEState *pci_dev = opaque;
-    BMDMAState *bm = &pci_dev->bmdma[0];
-
-    bmdma_writeb_common(pci_dev, bm, addr, val);
-}
-
-static void bmdma_writeb_1(void *opaque, uint32_t addr, uint32_t val)
-{
-    PCIIDEState *pci_dev = opaque;
-    BMDMAState *bm = &pci_dev->bmdma[1];
-
-    bmdma_writeb_common(pci_dev, bm, addr, val);
-}
+static MemoryRegionOps cmd646_bmdma_ops = {
+    .read = bmdma_read,
+    .write = bmdma_write,
+};
 
-static void bmdma_map(PCIDevice *pci_dev, int region_num,
-                    pcibus_t addr, pcibus_t size, int type)
+static void bmdma_setup_bar(PCIIDEState *d)
 {
-    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev);
+    BMDMAState *bm;
     int i;
 
+    memory_region_init(&d->bmdma_bar, "cmd646-bmdma", 16);
     for(i = 0;i < 2; i++) {
-        BMDMAState *bm = &d->bmdma[i];
-
-        if (i == 0) {
-            register_ioport_write(addr, 4, 1, bmdma_writeb_0, d);
-            register_ioport_read(addr, 4, 1, bmdma_readb_0, d);
-        } else {
-            register_ioport_write(addr, 4, 1, bmdma_writeb_1, d);
-            register_ioport_read(addr, 4, 1, bmdma_readb_1, d);
-        }
-
-        iorange_init(&bm->addr_ioport, &bmdma_addr_ioport_ops, addr + 4, 4);
-        ioport_register(&bm->addr_ioport);
-        addr += 8;
+        bm = &d->bmdma[i];
+        memory_region_init_io(&bm->extra_io, &cmd646_bmdma_ops, bm,
+                              "cmd646-bmdma-bus", 4);
+        memory_region_add_subregion(&d->bmdma_bar, i * 8, &bm->extra_io);
+        memory_region_init_io(&bm->addr_ioport, &bmdma_addr_ioport_ops, bm,
+                              "cmd646-bmdma-ioport", 4);
+        memory_region_add_subregion(&d->bmdma_bar, i * 8 + 4, &bm->addr_ioport);
     }
 }
 
@@ -234,11 +268,18 @@ static int pci_cmd646_ide_initfn(PCIDevice *dev)
         pci_conf[0x51] |= 0x08; /* enable IDE1 */
     }
 
-    pci_register_bar(dev, 0, 0x8, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
-    pci_register_bar(dev, 1, 0x4, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
-    pci_register_bar(dev, 2, 0x8, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
-    pci_register_bar(dev, 3, 0x4, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
-    pci_register_bar(dev, 4, 0x10, PCI_BASE_ADDRESS_SPACE_IO, bmdma_map);
+    setup_cmd646_bar(d, 0);
+    setup_cmd646_bar(d, 1);
+    pci_register_bar_region(dev, 0, PCI_BASE_ADDRESS_SPACE_IO,
+                            &d->cmd646_bar[0].data);
+    pci_register_bar_region(dev, 1, PCI_BASE_ADDRESS_SPACE_IO,
+                            &d->cmd646_bar[0].cmd);
+    pci_register_bar_region(dev, 2, PCI_BASE_ADDRESS_SPACE_IO,
+                            &d->cmd646_bar[1].data);
+    pci_register_bar_region(dev, 3, PCI_BASE_ADDRESS_SPACE_IO,
+                            &d->cmd646_bar[1].cmd);
+    bmdma_setup_bar(d);
+    pci_register_bar_region(dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &d->bmdma_bar);
 
     /* TODO: RST# value should be 0 */
     pci_conf[PCI_INTERRUPT_PIN] = 0x01; // interrupt on pin 1
@@ -248,7 +289,7 @@ static int pci_cmd646_ide_initfn(PCIDevice *dev)
         ide_bus_new(&d->bus[i], &d->dev.qdev, i);
         ide_init2(&d->bus[i], irq[i]);
 
-        bmdma_init(&d->bus[i], &d->bmdma[i]);
+        bmdma_init(&d->bus[i], &d->bmdma[i], d);
         d->bmdma[i].bus = &d->bus[i];
         qemu_add_vm_change_state_handler(d->bus[i].dma->ops->restart_cb,
                                          &d->bmdma[i].dma);
@@ -259,6 +300,24 @@ static int pci_cmd646_ide_initfn(PCIDevice *dev)
     return 0;
 }
 
+static int pci_cmd646_ide_exitfn(PCIDevice *dev)
+{
+    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);
+    unsigned i;
+
+    for (i = 0; i < 2; ++i) {
+        memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].extra_io);
+        memory_region_destroy(&d->bmdma[i].extra_io);
+        memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].addr_ioport);
+        memory_region_destroy(&d->bmdma[i].addr_ioport);
+        memory_region_destroy(&d->cmd646_bar[i].cmd);
+        memory_region_destroy(&d->cmd646_bar[i].data);
+    }
+    memory_region_destroy(&d->bmdma_bar);
+
+    return 0;
+}
+
 void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table,
                          int secondary_ide_enabled)
 {
@@ -276,6 +335,7 @@ static PCIDeviceInfo cmd646_ide_info[] = {
         .qdev.name    = "cmd646-ide",
         .qdev.size    = sizeof(PCIIDEState),
         .init         = pci_cmd646_ide_initfn,
+        .exit         = pci_cmd646_ide_exitfn,
         .vendor_id    = PCI_VENDOR_ID_CMD,
         .device_id    = PCI_DEVICE_ID_CMD_646,
         .revision     = 0x07, // IDE controller revision
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index 9f3050a..d1a14d7 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -287,9 +287,8 @@ static void bmdma_irq(void *opaque, int n, int level)
     qemu_set_irq(bm->irq, level);
 }
 
-void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
+void bmdma_cmd_writeb(BMDMAState *bm, uint32_t val)
 {
-    BMDMAState *bm = opaque;
 #ifdef DEBUG_IDE
     printf("%s: 0x%08x\n", __func__, val);
 #endif
@@ -328,22 +327,24 @@ void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
     bm->cmd = val & 0x09;
 }
 
-static void bmdma_addr_read(IORange *ioport, uint64_t addr,
-                            unsigned width, uint64_t *data)
+static uint64_t bmdma_addr_read(void *opaque, target_phys_addr_t addr,
+                                unsigned width)
 {
-    BMDMAState *bm = container_of(ioport, BMDMAState, addr_ioport);
+    BMDMAState *bm = opaque;
     uint32_t mask = (1ULL << (width * 8)) - 1;
+    uint64_t data;
 
-    *data = (bm->addr >> (addr * 8)) & mask;
+    data = (bm->addr >> (addr * 8)) & mask;
 #ifdef DEBUG_IDE
     printf("%s: 0x%08x\n", __func__, (unsigned)*data);
 #endif
+    return data;
 }
 
-static void bmdma_addr_write(IORange *ioport, uint64_t addr,
-                             unsigned width, uint64_t data)
+static void bmdma_addr_write(void *opaque, target_phys_addr_t addr,
+                             uint64_t data, unsigned width)
 {
-    BMDMAState *bm = container_of(ioport, BMDMAState, addr_ioport);
+    BMDMAState *bm = opaque;
     int shift = addr * 8;
     uint32_t mask = (1ULL << (width * 8)) - 1;
 
@@ -354,9 +355,10 @@ static void bmdma_addr_write(IORange *ioport, uint64_t addr,
     bm->addr |= ((data & mask) << shift) & ~3;
 }
 
-const IORangeOps bmdma_addr_ioport_ops = {
+MemoryRegionOps bmdma_addr_ioport_ops = {
     .read = bmdma_addr_read,
     .write = bmdma_addr_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
 static bool ide_bmdma_current_needed(void *opaque)
@@ -514,7 +516,7 @@ static const struct IDEDMAOps bmdma_ops = {
     .reset = bmdma_reset,
 };
 
-void bmdma_init(IDEBus *bus, BMDMAState *bm)
+void bmdma_init(IDEBus *bus, BMDMAState *bm, PCIIDEState *d)
 {
     qemu_irq *irq;
 
@@ -527,4 +529,5 @@ void bmdma_init(IDEBus *bus, BMDMAState *bm)
     bm->irq = bus->irq;
     irq = qemu_allocate_irqs(bmdma_irq, bm, 1);
     bus->irq = *irq;
+    bm->pci_dev = d;
 }
diff --git a/hw/ide/pci.h b/hw/ide/pci.h
index b4f3691..a694e54 100644
--- a/hw/ide/pci.h
+++ b/hw/ide/pci.h
@@ -19,20 +19,31 @@ typedef struct BMDMAState {
     BlockDriverCompletionFunc *dma_cb;
     int64_t sector_num;
     uint32_t nsector;
-    IORange addr_ioport;
+    MemoryRegion addr_ioport;
+    MemoryRegion extra_io;
     QEMUBH *bh;
     qemu_irq irq;
 
     /* Bit 0-2 and 7:   BM status register
      * Bit 3-6:         bus->error_status */
     uint8_t migration_compat_status;
+    struct PCIIDEState *pci_dev;
 } BMDMAState;
 
+typedef struct CMD646BAR {
+    MemoryRegion cmd;
+    MemoryRegion data;
+    IDEBus *bus;
+    struct PCIIDEState *pci_dev;
+} CMD646BAR;
+
 typedef struct PCIIDEState {
     PCIDevice dev;
     IDEBus bus[2];
     BMDMAState bmdma[2];
     uint32_t secondary; /* used only for cmd646 */
+    MemoryRegion bmdma_bar;
+    CMD646BAR cmd646_bar[2]; /* used only for cmd646 */
 } PCIIDEState;
 
 
@@ -43,9 +54,9 @@ static inline IDEState *bmdma_active_if(BMDMAState *bmdma)
 }
 
 
-void bmdma_init(IDEBus *bus, BMDMAState *bm);
-void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val);
-extern const IORangeOps bmdma_addr_ioport_ops;
+void bmdma_init(IDEBus *bus, BMDMAState *bm, PCIIDEState *d);
+void bmdma_cmd_writeb(BMDMAState *bm, uint32_t val);
+extern MemoryRegionOps bmdma_addr_ioport_ops;
 void pci_ide_create_devs(PCIDevice *dev, DriveInfo **hd_table);
 
 extern const VMStateDescription vmstate_ide_pci;
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index f527dbd..5aa0a30 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -33,11 +33,15 @@
 
 #include <hw/ide/pci.h>
 
-static uint32_t bmdma_readb(void *opaque, uint32_t addr)
+static uint64_t bmdma_read(void *opaque, target_phys_addr_t addr, unsigned size)
 {
     BMDMAState *bm = opaque;
     uint32_t val;
 
+    if (size != 1) {
+        return ((uint64_t)1 << (size * 8)) - 1;
+    }
+
     switch(addr & 3) {
     case 0:
         val = bm->cmd;
@@ -55,36 +59,46 @@ static uint32_t bmdma_readb(void *opaque, uint32_t addr)
     return val;
 }
 
-static void bmdma_writeb(void *opaque, uint32_t addr, uint32_t val)
+static void bmdma_write(void *opaque, target_phys_addr_t addr,
+                        uint64_t val, unsigned size)
 {
     BMDMAState *bm = opaque;
+
+    if (size != 1) {
+        return;
+    }
+
 #ifdef DEBUG_IDE
     printf("bmdma: writeb 0x%02x : 0x%02x\n", addr, val);
 #endif
     switch(addr & 3) {
+    case 0:
+        return bmdma_cmd_writeb(bm, val);
     case 2:
         bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06);
         break;
     }
 }
 
-static void bmdma_map(PCIDevice *pci_dev, int region_num,
-                    pcibus_t addr, pcibus_t size, int type)
+static MemoryRegionOps piix_bmdma_ops = {
+    .read = bmdma_read,
+    .write = bmdma_write,
+};
+
+static void bmdma_setup_bar(PCIIDEState *d)
 {
-    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev);
     int i;
 
+    memory_region_init(&d->bmdma_bar, "piix-bmdma-container", 16);
     for(i = 0;i < 2; i++) {
         BMDMAState *bm = &d->bmdma[i];
 
-        register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm);
-
-        register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm);
-        register_ioport_read(addr, 4, 1, bmdma_readb, bm);
-
-        iorange_init(&bm->addr_ioport, &bmdma_addr_ioport_ops, addr + 4, 4);
-        ioport_register(&bm->addr_ioport);
-        addr += 8;
+        memory_region_init_io(&bm->extra_io, &piix_bmdma_ops, bm,
+                              "piix-bmdma", 4);
+        memory_region_add_subregion(&d->bmdma_bar, i * 8, &bm->extra_io);
+        memory_region_init_io(&bm->addr_ioport, &bmdma_addr_ioport_ops, bm,
+                              "bmdma", 4);
+        memory_region_add_subregion(&d->bmdma_bar, i * 8 + 4, &bm->addr_ioport);
     }
 }
 
@@ -124,7 +138,7 @@ static void pci_piix_init_ports(PCIIDEState *d) {
         ide_init_ioport(&d->bus[i], port_info[i].iobase, port_info[i].iobase2);
         ide_init2(&d->bus[i], isa_get_irq(port_info[i].isairq));
 
-        bmdma_init(&d->bus[i], &d->bmdma[i]);
+        bmdma_init(&d->bus[i], &d->bmdma[i], d);
         d->bmdma[i].bus = &d->bus[i];
         qemu_add_vm_change_state_handler(d->bus[i].dma->ops->restart_cb,
                                          &d->bmdma[i].dma);
@@ -140,7 +154,9 @@ static int pci_piix_ide_initfn(PCIDevice *dev)
 
     qemu_register_reset(piix3_reset, d);
 
-    pci_register_bar(&d->dev, 4, 0x10, PCI_BASE_ADDRESS_SPACE_IO, bmdma_map);
+    bmdma_setup_bar(d);
+    pci_register_bar_region(&d->dev, 4, PCI_BASE_ADDRESS_SPACE_IO,
+                            &d->bmdma_bar);
 
     vmstate_register(&d->dev.qdev, 0, &vmstate_ide_pci, d);
 
@@ -185,6 +201,22 @@ PCIDevice *pci_piix3_xen_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
     return dev;
 }
 
+static int pci_piix_ide_exitfn(PCIDevice *dev)
+{
+    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);
+    unsigned i;
+
+    for (i = 0; i < 2; ++i) {
+        memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].extra_io);
+        memory_region_destroy(&d->bmdma[i].extra_io);
+        memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].addr_ioport);
+        memory_region_destroy(&d->bmdma[i].addr_ioport);
+    }
+    memory_region_destroy(&d->bmdma_bar);
+
+    return 0;
+}
+
 /* hd_table must contain 4 block drivers */
 /* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */
 PCIDevice *pci_piix3_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
@@ -214,6 +246,7 @@ static PCIDeviceInfo piix_ide_info[] = {
         .qdev.no_user = 1,
         .no_hotplug   = 1,
         .init         = pci_piix_ide_initfn,
+        .exit         = pci_piix_ide_exitfn,
         .vendor_id    = PCI_VENDOR_ID_INTEL,
         .device_id    = PCI_DEVICE_ID_INTEL_82371SB_1,
         .class_id     = PCI_CLASS_STORAGE_IDE,
@@ -231,6 +264,7 @@ static PCIDeviceInfo piix_ide_info[] = {
         .qdev.no_user = 1,
         .no_hotplug   = 1,
         .init         = pci_piix_ide_initfn,
+        .exit         = pci_piix_ide_exitfn,
         .vendor_id    = PCI_VENDOR_ID_INTEL,
         .device_id    = PCI_DEVICE_ID_INTEL_82371AB,
         .class_id     = PCI_CLASS_STORAGE_IDE,
diff --git a/hw/ide/via.c b/hw/ide/via.c
index 3474c37..eb6a409 100644
--- a/hw/ide/via.c
+++ b/hw/ide/via.c
@@ -34,11 +34,16 @@
 
 #include <hw/ide/pci.h>
 
-static uint32_t bmdma_readb(void *opaque, uint32_t addr)
+static uint64_t bmdma_read(void *opaque, target_phys_addr_t addr,
+                           unsigned size)
 {
     BMDMAState *bm = opaque;
     uint32_t val;
 
+    if (size != 1) {
+        return ((uint64_t)1 << (size * 8)) - 1;
+    }
+
     switch (addr & 3) {
     case 0:
         val = bm->cmd;
@@ -56,13 +61,21 @@ static uint32_t bmdma_readb(void *opaque, uint32_t addr)
     return val;
 }
 
-static void bmdma_writeb(void *opaque, uint32_t addr, uint32_t val)
+static void bmdma_write(void *opaque, target_phys_addr_t addr,
+                        uint64_t val, unsigned size)
 {
     BMDMAState *bm = opaque;
+
+    if (size != 1) {
+        return;
+    }
+
 #ifdef DEBUG_IDE
     printf("bmdma: writeb 0x%02x : 0x%02x\n", addr, val);
 #endif
     switch (addr & 3) {
+    case 0:
+        return bmdma_cmd_writeb(bm, val);
     case 2:
         bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06);
         break;
@@ -70,23 +83,25 @@ static void bmdma_writeb(void *opaque, uint32_t addr, uint32_t val)
     }
 }
 
-static void bmdma_map(PCIDevice *pci_dev, int region_num,
-                    pcibus_t addr, pcibus_t size, int type)
+static MemoryRegionOps via_bmdma_ops = {
+    .read = bmdma_read,
+    .write = bmdma_write,
+};
+
+static void bmdma_setup_bar(PCIIDEState *d)
 {
-    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev);
     int i;
 
+    memory_region_init(&d->bmdma_bar, "via-bmdma-container", 16);
     for(i = 0;i < 2; i++) {
         BMDMAState *bm = &d->bmdma[i];
 
-        register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm);
-
-        register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm);
-        register_ioport_read(addr, 4, 1, bmdma_readb, bm);
-
-        iorange_init(&bm->addr_ioport, &bmdma_addr_ioport_ops, addr + 4, 4);
-        ioport_register(&bm->addr_ioport);
-        addr += 8;
+        memory_region_init_io(&bm->extra_io, &via_bmdma_ops, bm,
+                              "via-bmdma", 4);
+        memory_region_add_subregion(&d->bmdma_bar, i * 8, &bm->extra_io);
+        memory_region_init_io(&bm->addr_ioport, &bmdma_addr_ioport_ops, bm,
+                              "bmdma", 4);
+        memory_region_add_subregion(&d->bmdma_bar, i * 8 + 4, &bm->addr_ioport);
     }
 }
 
@@ -147,7 +162,7 @@ static void vt82c686b_init_ports(PCIIDEState *d) {
         ide_init_ioport(&d->bus[i], port_info[i].iobase, port_info[i].iobase2);
         ide_init2(&d->bus[i], isa_get_irq(port_info[i].isairq));
 
-        bmdma_init(&d->bus[i], &d->bmdma[i]);
+        bmdma_init(&d->bus[i], &d->bmdma[i], d);
         d->bmdma[i].bus = &d->bus[i];
         qemu_add_vm_change_state_handler(d->bus[i].dma->ops->restart_cb,
                                          &d->bmdma[i].dma);
@@ -164,8 +179,9 @@ static int vt82c686b_ide_initfn(PCIDevice *dev)
     pci_set_long(pci_conf + PCI_CAPABILITY_LIST, 0x000000c0);
 
     qemu_register_reset(via_reset, d);
-    pci_register_bar(&d->dev, 4, 0x10,
-                           PCI_BASE_ADDRESS_SPACE_IO, bmdma_map);
+    bmdma_setup_bar(d);
+    pci_register_bar_region(&d->dev, 4, PCI_BASE_ADDRESS_SPACE_IO,
+                            &d->bmdma_bar);
 
     vmstate_register(&dev->qdev, 0, &vmstate_ide_pci, d);
 
@@ -174,6 +190,22 @@ static int vt82c686b_ide_initfn(PCIDevice *dev)
     return 0;
 }
 
+static int vt82c686b_ide_exitfn(PCIDevice *dev)
+{
+    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);
+    unsigned i;
+
+    for (i = 0; i < 2; ++i) {
+        memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].extra_io);
+        memory_region_destroy(&d->bmdma[i].extra_io);
+        memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].addr_ioport);
+        memory_region_destroy(&d->bmdma[i].addr_ioport);
+    }
+    memory_region_destroy(&d->bmdma_bar);
+
+    return 0;
+}
+
 void vt82c686b_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
 {
     PCIDevice *dev;
@@ -187,6 +219,7 @@ static PCIDeviceInfo via_ide_info = {
     .qdev.size    = sizeof(PCIIDEState),
     .qdev.no_user = 1,
     .init         = vt82c686b_ide_initfn,
+    .exit         = vt82c686b_ide_exitfn,
     .vendor_id    = PCI_VENDOR_ID_VIA,
     .device_id    = PCI_DEVICE_ID_VIA_IDE,
     .revision     = 0x06,
commit e1a99dbd9c6d435b9850ad98eea47f9b8ad614e6
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:09:10 2011 +0300

    es1370: convert to memory API
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/es1370.c b/hw/es1370.c
index 1ed62b7..4e43c4a 100644
--- a/hw/es1370.c
+++ b/hw/es1370.c
@@ -268,6 +268,7 @@ struct chan {
 typedef struct ES1370State {
     PCIDevice dev;
     QEMUSoundCard card;
+    MemoryRegion io;
     struct chan chan[NB_CHANNELS];
     SWVoiceOut *dac_voice[2];
     SWVoiceIn *adc_voice;
@@ -775,7 +776,6 @@ IO_READ_PROTO (es1370_readl)
     return val;
 }
 
-
 static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel,
                                    int max, int *irq)
 {
@@ -906,23 +906,20 @@ static void es1370_adc_callback (void *opaque, int avail)
     es1370_run_channel (s, ADC_CHANNEL, avail);
 }
 
-static void es1370_map (PCIDevice *pci_dev, int region_num,
-                        pcibus_t addr, pcibus_t size, int type)
-{
-    ES1370State *s = DO_UPCAST (ES1370State, dev, pci_dev);
-
-    (void) region_num;
-    (void) size;
-    (void) type;
-
-    register_ioport_write (addr, 0x40 * 4, 1, es1370_writeb, s);
-    register_ioport_write (addr, 0x40 * 2, 2, es1370_writew, s);
-    register_ioport_write (addr, 0x40, 4, es1370_writel, s);
+static const MemoryRegionPortio es1370_portio[] = {
+    { 0, 0x40 * 4, 1, .write = es1370_writeb, },
+    { 0, 0x40 * 2, 2, .write = es1370_writew, },
+    { 0, 0x40, 4, .write = es1370_writel, },
+    { 0, 0x40 * 4, 1, .read = es1370_readb, },
+    { 0, 0x40 * 2, 2, .read = es1370_readw, },
+    { 0, 0x40, 4, .read = es1370_readl, },
+    PORTIO_END_OF_LIST()
+};
 
-    register_ioport_read (addr, 0x40 * 4, 1, es1370_readb, s);
-    register_ioport_read (addr, 0x40 * 2, 2, es1370_readw, s);
-    register_ioport_read (addr, 0x40, 4, es1370_readl, s);
-}
+static const MemoryRegionOps es1370_io_ops = {
+    .old_portio = es1370_portio,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
 
 static const VMStateDescription vmstate_es1370_channel = {
     .name = "es1370_channel",
@@ -1011,7 +1008,8 @@ static int es1370_initfn (PCIDevice *dev)
     c[PCI_MIN_GNT] = 0x0c;
     c[PCI_MAX_LAT] = 0x80;
 
-    pci_register_bar (&s->dev, 0, 256, PCI_BASE_ADDRESS_SPACE_IO, es1370_map);
+    memory_region_init_io (&s->io, &es1370_io_ops, s, "es1370", 256);
+    pci_register_bar_region (&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io);
     qemu_register_reset (es1370_on_reset, s);
 
     AUD_register_card ("es1370", &s->card);
@@ -1019,6 +1017,14 @@ static int es1370_initfn (PCIDevice *dev)
     return 0;
 }
 
+static int es1370_exitfn(PCIDevice *dev)
+{
+    ES1370State *s = DO_UPCAST (ES1370State, dev, dev);
+
+    memory_region_destroy (&s->io);
+    return 0;
+}
+
 int es1370_init (PCIBus *bus)
 {
     pci_create_simple (bus, -1, "ES1370");
@@ -1031,6 +1037,7 @@ static PCIDeviceInfo es1370_info = {
     .qdev.size    = sizeof (ES1370State),
     .qdev.vmsd    = &vmstate_es1370,
     .init         = es1370_initfn,
+    .exit         = es1370_exitfn,
     .vendor_id    = PCI_VENDOR_ID_ENSONIQ,
     .device_id    = PCI_DEVICE_ID_ENSONIQ_ES1370,
     .class_id     = PCI_CLASS_MULTIMEDIA_AUDIO,
commit 5e6ffddef69837c06cfb1db90fa5e3e54de4c531
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:09:09 2011 +0300

    eepro100: convert to memory API
    
    Note: the existing code aliases the flash BAR into the MMIO bar.  This is
    probably a bug.  This patch does not correct the problem.
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/eepro100.c b/hw/eepro100.c
index 9b6f4a5..04723f3 100644
--- a/hw/eepro100.c
+++ b/hw/eepro100.c
@@ -228,13 +228,14 @@ typedef struct {
     PCIDevice dev;
     /* Hash register (multicast mask array, multiple individual addresses). */
     uint8_t mult[8];
-    int mmio_index;
+    MemoryRegion mmio_bar;
+    MemoryRegion io_bar;
+    MemoryRegion flash_bar;
     NICState *nic;
     NICConf conf;
     uint8_t scb_stat;           /* SCB stat/ack byte */
     uint8_t int_stat;           /* PCI interrupt status */
     /* region must not be saved by nic_save. */
-    uint32_t region1;           /* PCI region 1 address */
     uint16_t mdimem[32];
     eeprom_t *eeprom;
     uint32_t device;            /* device variant */
@@ -1584,147 +1585,36 @@ static void eepro100_write4(EEPRO100State * s, uint32_t addr, uint32_t val)
     }
 }
 
-/*****************************************************************************
- *
- * Port mapped I/O.
- *
- ****************************************************************************/
-
-static uint32_t ioport_read1(void *opaque, uint32_t addr)
-{
-    EEPRO100State *s = opaque;
-#if 0
-    logout("addr=%s\n", regname(addr));
-#endif
-    return eepro100_read1(s, addr - s->region1);
-}
-
-static uint32_t ioport_read2(void *opaque, uint32_t addr)
-{
-    EEPRO100State *s = opaque;
-    return eepro100_read2(s, addr - s->region1);
-}
-
-static uint32_t ioport_read4(void *opaque, uint32_t addr)
-{
-    EEPRO100State *s = opaque;
-    return eepro100_read4(s, addr - s->region1);
-}
-
-static void ioport_write1(void *opaque, uint32_t addr, uint32_t val)
-{
-    EEPRO100State *s = opaque;
-#if 0
-    logout("addr=%s val=0x%02x\n", regname(addr), val);
-#endif
-    eepro100_write1(s, addr - s->region1, val);
-}
-
-static void ioport_write2(void *opaque, uint32_t addr, uint32_t val)
-{
-    EEPRO100State *s = opaque;
-    eepro100_write2(s, addr - s->region1, val);
-}
-
-static void ioport_write4(void *opaque, uint32_t addr, uint32_t val)
-{
-    EEPRO100State *s = opaque;
-    eepro100_write4(s, addr - s->region1, val);
-}
-
-/***********************************************************/
-/* PCI EEPRO100 definitions */
-
-static void pci_map(PCIDevice * pci_dev, int region_num,
-                    pcibus_t addr, pcibus_t size, int type)
-{
-    EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
-
-    TRACE(OTHER, logout("region %d, addr=0x%08"FMT_PCIBUS", "
-          "size=0x%08"FMT_PCIBUS", type=%d\n",
-          region_num, addr, size, type));
-
-    assert(region_num == 1);
-    register_ioport_write(addr, size, 1, ioport_write1, s);
-    register_ioport_read(addr, size, 1, ioport_read1, s);
-    register_ioport_write(addr, size, 2, ioport_write2, s);
-    register_ioport_read(addr, size, 2, ioport_read2, s);
-    register_ioport_write(addr, size, 4, ioport_write4, s);
-    register_ioport_read(addr, size, 4, ioport_read4, s);
-
-    s->region1 = addr;
-}
-
-/*****************************************************************************
- *
- * Memory mapped I/O.
- *
- ****************************************************************************/
-
-static void pci_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    EEPRO100State *s = opaque;
-#if 0
-    logout("addr=%s val=0x%02x\n", regname(addr), val);
-#endif
-    eepro100_write1(s, addr, val);
-}
-
-static void pci_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+static uint64_t eepro100_read(void *opaque, target_phys_addr_t addr,
+                              unsigned size)
 {
     EEPRO100State *s = opaque;
-#if 0
-    logout("addr=%s val=0x%02x\n", regname(addr), val);
-#endif
-    eepro100_write2(s, addr, val);
-}
 
-static void pci_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    EEPRO100State *s = opaque;
-#if 0
-    logout("addr=%s val=0x%02x\n", regname(addr), val);
-#endif
-    eepro100_write4(s, addr, val);
-}
-
-static uint32_t pci_mmio_readb(void *opaque, target_phys_addr_t addr)
-{
-    EEPRO100State *s = opaque;
-#if 0
-    logout("addr=%s\n", regname(addr));
-#endif
-    return eepro100_read1(s, addr);
+    switch (size) {
+    case 1: return eepro100_read1(s, addr);
+    case 2: return eepro100_read2(s, addr);
+    case 4: return eepro100_read4(s, addr);
+    default: abort();
+    }
 }
 
-static uint32_t pci_mmio_readw(void *opaque, target_phys_addr_t addr)
+static void eepro100_write(void *opaque, target_phys_addr_t addr,
+                           uint64_t data, unsigned size)
 {
     EEPRO100State *s = opaque;
-#if 0
-    logout("addr=%s\n", regname(addr));
-#endif
-    return eepro100_read2(s, addr);
-}
 
-static uint32_t pci_mmio_readl(void *opaque, target_phys_addr_t addr)
-{
-    EEPRO100State *s = opaque;
-#if 0
-    logout("addr=%s\n", regname(addr));
-#endif
-    return eepro100_read4(s, addr);
+    switch (size) {
+    case 1: return eepro100_write1(s, addr, data);
+    case 2: return eepro100_write2(s, addr, data);
+    case 4: return eepro100_write4(s, addr, data);
+    default: abort();
+    }
 }
 
-static CPUWriteMemoryFunc * const pci_mmio_write[] = {
-    pci_mmio_writeb,
-    pci_mmio_writew,
-    pci_mmio_writel
-};
-
-static CPUReadMemoryFunc * const pci_mmio_read[] = {
-    pci_mmio_readb,
-    pci_mmio_readw,
-    pci_mmio_readl
+static const MemoryRegionOps eepro100_ops = {
+    .read = eepro100_read,
+    .write = eepro100_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
 static int nic_can_receive(VLANClientState *nc)
@@ -1953,7 +1843,9 @@ static int pci_nic_uninit(PCIDevice *pci_dev)
 {
     EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
 
-    cpu_unregister_io_memory(s->mmio_index);
+    memory_region_destroy(&s->mmio_bar);
+    memory_region_destroy(&s->io_bar);
+    memory_region_destroy(&s->flash_bar);
     vmstate_unregister(&pci_dev->qdev, s->vmstate, s);
     eeprom93xx_free(&pci_dev->qdev, s->eeprom);
     qemu_del_vlan_client(&s->nic->nc);
@@ -1985,20 +1877,20 @@ static int e100_nic_init(PCIDevice *pci_dev)
     s->eeprom = eeprom93xx_new(&pci_dev->qdev, EEPROM_SIZE);
 
     /* Handler for memory-mapped I/O */
-    s->mmio_index =
-        cpu_register_io_memory(pci_mmio_read, pci_mmio_write, s,
-                               DEVICE_LITTLE_ENDIAN);
-
-    pci_register_bar_simple(&s->dev, 0, PCI_MEM_SIZE,
-                            PCI_BASE_ADDRESS_MEM_PREFETCH, s->mmio_index);
-
-    pci_register_bar(&s->dev, 1, PCI_IO_SIZE, PCI_BASE_ADDRESS_SPACE_IO,
-                           pci_map);
-    pci_register_bar_simple(&s->dev, 2, PCI_FLASH_SIZE, 0, s->mmio_index);
+    memory_region_init_io(&s->mmio_bar, &eepro100_ops, s, "eepro100-mmio",
+                          PCI_MEM_SIZE);
+    pci_register_bar_region(&s->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH,
+                            &s->mmio_bar);
+    memory_region_init_io(&s->io_bar, &eepro100_ops, s, "eepro100-io",
+                          PCI_IO_SIZE);
+    pci_register_bar_region(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->io_bar);
+    /* FIXME: flash aliases to mmio?! */
+    memory_region_init_io(&s->flash_bar, &eepro100_ops, s, "eepro100-flash",
+                          PCI_FLASH_SIZE);
+    pci_register_bar_region(&s->dev, 2, 0, &s->flash_bar);
 
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
     logout("macaddr: %s\n", nic_dump(&s->conf.macaddr.a[0], 6));
-    assert(s->region1 == 0);
 
     nic_reset(s);
 
commit ad00a9b9d4562496b9b89787ca8ac6d52419ba7c
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:09:08 2011 +0300

    e1000: convert to memory API
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/e1000.c b/hw/e1000.c
index 96d84f9..dfc082b 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -82,7 +82,8 @@ typedef struct E1000State_st {
     PCIDevice dev;
     NICState *nic;
     NICConf conf;
-    int mmio_index;
+    MemoryRegion mmio;
+    MemoryRegion io;
 
     uint32_t mac_reg[0x8000];
     uint16_t phy_reg[0x20];
@@ -151,14 +152,6 @@ static const char phy_regcap[0x20] = {
 };
 
 static void
-ioport_map(PCIDevice *pci_dev, int region_num, pcibus_t addr,
-           pcibus_t size, int type)
-{
-    DBGOUT(IO, "e1000_ioport_map addr=0x%04"FMT_PCIBUS
-           " size=0x%08"FMT_PCIBUS"\n", addr, size);
-}
-
-static void
 set_interrupt_cause(E1000State *s, int index, uint32_t val)
 {
     if (val)
@@ -905,7 +898,8 @@ static void (*macreg_writeops[])(E1000State *, int, uint32_t) = {
 enum { NWRITEOPS = ARRAY_SIZE(macreg_writeops) };
 
 static void
-e1000_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+e1000_mmio_write(void *opaque, target_phys_addr_t addr, uint64_t val,
+                 unsigned size)
 {
     E1000State *s = opaque;
     unsigned int index = (addr & 0x1ffff) >> 2;
@@ -913,31 +907,15 @@ e1000_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
     if (index < NWRITEOPS && macreg_writeops[index]) {
         macreg_writeops[index](s, index, val);
     } else if (index < NREADOPS && macreg_readops[index]) {
-        DBGOUT(MMIO, "e1000_mmio_writel RO %x: 0x%04x\n", index<<2, val);
+        DBGOUT(MMIO, "e1000_mmio_writel RO %x: 0x%04"PRIx64"\n", index<<2, val);
     } else {
-        DBGOUT(UNKNOWN, "MMIO unknown write addr=0x%08x,val=0x%08x\n",
+        DBGOUT(UNKNOWN, "MMIO unknown write addr=0x%08x,val=0x%08"PRIx64"\n",
                index<<2, val);
     }
 }
 
-static void
-e1000_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    // emulate hw without byte enables: no RMW
-    e1000_mmio_writel(opaque, addr & ~3,
-                      (val & 0xffff) << (8*(addr & 3)));
-}
-
-static void
-e1000_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    // emulate hw without byte enables: no RMW
-    e1000_mmio_writel(opaque, addr & ~3,
-                      (val & 0xff) << (8*(addr & 3)));
-}
-
-static uint32_t
-e1000_mmio_readl(void *opaque, target_phys_addr_t addr)
+static uint64_t
+e1000_mmio_read(void *opaque, target_phys_addr_t addr, unsigned size)
 {
     E1000State *s = opaque;
     unsigned int index = (addr & 0x1ffff) >> 2;
@@ -950,20 +928,39 @@ e1000_mmio_readl(void *opaque, target_phys_addr_t addr)
     return 0;
 }
 
-static uint32_t
-e1000_mmio_readb(void *opaque, target_phys_addr_t addr)
+static const MemoryRegionOps e1000_mmio_ops = {
+    .read = e1000_mmio_read,
+    .write = e1000_mmio_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static uint64_t e1000_io_read(void *opaque, target_phys_addr_t addr,
+                              unsigned size)
 {
-    return ((e1000_mmio_readl(opaque, addr & ~3)) >>
-            (8 * (addr & 3))) & 0xff;
+    E1000State *s = opaque;
+
+    (void)s;
+    return 0;
 }
 
-static uint32_t
-e1000_mmio_readw(void *opaque, target_phys_addr_t addr)
+static void e1000_io_write(void *opaque, target_phys_addr_t addr,
+                           uint64_t val, unsigned size)
 {
-    return ((e1000_mmio_readl(opaque, addr & ~3)) >>
-            (8 * (addr & 3))) & 0xffff;
+    E1000State *s = opaque;
+
+    (void)s;
 }
 
+static const MemoryRegionOps e1000_io_ops = {
+    .read = e1000_io_read,
+    .write = e1000_io_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
 static bool is_version_1(void *opaque, int version_id)
 {
     return version_id == 1;
@@ -1083,36 +1080,22 @@ static const uint32_t mac_reg_init[] = {
 
 /* PCI interface */
 
-static CPUWriteMemoryFunc * const e1000_mmio_write[] = {
-    e1000_mmio_writeb,	e1000_mmio_writew,	e1000_mmio_writel
-};
-
-static CPUReadMemoryFunc * const e1000_mmio_read[] = {
-    e1000_mmio_readb,	e1000_mmio_readw,	e1000_mmio_readl
-};
-
 static void
-e1000_mmio_map(PCIDevice *pci_dev, int region_num,
-                pcibus_t addr, pcibus_t size, int type)
+e1000_mmio_setup(E1000State *d)
 {
-    E1000State *d = DO_UPCAST(E1000State, dev, pci_dev);
     int i;
     const uint32_t excluded_regs[] = {
         E1000_MDIC, E1000_ICR, E1000_ICS, E1000_IMS,
         E1000_IMC, E1000_TCTL, E1000_TDT, PNPMMIO_SIZE
     };
 
-
-    DBGOUT(MMIO, "e1000_mmio_map addr=0x%08"FMT_PCIBUS" 0x%08"FMT_PCIBUS"\n",
-           addr, size);
-
-    cpu_register_physical_memory(addr, PNPMMIO_SIZE, d->mmio_index);
-    qemu_register_coalesced_mmio(addr, excluded_regs[0]);
-
+    memory_region_init_io(&d->mmio, &e1000_mmio_ops, d, "e1000-mmio",
+                          PNPMMIO_SIZE);
+    memory_region_add_coalescing(&d->mmio, 0, excluded_regs[0]);
     for (i = 0; excluded_regs[i] != PNPMMIO_SIZE; i++)
-        qemu_register_coalesced_mmio(addr + excluded_regs[i] + 4,
-                                     excluded_regs[i + 1] -
-                                     excluded_regs[i] - 4);
+        memory_region_add_coalescing(&d->mmio, excluded_regs[i] + 4,
+                                     excluded_regs[i+1] - excluded_regs[i] - 4);
+    memory_region_init_io(&d->io, &e1000_io_ops, d, "e1000-io", IOPORT_SIZE);
 }
 
 static void
@@ -1128,7 +1111,8 @@ pci_e1000_uninit(PCIDevice *dev)
 {
     E1000State *d = DO_UPCAST(E1000State, dev, dev);
 
-    cpu_unregister_io_memory(d->mmio_index);
+    memory_region_destroy(&d->mmio);
+    memory_region_destroy(&d->io);
     qemu_del_vlan_client(&d->nic->nc);
     return 0;
 }
@@ -1172,14 +1156,12 @@ static int pci_e1000_init(PCIDevice *pci_dev)
     /* TODO: RST# value should be 0 if programmable, PCI spec 6.2.4 */
     pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0
 
-    d->mmio_index = cpu_register_io_memory(e1000_mmio_read,
-            e1000_mmio_write, d, DEVICE_LITTLE_ENDIAN);
+    e1000_mmio_setup(d);
 
-    pci_register_bar(&d->dev, 0, PNPMMIO_SIZE,
-                           PCI_BASE_ADDRESS_SPACE_MEMORY, e1000_mmio_map);
+    pci_register_bar_region(&d->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
+                            &d->mmio);
 
-    pci_register_bar(&d->dev, 1, IOPORT_SIZE,
-                           PCI_BASE_ADDRESS_SPACE_IO, ioport_map);
+    pci_register_bar_region(&d->dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &d->io);
 
     memmove(d->eeprom_data, e1000_eeprom_template,
         sizeof e1000_eeprom_template);
commit 83c406d986a5dfadf303da8c3dc6944eda3c4e4d
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:09:07 2011 +0300

    ac97: convert to memory API
    
    fixes BAR sizing as well.
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/ac97.c b/hw/ac97.c
index 0b59896..52f0f0d 100644
--- a/hw/ac97.c
+++ b/hw/ac97.c
@@ -160,8 +160,9 @@ typedef struct AC97LinkState {
     SWVoiceIn *voice_mc;
     int invalid_freq[3];
     uint8_t silence[128];
-    uint32_t base[2];
     int bup_flag;
+    MemoryRegion io_nam;
+    MemoryRegion io_nabm;
 } AC97LinkState;
 
 enum {
@@ -583,7 +584,7 @@ static uint32_t nam_readw (void *opaque, uint32_t addr)
 {
     AC97LinkState *s = opaque;
     uint32_t val = ~0U;
-    uint32_t index = addr - s->base[0];
+    uint32_t index = addr;
     s->cas = 0;
     val = mixer_load (s, index);
     return val;
@@ -611,7 +612,7 @@ static void nam_writeb (void *opaque, uint32_t addr, uint32_t val)
 static void nam_writew (void *opaque, uint32_t addr, uint32_t val)
 {
     AC97LinkState *s = opaque;
-    uint32_t index = addr - s->base[0];
+    uint32_t index = addr;
     s->cas = 0;
     switch (index) {
     case AC97_Reset:
@@ -714,7 +715,7 @@ static uint32_t nabm_readb (void *opaque, uint32_t addr)
 {
     AC97LinkState *s = opaque;
     AC97BusMasterRegs *r = NULL;
-    uint32_t index = addr - s->base[1];
+    uint32_t index = addr;
     uint32_t val = ~0U;
 
     switch (index) {
@@ -769,7 +770,7 @@ static uint32_t nabm_readw (void *opaque, uint32_t addr)
 {
     AC97LinkState *s = opaque;
     AC97BusMasterRegs *r = NULL;
-    uint32_t index = addr - s->base[1];
+    uint32_t index = addr;
     uint32_t val = ~0U;
 
     switch (index) {
@@ -798,7 +799,7 @@ static uint32_t nabm_readl (void *opaque, uint32_t addr)
 {
     AC97LinkState *s = opaque;
     AC97BusMasterRegs *r = NULL;
-    uint32_t index = addr - s->base[1];
+    uint32_t index = addr;
     uint32_t val = ~0U;
 
     switch (index) {
@@ -848,7 +849,7 @@ static void nabm_writeb (void *opaque, uint32_t addr, uint32_t val)
 {
     AC97LinkState *s = opaque;
     AC97BusMasterRegs *r = NULL;
-    uint32_t index = addr - s->base[1];
+    uint32_t index = addr;
     switch (index) {
     case PI_LVI:
     case PO_LVI:
@@ -904,7 +905,7 @@ static void nabm_writew (void *opaque, uint32_t addr, uint32_t val)
 {
     AC97LinkState *s = opaque;
     AC97BusMasterRegs *r = NULL;
-    uint32_t index = addr - s->base[1];
+    uint32_t index = addr;
     switch (index) {
     case PI_SR:
     case PO_SR:
@@ -924,7 +925,7 @@ static void nabm_writel (void *opaque, uint32_t addr, uint32_t val)
 {
     AC97LinkState *s = opaque;
     AC97BusMasterRegs *r = NULL;
-    uint32_t index = addr - s->base[1];
+    uint32_t index = addr;
     switch (index) {
     case PI_BDBAR:
     case PO_BDBAR:
@@ -1230,31 +1231,33 @@ static const VMStateDescription vmstate_ac97 = {
     }
 };
 
-static void ac97_map (PCIDevice *pci_dev, int region_num,
-                      pcibus_t addr, pcibus_t size, int type)
-{
-    AC97LinkState *s = DO_UPCAST (AC97LinkState, dev, pci_dev);
-    PCIDevice *d = &s->dev;
-
-    if (!region_num) {
-        s->base[0] = addr;
-        register_ioport_read (addr, 256 * 1, 1, nam_readb, d);
-        register_ioport_read (addr, 256 * 2, 2, nam_readw, d);
-        register_ioport_read (addr, 256 * 4, 4, nam_readl, d);
-        register_ioport_write (addr, 256 * 1, 1, nam_writeb, d);
-        register_ioport_write (addr, 256 * 2, 2, nam_writew, d);
-        register_ioport_write (addr, 256 * 4, 4, nam_writel, d);
-    }
-    else {
-        s->base[1] = addr;
-        register_ioport_read (addr, 64 * 1, 1, nabm_readb, d);
-        register_ioport_read (addr, 64 * 2, 2, nabm_readw, d);
-        register_ioport_read (addr, 64 * 4, 4, nabm_readl, d);
-        register_ioport_write (addr, 64 * 1, 1, nabm_writeb, d);
-        register_ioport_write (addr, 64 * 2, 2, nabm_writew, d);
-        register_ioport_write (addr, 64 * 4, 4, nabm_writel, d);
-    }
-}
+static const MemoryRegionPortio nam_portio[] = {
+    { 0, 256 * 1, 1, .read = nam_readb, },
+    { 0, 256 * 2, 2, .read = nam_readw, },
+    { 0, 256 * 4, 4, .read = nam_readl, },
+    { 0, 256 * 1, 1, .write = nam_writeb, },
+    { 0, 256 * 2, 2, .write = nam_writew, },
+    { 0, 256 * 4, 4, .write = nam_writel, },
+    PORTIO_END_OF_LIST(),
+};
+
+static const MemoryRegionOps ac97_io_nam_ops = {
+    .old_portio = nam_portio,
+};
+
+static const MemoryRegionPortio nabm_portio[] = {
+    { 0, 64 * 1, 1, .read = nabm_readb, },
+    { 0, 64 * 2, 2, .read = nabm_readw, },
+    { 0, 64 * 4, 4, .read = nabm_readl, },
+    { 0, 64 * 1, 1, .write = nabm_writeb, },
+    { 0, 64 * 2, 2, .write = nabm_writew, },
+    { 0, 64 * 4, 4, .write = nabm_writel, },
+    PORTIO_END_OF_LIST()
+};
+
+static const MemoryRegionOps ac97_io_nabm_ops = {
+    .old_portio = nabm_portio,
+};
 
 static void ac97_on_reset (void *opaque)
 {
@@ -1311,15 +1314,26 @@ static int ac97_initfn (PCIDevice *dev)
     /* TODO: RST# value should be 0. */
     c[PCI_INTERRUPT_PIN] = 0x01;      /* intr_pn interrupt pin ro */
 
-    pci_register_bar (&s->dev, 0, 256 * 4, PCI_BASE_ADDRESS_SPACE_IO,
-                      ac97_map);
-    pci_register_bar (&s->dev, 1, 64 * 4, PCI_BASE_ADDRESS_SPACE_IO, ac97_map);
+    memory_region_init_io (&s->io_nam, &ac97_io_nam_ops, s, "ac97-nam", 1024);
+    memory_region_init_io (&s->io_nabm, &ac97_io_nabm_ops, s, "ac97-nabm", 256);
+    pci_register_bar_region (&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_nam);
+    pci_register_bar_region (&s->dev, 1, PCI_BASE_ADDRESS_SPACE_IO,
+                             &s->io_nabm);
     qemu_register_reset (ac97_on_reset, s);
     AUD_register_card ("ac97", &s->card);
     ac97_on_reset (s);
     return 0;
 }
 
+static int ac97_exitfn (PCIDevice *dev)
+{
+    AC97LinkState *s = DO_UPCAST (AC97LinkState, dev, dev);
+
+    memory_region_destroy (&s->io_nam);
+    memory_region_destroy (&s->io_nabm);
+    return 0;
+}
+
 int ac97_init (PCIBus *bus)
 {
     pci_create_simple (bus, -1, "AC97");
@@ -1332,6 +1346,7 @@ static PCIDeviceInfo ac97_info = {
     .qdev.size    = sizeof (AC97LinkState),
     .qdev.vmsd    = &vmstate_ac97,
     .init         = ac97_initfn,
+    .exit         = ac97_exitfn,
     .vendor_id    = PCI_VENDOR_ID_INTEL,
     .device_id    = PCI_DEVICE_ID_INTEL_82801AA_5,
     .revision     = 0x01,
commit bd80f3fc006011b6a3d3d78c15b81c035ed8086d
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:09:06 2011 +0300

    rtl8139: convert to memory API
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 5214b8c..f07af35 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -474,7 +474,6 @@ typedef struct RTL8139State {
 
     NICState *nic;
     NICConf conf;
-    int rtl8139_mmio_io_addr;
 
     /* C ring mode */
     uint32_t   currTxDesc;
@@ -506,6 +505,9 @@ typedef struct RTL8139State {
     QEMUTimer *timer;
     int64_t TimerExpire;
 
+    MemoryRegion bar_io;
+    MemoryRegion bar_mem;
+
     /* Support migration to/from old versions */
     int rtl8139_mmio_io_addr_dummy;
 } RTL8139State;
@@ -3283,7 +3285,7 @@ static void rtl8139_pre_save(void *opaque)
     rtl8139_set_next_tctr_time(s, current_time);
     s->TCTR = muldiv64(current_time - s->TCTR_base, PCI_FREQUENCY,
                        get_ticks_per_sec());
-    s->rtl8139_mmio_io_addr_dummy = s->rtl8139_mmio_io_addr;
+    s->rtl8139_mmio_io_addr_dummy = 0;
 }
 
 static const VMStateDescription vmstate_rtl8139 = {
@@ -3379,31 +3381,35 @@ static const VMStateDescription vmstate_rtl8139 = {
 /***********************************************************/
 /* PCI RTL8139 definitions */
 
-static void rtl8139_ioport_map(PCIDevice *pci_dev, int region_num,
-                       pcibus_t addr, pcibus_t size, int type)
-{
-    RTL8139State *s = DO_UPCAST(RTL8139State, dev, pci_dev);
-
-    register_ioport_write(addr, 0x100, 1, rtl8139_ioport_writeb, s);
-    register_ioport_read( addr, 0x100, 1, rtl8139_ioport_readb,  s);
-
-    register_ioport_write(addr, 0x100, 2, rtl8139_ioport_writew, s);
-    register_ioport_read( addr, 0x100, 2, rtl8139_ioport_readw,  s);
-
-    register_ioport_write(addr, 0x100, 4, rtl8139_ioport_writel, s);
-    register_ioport_read( addr, 0x100, 4, rtl8139_ioport_readl,  s);
-}
+static const MemoryRegionPortio rtl8139_portio[] = {
+    { 0, 0x100, 1, .read = rtl8139_ioport_readb, },
+    { 0, 0x100, 1, .write = rtl8139_ioport_writeb, },
+    { 0, 0x100, 2, .read = rtl8139_ioport_readw, },
+    { 0, 0x100, 2, .write = rtl8139_ioport_writew, },
+    { 0, 0x100, 4, .read = rtl8139_ioport_readl, },
+    { 0, 0x100, 4, .write = rtl8139_ioport_writel, },
+    PORTIO_END_OF_LIST()
+};
 
-static CPUReadMemoryFunc * const rtl8139_mmio_read[3] = {
-    rtl8139_mmio_readb,
-    rtl8139_mmio_readw,
-    rtl8139_mmio_readl,
+static const MemoryRegionOps rtl8139_io_ops = {
+    .old_portio = rtl8139_portio,
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const rtl8139_mmio_write[3] = {
-    rtl8139_mmio_writeb,
-    rtl8139_mmio_writew,
-    rtl8139_mmio_writel,
+static const MemoryRegionOps rtl8139_mmio_ops = {
+    .old_mmio = {
+        .read = {
+            rtl8139_mmio_readb,
+            rtl8139_mmio_readw,
+            rtl8139_mmio_readl,
+        },
+        .write = {
+            rtl8139_mmio_writeb,
+            rtl8139_mmio_writew,
+            rtl8139_mmio_writel,
+        },
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
 static void rtl8139_timer(void *opaque)
@@ -3432,7 +3438,8 @@ static int pci_rtl8139_uninit(PCIDevice *dev)
 {
     RTL8139State *s = DO_UPCAST(RTL8139State, dev, dev);
 
-    cpu_unregister_io_memory(s->rtl8139_mmio_io_addr);
+    memory_region_destroy(&s->bar_io);
+    memory_region_destroy(&s->bar_mem);
     if (s->cplus_txbuffer) {
         qemu_free(s->cplus_txbuffer);
         s->cplus_txbuffer = NULL;
@@ -3462,15 +3469,12 @@ static int pci_rtl8139_init(PCIDevice *dev)
      * list bit in status register, and offset 0xdc seems unused. */
     pci_conf[PCI_CAPABILITY_LIST] = 0xdc;
 
-    /* I/O handler for memory-mapped I/O */
-    s->rtl8139_mmio_io_addr =
-        cpu_register_io_memory(rtl8139_mmio_read, rtl8139_mmio_write, s,
-                               DEVICE_LITTLE_ENDIAN);
-
-    pci_register_bar(&s->dev, 0, 0x100,
-                           PCI_BASE_ADDRESS_SPACE_IO,  rtl8139_ioport_map);
-
-    pci_register_bar_simple(&s->dev, 1, 0x100, 0, s->rtl8139_mmio_io_addr);
+    memory_region_init_io(&s->bar_io, &rtl8139_io_ops, s, "rtl8139", 0x100);
+    memory_region_init_io(&s->bar_mem, &rtl8139_mmio_ops, s, "rtl8139", 0x100);
+    pci_register_bar_region(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO,
+                            &s->bar_io);
+    pci_register_bar_region(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY,
+                            &s->bar_mem);
 
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
 
commit 5968eca3a3c2c92bf2b1318e7d4f978eb1226dd5
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:09:05 2011 +0300

    pci: allow I/O BARs to be registered with pci_register_bar_region()
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/pci.c b/hw/pci.c
index 0857644..c00cbf8 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -271,7 +271,8 @@ void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
     qbus_create_inplace(&bus->qbus, &pci_bus_info, parent, name);
     assert(PCI_FUNC(devfn_min) == 0);
     bus->devfn_min = devfn_min;
-    bus->address_space = address_space_mem;
+    bus->address_space_mem = address_space_mem;
+    bus->address_space_io = address_space_io;
 
     /* host bridge */
     QLIST_INIT(&bus->child);
@@ -847,12 +848,11 @@ static void pci_unregister_io_regions(PCIDevice *pci_dev)
         r = &pci_dev->io_regions[i];
         if (!r->size || r->addr == PCI_BAR_UNMAPPED)
             continue;
-        if (r->type == PCI_BASE_ADDRESS_SPACE_IO) {
-            isa_unassign_ioport(r->addr, r->filtered_size);
+        if (r->memory) {
+            memory_region_del_subregion(r->address_space, r->memory);
         } else {
-            if (r->memory) {
-                memory_region_del_subregion(pci_dev->bus->address_space,
-                                            r->memory);
+            if (r->type == PCI_BASE_ADDRESS_SPACE_IO) {
+                isa_unassign_ioport(r->addr, r->filtered_size);
             } else {
                 cpu_register_physical_memory(pci_to_cpu_addr(pci_dev->bus,
                                                              r->addr),
@@ -934,9 +934,11 @@ static void pci_simple_bar_mapfunc_region(PCIDevice *pci_dev, int region_num,
                                           pcibus_t addr, pcibus_t size,
                                           int type)
 {
-    memory_region_add_subregion_overlap(pci_dev->bus->address_space,
+    PCIIORegion *r = &pci_dev->io_regions[region_num];
+
+    memory_region_add_subregion_overlap(r->address_space,
                                         addr,
-                                        pci_dev->io_regions[region_num].memory,
+                                        r->memory,
                                         1);
 }
 
@@ -953,9 +955,13 @@ void pci_register_bar_region(PCIDevice *pci_dev, int region_num,
                              uint8_t attr, MemoryRegion *memory)
 {
     pci_register_bar(pci_dev, region_num, memory_region_size(memory),
-                     PCI_BASE_ADDRESS_SPACE_MEMORY | attr,
+                     attr,
                      pci_simple_bar_mapfunc_region);
     pci_dev->io_regions[region_num].memory = memory;
+    pci_dev->io_regions[region_num].address_space
+        = attr & PCI_BASE_ADDRESS_SPACE_IO
+        ? pci_dev->bus->address_space_io
+        : pci_dev->bus->address_space_mem;
 }
 
 pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num)
@@ -1090,7 +1096,9 @@ static void pci_update_mappings(PCIDevice *d)
 
         /* now do the real mapping */
         if (r->addr != PCI_BAR_UNMAPPED) {
-            if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
+            if (r->memory) {
+                memory_region_del_subregion(r->address_space, r->memory);
+            } else if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
                 int class;
                 /* NOTE: specific hack for IDE in PC case:
                    only one byte must be mapped. */
@@ -1101,16 +1109,11 @@ static void pci_update_mappings(PCIDevice *d)
                     isa_unassign_ioport(r->addr, r->filtered_size);
                 }
             } else {
-                if (r->memory) {
-                    memory_region_del_subregion(d->bus->address_space,
-                                                r->memory);
-                } else {
-                    cpu_register_physical_memory(pci_to_cpu_addr(d->bus,
-                                                                 r->addr),
-                                                 r->filtered_size,
-                                                 IO_MEM_UNASSIGNED);
-                    qemu_unregister_coalesced_mmio(r->addr, r->filtered_size);
-                }
+                cpu_register_physical_memory(pci_to_cpu_addr(d->bus,
+                                                             r->addr),
+                                             r->filtered_size,
+                                             IO_MEM_UNASSIGNED);
+                qemu_unregister_coalesced_mmio(r->addr, r->filtered_size);
             }
         }
         r->addr = new_addr;
diff --git a/hw/pci.h b/hw/pci.h
index 45b30fa..928e96c 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -95,6 +95,7 @@ typedef struct PCIIORegion {
     PCIMapIORegionFunc *map_func;
     ram_addr_t ram_addr;
     MemoryRegion *memory;
+    MemoryRegion *address_space;
 } PCIIORegion;
 
 #define PCI_ROM_SLOT 6
diff --git a/hw/pci_internals.h b/hw/pci_internals.h
index c3a463a..c7fd23d 100644
--- a/hw/pci_internals.h
+++ b/hw/pci_internals.h
@@ -25,7 +25,8 @@ struct PCIBus {
     PCIDevice *devices[PCI_SLOT_MAX * PCI_FUNC_MAX];
     PCIDevice *parent_dev;
     target_phys_addr_t mem_base;
-    MemoryRegion *address_space;
+    MemoryRegion *address_space_mem;
+    MemoryRegion *address_space_io;
 
     QLIST_HEAD(, PCIBus) child; /* this will be replaced by qdev later */
     QLIST_ENTRY(PCIBus) sibling;/* this will be replaced by qdev later */
commit aee97b840fd0362594c954af750491fafad66a3d
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:09:04 2011 +0300

    pci: pass I/O address space to new PCI bus
    
    This lets us register BARs in the I/O address space.
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/apb_pci.c b/hw/apb_pci.c
index 8b9939c..1638226 100644
--- a/hw/apb_pci.c
+++ b/hw/apb_pci.c
@@ -348,6 +348,7 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base,
     d->bus = pci_register_bus(&d->busdev.qdev, "pci",
                                          pci_apb_set_irq, pci_pbm_map_irq, d,
                                          get_system_memory(),
+                                         get_system_io(),
                                          0, 32);
     pci_bus_set_mem_base(d->bus, mem_base);
 
diff --git a/hw/bonito.c b/hw/bonito.c
index 5f62dda..8708e95 100644
--- a/hw/bonito.c
+++ b/hw/bonito.c
@@ -775,6 +775,7 @@ PCIBus *bonito_init(qemu_irq *pic)
     pcihost = FROM_SYSBUS(BonitoState, sysbus_from_qdev(dev));
     b = pci_register_bus(&pcihost->busdev.qdev, "pci", pci_bonito_set_irq,
                          pci_bonito_map_irq, pic, get_system_memory(),
+                         get_system_io(),
                          0x28, 32);
     pcihost->bus = b;
     qdev_init_nofail(dev);
diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c
index da67cf9..9a823e1 100644
--- a/hw/grackle_pci.c
+++ b/hw/grackle_pci.c
@@ -62,7 +62,8 @@ static void pci_grackle_reset(void *opaque)
 }
 
 PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic,
-                         MemoryRegion *address_space)
+                         MemoryRegion *address_space_mem,
+                         MemoryRegion *address_space_io)
 {
     DeviceState *dev;
     SysBusDevice *s;
@@ -75,7 +76,10 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic,
     d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
                                          pci_grackle_set_irq,
                                          pci_grackle_map_irq,
-                                         pic, address_space, 0, 4);
+                                         pic,
+                                         address_space_mem,
+                                         address_space_io,
+                                         0, 4);
 
     pci_create_simple(d->host_state.bus, 0, "grackle");
 
diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c
index 65e63dd..d541558 100644
--- a/hw/gt64xxx.c
+++ b/hw/gt64xxx.c
@@ -1093,7 +1093,9 @@ PCIBus *gt64120_register(qemu_irq *pic)
     d = FROM_SYSBUS(GT64120State, s);
     d->pci.bus = pci_register_bus(&d->busdev.qdev, "pci",
                                   gt64120_pci_set_irq, gt64120_pci_map_irq,
-                                  pic, get_system_memory(),
+                                  pic,
+                                  get_system_memory(),
+                                  get_system_io(),
                                   PCI_DEVFN(18, 0), 4);
     d->ISD_handle = cpu_register_io_memory(gt64120_read, gt64120_write, d,
                                            DEVICE_NATIVE_ENDIAN);
diff --git a/hw/pc.h b/hw/pc.h
index a2de0fe..ec34db7 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -179,7 +179,9 @@ struct PCII440FXState;
 typedef struct PCII440FXState PCII440FXState;
 
 PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix_devfn,
-                    qemu_irq *pic, MemoryRegion *address_space,
+                    qemu_irq *pic,
+                    MemoryRegion *address_space_mem,
+                    MemoryRegion *address_space_io,
                     ram_addr_t ram_size);
 void i440fx_init_memory_mappings(PCII440FXState *d);
 
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index c0a2abe..7dd5008 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -69,6 +69,7 @@ static void ioapic_init(IsaIrqState *isa_irq_state)
 
 /* PC hardware initialisation */
 static void pc_init1(MemoryRegion *system_memory,
+                     MemoryRegion *system_io,
                      ram_addr_t ram_size,
                      const char *boot_device,
                      const char *kernel_filename,
@@ -129,7 +130,7 @@ static void pc_init1(MemoryRegion *system_memory,
 
     if (pci_enabled) {
         pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq,
-                              system_memory, ram_size);
+                              system_memory, system_io, ram_size);
     } else {
         pci_bus = NULL;
         i440fx_state = NULL;
@@ -218,6 +219,7 @@ static void pc_init_pci(ram_addr_t ram_size,
                         const char *cpu_model)
 {
     pc_init1(get_system_memory(),
+             get_system_io(),
              ram_size, boot_device,
              kernel_filename, kernel_cmdline,
              initrd_filename, cpu_model, 1, 1);
@@ -231,6 +233,7 @@ static void pc_init_pci_no_kvmclock(ram_addr_t ram_size,
                                     const char *cpu_model)
 {
     pc_init1(get_system_memory(),
+             get_system_io(),
              ram_size, boot_device,
              kernel_filename, kernel_cmdline,
              initrd_filename, cpu_model, 1, 0);
@@ -246,6 +249,7 @@ static void pc_init_isa(ram_addr_t ram_size,
     if (cpu_model == NULL)
         cpu_model = "486";
     pc_init1(get_system_memory(),
+             get_system_io(),
              ram_size, boot_device,
              kernel_filename, kernel_cmdline,
              initrd_filename, cpu_model, 0, 1);
diff --git a/hw/pci.c b/hw/pci.c
index c2c2699..0857644 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -264,13 +264,14 @@ int pci_find_domain(const PCIBus *bus)
 
 void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
                          const char *name,
-                         MemoryRegion *address_space,
+                         MemoryRegion *address_space_mem,
+                         MemoryRegion *address_space_io,
                          uint8_t devfn_min)
 {
     qbus_create_inplace(&bus->qbus, &pci_bus_info, parent, name);
     assert(PCI_FUNC(devfn_min) == 0);
     bus->devfn_min = devfn_min;
-    bus->address_space = address_space;
+    bus->address_space = address_space_mem;
 
     /* host bridge */
     QLIST_INIT(&bus->child);
@@ -280,13 +281,16 @@ void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
 }
 
 PCIBus *pci_bus_new(DeviceState *parent, const char *name,
-                    MemoryRegion *address_space, uint8_t devfn_min)
+                    MemoryRegion *address_space_mem,
+                    MemoryRegion *address_space_io,
+                    uint8_t devfn_min)
 {
     PCIBus *bus;
 
     bus = qemu_mallocz(sizeof(*bus));
     bus->qbus.qdev_allocated = 1;
-    pci_bus_new_inplace(bus, parent, name, address_space, devfn_min);
+    pci_bus_new_inplace(bus, parent, name, address_space_mem,
+                        address_space_io, devfn_min);
     return bus;
 }
 
@@ -315,12 +319,14 @@ void pci_bus_set_mem_base(PCIBus *bus, target_phys_addr_t base)
 PCIBus *pci_register_bus(DeviceState *parent, const char *name,
                          pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
                          void *irq_opaque,
-                         MemoryRegion *address_space,
+                         MemoryRegion *address_space_mem,
+                         MemoryRegion *address_space_io,
                          uint8_t devfn_min, int nirq)
 {
     PCIBus *bus;
 
-    bus = pci_bus_new(parent, name, address_space, devfn_min);
+    bus = pci_bus_new(parent, name, address_space_mem,
+                      address_space_io, devfn_min);
     pci_bus_irqs(bus, set_irq, map_irq, irq_opaque, nirq);
     return bus;
 }
diff --git a/hw/pci.h b/hw/pci.h
index 64282ad..45b30fa 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -239,10 +239,13 @@ typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev,
                               PCIHotplugState state);
 void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
                          const char *name,
-                         MemoryRegion *address_space,
+                         MemoryRegion *address_space_mem,
+                         MemoryRegion *address_space_io,
                          uint8_t devfn_min);
 PCIBus *pci_bus_new(DeviceState *parent, const char *name,
-                    MemoryRegion *address_space, uint8_t devfn_min);
+                    MemoryRegion *address_space_mem,
+                    MemoryRegion *address_space_io,
+                    uint8_t devfn_min);
 void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
                   void *irq_opaque, int nirq);
 int pci_bus_get_irq_level(PCIBus *bus, int irq_num);
@@ -250,7 +253,8 @@ void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *dev);
 PCIBus *pci_register_bus(DeviceState *parent, const char *name,
                          pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
                          void *irq_opaque,
-                         MemoryRegion *address_space,
+                         MemoryRegion *address_space_mem,
+                         MemoryRegion *address_space_io,
                          uint8_t devfn_min, int nirq);
 void pci_device_reset(PCIDevice *dev);
 void pci_bus_reset(PCIBus *bus);
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index 80d6665..28a3ee2 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -242,7 +242,8 @@ static PCIBus *i440fx_common_init(const char *device_name,
                                   PCII440FXState **pi440fx_state,
                                   int *piix3_devfn,
                                   qemu_irq *pic,
-                                  MemoryRegion *address_space,
+                                  MemoryRegion *address_space_mem,
+                                  MemoryRegion *address_space_io,
                                   ram_addr_t ram_size)
 {
     DeviceState *dev;
@@ -253,8 +254,9 @@ static PCIBus *i440fx_common_init(const char *device_name,
 
     dev = qdev_create(NULL, "i440FX-pcihost");
     s = FROM_SYSBUS(I440FXState, sysbus_from_qdev(dev));
-    s->address_space = address_space;
-    b = pci_bus_new(&s->busdev.qdev, NULL, s->address_space, 0);
+    s->address_space = address_space_mem;
+    b = pci_bus_new(&s->busdev.qdev, NULL, s->address_space,
+                    address_space_io, 0);
     s->bus = b;
     qdev_init_nofail(dev);
 
@@ -291,13 +293,15 @@ static PCIBus *i440fx_common_init(const char *device_name,
 }
 
 PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn,
-                    qemu_irq *pic, MemoryRegion *address_space,
+                    qemu_irq *pic,
+                    MemoryRegion *address_space_mem,
+                    MemoryRegion *address_space_io,
                     ram_addr_t ram_size)
 {
     PCIBus *b;
 
     b = i440fx_common_init("i440FX", pi440fx_state, piix3_devfn, pic,
-                           address_space, ram_size);
+                           address_space_mem, address_space_io, ram_size);
     return b;
 }
 
diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c
index 15c24f6..c7696b0 100644
--- a/hw/ppc4xx_pci.c
+++ b/hw/ppc4xx_pci.c
@@ -348,6 +348,7 @@ PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4],
                                                  ppc4xx_pci_map_irq,
                                                  pci_irqs,
                                                  get_system_memory(),
+                                                 get_system_io(),
                                                  0, 4);
 
     controller->pci_dev = pci_register_device(controller->pci_state.bus,
diff --git a/hw/ppc_mac.h b/hw/ppc_mac.h
index 6fad20a..25a2274 100644
--- a/hw/ppc_mac.h
+++ b/hw/ppc_mac.h
@@ -55,11 +55,16 @@ qemu_irq *heathrow_pic_init(int *pmem_index,
 
 /* Grackle PCI */
 PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic,
-                         MemoryRegion *address_space);
+                         MemoryRegion *address_space_mem,
+                         MemoryRegion *address_space_io);
 
 /* UniNorth PCI */
-PCIBus *pci_pmac_init(qemu_irq *pic, MemoryRegion *address_space);
-PCIBus *pci_pmac_u3_init(qemu_irq *pic, MemoryRegion *address_space);
+PCIBus *pci_pmac_init(qemu_irq *pic,
+                      MemoryRegion *address_space_mem,
+                      MemoryRegion *address_space_io);
+PCIBus *pci_pmac_u3_init(qemu_irq *pic,
+                         MemoryRegion *address_space_mem,
+                         MemoryRegion *address_space_io);
 
 /* Mac NVRAM */
 typedef struct MacIONVRAMState MacIONVRAMState;
diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c
index 2c0fae8..94a21f9 100644
--- a/hw/ppc_newworld.c
+++ b/hw/ppc_newworld.c
@@ -318,10 +318,10 @@ static void ppc_core99_init (ram_addr_t ram_size,
     pic = openpic_init(NULL, &pic_mem_index, smp_cpus, openpic_irqs, NULL);
     if (PPC_INPUT(env) == PPC_FLAGS_INPUT_970) {
         /* 970 gets a U3 bus */
-        pci_bus = pci_pmac_u3_init(pic, get_system_memory());
+        pci_bus = pci_pmac_u3_init(pic, get_system_memory(), get_system_io());
         machine_arch = ARCH_MAC99_U3;
     } else {
-        pci_bus = pci_pmac_init(pic, get_system_memory());
+        pci_bus = pci_pmac_init(pic, get_system_memory(), get_system_io());
         machine_arch = ARCH_MAC99;
     }
     /* init basic PC hardware */
diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c
index 585afd6..0f99eef 100644
--- a/hw/ppc_oldworld.c
+++ b/hw/ppc_oldworld.c
@@ -234,7 +234,9 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
         hw_error("Only 6xx bus is supported on heathrow machine\n");
     }
     pic = heathrow_pic_init(&pic_mem_index, 1, heathrow_irqs);
-    pci_bus = pci_grackle_init(0xfec00000, pic, get_system_memory());
+    pci_bus = pci_grackle_init(0xfec00000, pic,
+                               get_system_memory(),
+                               get_system_io());
     pci_vga_init(pci_bus);
 
     escc_mem_index = escc_init(0x80013000, pic[0x0f], pic[0x10], serial_hds[0],
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 91ebe07..38d8573 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -649,7 +649,7 @@ static void ppc_prep_init (ram_addr_t ram_size,
         hw_error("Only 6xx bus is supported on PREP machine\n");
     }
     i8259 = i8259_init(first_cpu->irq_inputs[PPC6xx_INPUT_INT]);
-    pci_bus = pci_prep_init(i8259, get_system_memory());
+    pci_bus = pci_prep_init(i8259, get_system_memory(), get_system_io());
     /* Hmm, prep has no pci-isa bridge ??? */
     isa_bus_new(NULL);
     isa_bus_irqs(i8259);
diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c
index 1344539..6a9f979 100644
--- a/hw/ppce500_pci.c
+++ b/hw/ppce500_pci.c
@@ -282,7 +282,8 @@ static int e500_pcihost_initfn(SysBusDevice *dev)
     PPCE500PCIState *s;
     PCIBus *b;
     int i;
-    MemoryRegion *address_space = get_system_memory();
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *address_space_io = get_system_io();
 
     h = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev));
     s = DO_UPCAST(PPCE500PCIState, pci_state, h);
@@ -292,8 +293,8 @@ static int e500_pcihost_initfn(SysBusDevice *dev)
     }
 
     b = pci_register_bus(&s->pci_state.busdev.qdev, NULL, mpc85xx_pci_set_irq,
-                         mpc85xx_pci_map_irq, s->irq, address_space,
-                         PCI_DEVFN(0x11, 0), 4);
+                         mpc85xx_pci_map_irq, s->irq, address_space_mem,
+                         address_space_io, PCI_DEVFN(0x11, 0), 4);
     s->pci_state.bus = b;
 
     pci_create_simple(b, 0, "e500-host-bridge");
diff --git a/hw/prep_pci.c b/hw/prep_pci.c
index da02f0e..58619dd 100644
--- a/hw/prep_pci.c
+++ b/hw/prep_pci.c
@@ -110,7 +110,9 @@ static void prep_set_irq(void *opaque, int irq_num, int level)
     qemu_set_irq(pic[(irq_num & 1) ? 11 : 9] , level);
 }
 
-PCIBus *pci_prep_init(qemu_irq *pic, MemoryRegion *address_space)
+PCIBus *pci_prep_init(qemu_irq *pic,
+                      MemoryRegion *address_space_mem,
+                      MemoryRegion *address_space_io)
 {
     PREPPCIState *s;
     PCIDevice *d;
@@ -119,7 +121,9 @@ PCIBus *pci_prep_init(qemu_irq *pic, MemoryRegion *address_space)
     s = qemu_mallocz(sizeof(PREPPCIState));
     s->bus = pci_register_bus(NULL, "pci",
                               prep_set_irq, prep_map_irq, pic,
-                              address_space, 0, 4);
+                              address_space_mem,
+                              address_space_io,
+                              0, 4);
 
     pci_host_conf_register_ioport(0xcf8, s);
 
diff --git a/hw/prep_pci.h b/hw/prep_pci.h
index a27368b..b6b481a 100644
--- a/hw/prep_pci.h
+++ b/hw/prep_pci.h
@@ -4,6 +4,8 @@
 #include "qemu-common.h"
 #include "memory.h"
 
-PCIBus *pci_prep_init(qemu_irq *pic, MemoryRegion *address_space);
+PCIBus *pci_prep_init(qemu_irq *pic,
+                      MemoryRegion *address_space_mem,
+                      MemoryRegion *address_space_io);
 
 #endif
diff --git a/hw/sh_pci.c b/hw/sh_pci.c
index 0ef93a0..cd86501 100644
--- a/hw/sh_pci.c
+++ b/hw/sh_pci.c
@@ -128,7 +128,9 @@ static int sh_pci_init_device(SysBusDevice *dev)
     }
     s->bus = pci_register_bus(&s->busdev.qdev, "pci",
                               sh_pci_set_irq, sh_pci_map_irq,
-                              s->irq, get_system_memory(),
+                              s->irq,
+                              get_system_memory(),
+                              get_system_io(),
                               PCI_DEVFN(0, 0), 4);
     s->memconfig = cpu_register_io_memory(sh_pci_reg.r, sh_pci_reg.w,
                                           s, DEVICE_NATIVE_ENDIAN);
diff --git a/hw/unin_pci.c b/hw/unin_pci.c
index b499523..f896f8c 100644
--- a/hw/unin_pci.c
+++ b/hw/unin_pci.c
@@ -201,7 +201,9 @@ static int pci_unin_internal_init_device(SysBusDevice *dev)
     return 0;
 }
 
-PCIBus *pci_pmac_init(qemu_irq *pic, MemoryRegion *address_space)
+PCIBus *pci_pmac_init(qemu_irq *pic,
+                      MemoryRegion *address_space_mem,
+                      MemoryRegion *address_space_io)
 {
     DeviceState *dev;
     SysBusDevice *s;
@@ -215,7 +217,9 @@ PCIBus *pci_pmac_init(qemu_irq *pic, MemoryRegion *address_space)
     d = FROM_SYSBUS(UNINState, s);
     d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
                                          pci_unin_set_irq, pci_unin_map_irq,
-                                         pic, address_space,
+                                         pic,
+                                         address_space_mem,
+                                         address_space_io,
                                          PCI_DEVFN(11, 0), 4);
 
 #if 0
@@ -253,7 +257,9 @@ PCIBus *pci_pmac_init(qemu_irq *pic, MemoryRegion *address_space)
     return d->host_state.bus;
 }
 
-PCIBus *pci_pmac_u3_init(qemu_irq *pic, MemoryRegion *address_space)
+PCIBus *pci_pmac_u3_init(qemu_irq *pic,
+                         MemoryRegion *address_space_mem,
+                         MemoryRegion *address_space_io)
 {
     DeviceState *dev;
     SysBusDevice *s;
@@ -268,7 +274,9 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic, MemoryRegion *address_space)
 
     d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
                                          pci_unin_set_irq, pci_unin_map_irq,
-                                         pic, address_space,
+                                         pic,
+                                         address_space_mem,
+                                         address_space_io,
                                          PCI_DEVFN(11, 0), 4);
 
     sysbus_mmio_map(s, 0, 0xf0800000);
diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c
index cffe387..e1d5c0b 100644
--- a/hw/versatile_pci.c
+++ b/hw/versatile_pci.c
@@ -112,7 +112,7 @@ static int pci_vpb_init(SysBusDevice *dev)
     }
     bus = pci_register_bus(&dev->qdev, "pci",
                            pci_vpb_set_irq, pci_vpb_map_irq, s->irq,
-                           get_system_memory(),
+                           get_system_memory(), get_system_io(),
                            PCI_DEVFN(11, 0), 4);
 
     /* ??? Register memory space.  */
commit 309cb471c80e5909710d1ee3c3b50d481496d189
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:09:03 2011 +0300

    Integrate I/O memory regions into qemu
    
    get_system_io() returns the root I/O memory region.
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/exec-memory.h b/exec-memory.h
index c439aba..334219f 100644
--- a/exec-memory.h
+++ b/exec-memory.h
@@ -28,6 +28,11 @@
  */
 MemoryRegion *get_system_memory(void);
 
+/* Get the root I/O port region.  This interface should only be used
+ * temporarily until a proper bus interface is available.
+ */
+MemoryRegion *get_system_io(void);
+
 /* Set the root memory region.  This region is the system memory map. */
 void set_system_memory_map(MemoryRegion *mr);
 
diff --git a/exec.c b/exec.c
index 719fff9..be7e4b2 100644
--- a/exec.c
+++ b/exec.c
@@ -113,6 +113,7 @@ static int in_migration;
 RAMList ram_list = { .blocks = QLIST_HEAD_INITIALIZER(ram_list) };
 
 static MemoryRegion *system_memory;
+static MemoryRegion *system_io;
 
 #endif
 
@@ -3830,6 +3831,10 @@ static void memory_map_init(void)
     system_memory = qemu_malloc(sizeof(*system_memory));
     memory_region_init(system_memory, "system", INT64_MAX);
     set_system_memory_map(system_memory);
+
+    system_io = qemu_malloc(sizeof(*system_io));
+    memory_region_init(system_io, "io", 65536);
+    set_system_io_map(system_io);
 }
 
 MemoryRegion *get_system_memory(void)
@@ -3837,6 +3842,11 @@ MemoryRegion *get_system_memory(void)
     return system_memory;
 }
 
+MemoryRegion *get_system_io(void)
+{
+    return system_io;
+}
+
 #endif /* !defined(CONFIG_USER_ONLY) */
 
 /* physical memory access (slow version, mainly for debug) */
commit 899adf8149c675c2ca0db870da6f00748ee53d59
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:09:02 2011 +0300

    cirrus: simplify linear framebuffer access functions
    
    Make use of the memory API's ability to satisfy multi-byte accesses via
    multiple single-byte accesses.
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index 2a9bd25..c9887ac 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -2250,7 +2250,8 @@ static void cirrus_cursor_draw_line(VGACommonState *s1, uint8_t *d1, int scr_y)
  *
  ***************************************/
 
-static uint32_t cirrus_linear_readb(void *opaque, target_phys_addr_t addr)
+static uint64_t cirrus_linear_read(void *opaque, target_phys_addr_t addr,
+                                   unsigned size)
 {
     CirrusVGAState *s = opaque;
     uint32_t ret;
@@ -2278,28 +2279,8 @@ static uint32_t cirrus_linear_readb(void *opaque, target_phys_addr_t addr)
     return ret;
 }
 
-static uint32_t cirrus_linear_readw(void *opaque, target_phys_addr_t addr)
-{
-    uint32_t v;
-
-    v = cirrus_linear_readb(opaque, addr);
-    v |= cirrus_linear_readb(opaque, addr + 1) << 8;
-    return v;
-}
-
-static uint32_t cirrus_linear_readl(void *opaque, target_phys_addr_t addr)
-{
-    uint32_t v;
-
-    v = cirrus_linear_readb(opaque, addr);
-    v |= cirrus_linear_readb(opaque, addr + 1) << 8;
-    v |= cirrus_linear_readb(opaque, addr + 2) << 16;
-    v |= cirrus_linear_readb(opaque, addr + 3) << 24;
-    return v;
-}
-
-static void cirrus_linear_writeb(void *opaque, target_phys_addr_t addr,
-				 uint32_t val)
+static void cirrus_linear_write(void *opaque, target_phys_addr_t addr,
+                                uint64_t val, unsigned size)
 {
     CirrusVGAState *s = opaque;
     unsigned mode;
@@ -2339,49 +2320,6 @@ static void cirrus_linear_writeb(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static void cirrus_linear_writew(void *opaque, target_phys_addr_t addr,
-				 uint32_t val)
-{
-    cirrus_linear_writeb(opaque, addr, val & 0xff);
-    cirrus_linear_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-}
-
-static void cirrus_linear_writel(void *opaque, target_phys_addr_t addr,
-				 uint32_t val)
-{
-    cirrus_linear_writeb(opaque, addr, val & 0xff);
-    cirrus_linear_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-    cirrus_linear_writeb(opaque, addr + 2, (val >> 16) & 0xff);
-    cirrus_linear_writeb(opaque, addr + 3, (val >> 24) & 0xff);
-}
-
-
-static uint64_t cirrus_linear_read(void *opaque, target_phys_addr_t addr,
-                                   unsigned size)
-{
-    CirrusVGAState *s = opaque;
-
-    switch (size) {
-    case 1: return cirrus_linear_readb(s, addr);
-    case 2: return cirrus_linear_readw(s, addr);
-    case 4: return cirrus_linear_readl(s, addr);
-    default: abort();
-    }
-}
-
-static void cirrus_linear_write(void *opaque, target_phys_addr_t addr,
-                                uint64_t data, unsigned size)
-{
-    CirrusVGAState *s = opaque;
-
-    switch (size) {
-    case 1: return cirrus_linear_writeb(s, addr, data);
-    case 2: return cirrus_linear_writew(s, addr, data);
-    case 4: return cirrus_linear_writel(s, addr, data);
-    default: abort();
-    }
-}
-
 /***************************************
  *
  *  system to screen memory access
@@ -2859,6 +2797,10 @@ static const MemoryRegionOps cirrus_linear_io_ops = {
     .read = cirrus_linear_read,
     .write = cirrus_linear_write,
     .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
 };
 
 static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci)
commit b2a5e761c6fcf0b03734f4d911c02272edbe6ad1
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:09:01 2011 +0300

    vga: simplify vga window mmio access functions
    
    Make use of the memory API's ability to satisfy multi-byte accesses via
    multiple single-byte accesses.
    
    We have to keep vga_mem_{read,write}b() since they're used by cirrus.
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index 5ded1ff..2a9bd25 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -1966,7 +1966,7 @@ static uint64_t cirrus_vga_mem_read(void *opaque,
     uint32_t val;
 
     if ((s->vga.sr[0x07] & 0x01) == 0) {
-	return vga_mem_readb(s, addr);
+        return vga_mem_readb(&s->vga, addr);
     }
 
     if (addr < 0x10000) {
@@ -2011,7 +2011,7 @@ static void cirrus_vga_mem_write(void *opaque,
     unsigned mode;
 
     if ((s->vga.sr[0x07] & 0x01) == 0) {
-	vga_mem_writeb(s, addr, mem_value);
+        vga_mem_writeb(&s->vga, addr, mem_value);
         return;
     }
 
diff --git a/hw/vga.c b/hw/vga.c
index 8b6e6b6..33dc478 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -708,9 +708,8 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
 #endif
 
 /* called for accesses between 0xa0000 and 0xc0000 */
-uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr)
+uint32_t vga_mem_readb(VGACommonState *s, target_phys_addr_t addr)
 {
-    VGACommonState *s = opaque;
     int memory_map_mode, plane;
     uint32_t ret;
 
@@ -764,28 +763,9 @@ uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr)
     return ret;
 }
 
-static uint32_t vga_mem_readw(void *opaque, target_phys_addr_t addr)
-{
-    uint32_t v;
-    v = vga_mem_readb(opaque, addr);
-    v |= vga_mem_readb(opaque, addr + 1) << 8;
-    return v;
-}
-
-static uint32_t vga_mem_readl(void *opaque, target_phys_addr_t addr)
-{
-    uint32_t v;
-    v = vga_mem_readb(opaque, addr);
-    v |= vga_mem_readb(opaque, addr + 1) << 8;
-    v |= vga_mem_readb(opaque, addr + 2) << 16;
-    v |= vga_mem_readb(opaque, addr + 3) << 24;
-    return v;
-}
-
 /* called for accesses between 0xa0000 and 0xc0000 */
-void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val)
 {
-    VGACommonState *s = opaque;
     int memory_map_mode, plane, write_mode, b, func_select, mask;
     uint32_t write_mask, bit_mask, set_mask;
 
@@ -917,20 +897,6 @@ void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
     }
 }
 
-static void vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    vga_mem_writeb(opaque, addr, val & 0xff);
-    vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-}
-
-static void vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    vga_mem_writeb(opaque, addr, val & 0xff);
-    vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-    vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
-    vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
-}
-
 typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
                              const uint8_t *font_ptr, int h,
                              uint32_t fgcol, uint32_t bgcol);
@@ -2105,12 +2071,7 @@ static uint64_t vga_mem_read(void *opaque, target_phys_addr_t addr,
 {
     VGACommonState *s = opaque;
 
-    switch (size) {
-    case 1: return vga_mem_readb(s, addr);
-    case 2: return vga_mem_readw(s, addr);
-    case 4: return vga_mem_readl(s, addr);
-    default: abort();
-    }
+    return vga_mem_readb(s, addr);
 }
 
 static void vga_mem_write(void *opaque, target_phys_addr_t addr,
@@ -2118,18 +2079,17 @@ static void vga_mem_write(void *opaque, target_phys_addr_t addr,
 {
     VGACommonState *s = opaque;
 
-    switch (size) {
-    case 1: return vga_mem_writeb(s, addr, data);
-    case 2: return vga_mem_writew(s, addr, data);
-    case 4: return vga_mem_writel(s, addr, data);
-    default: abort();
-    }
+    return vga_mem_writeb(s, addr, data);
 }
 
 const MemoryRegionOps vga_mem_ops = {
     .read = vga_mem_read,
     .write = vga_mem_write,
     .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
 };
 
 static int vga_common_post_load(void *opaque, int version_id)
diff --git a/hw/vga_int.h b/hw/vga_int.h
index 4592d2c..100d98c 100644
--- a/hw/vga_int.h
+++ b/hw/vga_int.h
@@ -198,8 +198,8 @@ void vga_dirty_log_restart(VGACommonState *s);
 extern const VMStateDescription vmstate_vga_common;
 uint32_t vga_ioport_read(void *opaque, uint32_t addr);
 void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val);
-uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr);
-void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val);
+uint32_t vga_mem_readb(VGACommonState *s, target_phys_addr_t addr);
+void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val);
 void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2);
 int ppm_save(const char *filename, struct DisplaySurface *ds);
 
commit a815b16649eb12f3d834464043dc5ad48eafe594
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:09:00 2011 +0300

    cirrus: simplify vga window mmio access functions
    
    Make use of the memory API's ability to satisfy multi-byte accesses via
    multiple single-byte accesses.
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index c39acb9..5ded1ff 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -1956,7 +1956,9 @@ static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s,
  *
  ***************************************/
 
-static uint32_t cirrus_vga_mem_readb(void *opaque, target_phys_addr_t addr)
+static uint64_t cirrus_vga_mem_read(void *opaque,
+                                    target_phys_addr_t addr,
+                                    uint32_t size)
 {
     CirrusVGAState *s = opaque;
     unsigned bank_index;
@@ -1967,8 +1969,6 @@ static uint32_t cirrus_vga_mem_readb(void *opaque, target_phys_addr_t addr)
 	return vga_mem_readb(s, addr);
     }
 
-    addr &= 0x1ffff;
-
     if (addr < 0x10000) {
 	/* XXX handle bitblt */
 	/* video memory */
@@ -2000,28 +2000,10 @@ static uint32_t cirrus_vga_mem_readb(void *opaque, target_phys_addr_t addr)
     return val;
 }
 
-static uint32_t cirrus_vga_mem_readw(void *opaque, target_phys_addr_t addr)
-{
-    uint32_t v;
-
-    v = cirrus_vga_mem_readb(opaque, addr);
-    v |= cirrus_vga_mem_readb(opaque, addr + 1) << 8;
-    return v;
-}
-
-static uint32_t cirrus_vga_mem_readl(void *opaque, target_phys_addr_t addr)
-{
-    uint32_t v;
-
-    v = cirrus_vga_mem_readb(opaque, addr);
-    v |= cirrus_vga_mem_readb(opaque, addr + 1) << 8;
-    v |= cirrus_vga_mem_readb(opaque, addr + 2) << 16;
-    v |= cirrus_vga_mem_readb(opaque, addr + 3) << 24;
-    return v;
-}
-
-static void cirrus_vga_mem_writeb(void *opaque, target_phys_addr_t addr,
-                                  uint32_t mem_value)
+static void cirrus_vga_mem_write(void *opaque,
+                                 target_phys_addr_t addr,
+                                 uint64_t mem_value,
+                                 uint32_t size)
 {
     CirrusVGAState *s = opaque;
     unsigned bank_index;
@@ -2033,8 +2015,6 @@ static void cirrus_vga_mem_writeb(void *opaque, target_phys_addr_t addr,
         return;
     }
 
-    addr &= 0x1ffff;
-
     if (addr < 0x10000) {
 	if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
 	    /* bitblt */
@@ -2084,51 +2064,14 @@ static void cirrus_vga_mem_writeb(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static void cirrus_vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    cirrus_vga_mem_writeb(opaque, addr, val & 0xff);
-    cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-}
-
-static void cirrus_vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    cirrus_vga_mem_writeb(opaque, addr, val & 0xff);
-    cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-    cirrus_vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
-    cirrus_vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
-}
-
-static uint64_t cirrus_vga_mem_read(void *opaque,
-                                    target_phys_addr_t addr,
-                                    uint32_t size)
-{
-    CirrusVGAState *s = opaque;
-
-    switch (size) {
-    case 1: return cirrus_vga_mem_readb(s, addr);
-    case 2: return cirrus_vga_mem_readw(s, addr);
-    case 4: return cirrus_vga_mem_readl(s, addr);
-    default: abort();
-    }
-}
-
-static void cirrus_vga_mem_write(void *opaque, target_phys_addr_t addr,
-                                 uint64_t data, unsigned size)
-{
-    CirrusVGAState *s = opaque;
-
-    switch (size) {
-    case 1: return cirrus_vga_mem_writeb(s, addr, data);
-    case 2: return cirrus_vga_mem_writew(s, addr, data);
-    case 4: return cirrus_vga_mem_writel(s, addr, data);
-    default: abort();
-    }
-};
-
 static const MemoryRegionOps cirrus_vga_mem_ops = {
     .read = cirrus_vga_mem_read,
     .write = cirrus_vga_mem_write,
     .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
 };
 
 /***************************************
commit 4e56f089ef3f170618207897e9727095c7a46940
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:08:59 2011 +0300

    cirrus: simplify bitblt BAR access functions
    
    Make use of the memory API's ability to satisfy multi-byte accesses via
    multiple single-byte accesses.
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index 4f57b92..c39acb9 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -2446,37 +2446,23 @@ static void cirrus_linear_write(void *opaque, target_phys_addr_t addr,
  ***************************************/
 
 
-static uint32_t cirrus_linear_bitblt_readb(void *opaque, target_phys_addr_t addr)
+static uint64_t cirrus_linear_bitblt_read(void *opaque,
+                                          target_phys_addr_t addr,
+                                          unsigned size)
 {
+    CirrusVGAState *s = opaque;
     uint32_t ret;
 
     /* XXX handle bitblt */
+    (void)s;
     ret = 0xff;
     return ret;
 }
 
-static uint32_t cirrus_linear_bitblt_readw(void *opaque, target_phys_addr_t addr)
-{
-    uint32_t v;
-
-    v = cirrus_linear_bitblt_readb(opaque, addr);
-    v |= cirrus_linear_bitblt_readb(opaque, addr + 1) << 8;
-    return v;
-}
-
-static uint32_t cirrus_linear_bitblt_readl(void *opaque, target_phys_addr_t addr)
-{
-    uint32_t v;
-
-    v = cirrus_linear_bitblt_readb(opaque, addr);
-    v |= cirrus_linear_bitblt_readb(opaque, addr + 1) << 8;
-    v |= cirrus_linear_bitblt_readb(opaque, addr + 2) << 16;
-    v |= cirrus_linear_bitblt_readb(opaque, addr + 3) << 24;
-    return v;
-}
-
-static void cirrus_linear_bitblt_writeb(void *opaque, target_phys_addr_t addr,
-				 uint32_t val)
+static void cirrus_linear_bitblt_write(void *opaque,
+                                       target_phys_addr_t addr,
+                                       uint64_t val,
+                                       unsigned size)
 {
     CirrusVGAState *s = opaque;
 
@@ -2489,55 +2475,14 @@ static void cirrus_linear_bitblt_writeb(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static void cirrus_linear_bitblt_writew(void *opaque, target_phys_addr_t addr,
-				 uint32_t val)
-{
-    cirrus_linear_bitblt_writeb(opaque, addr, val & 0xff);
-    cirrus_linear_bitblt_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-}
-
-static void cirrus_linear_bitblt_writel(void *opaque, target_phys_addr_t addr,
-				 uint32_t val)
-{
-    cirrus_linear_bitblt_writeb(opaque, addr, val & 0xff);
-    cirrus_linear_bitblt_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-    cirrus_linear_bitblt_writeb(opaque, addr + 2, (val >> 16) & 0xff);
-    cirrus_linear_bitblt_writeb(opaque, addr + 3, (val >> 24) & 0xff);
-}
-
-static uint64_t cirrus_linear_bitblt_read(void *opaque,
-                                          target_phys_addr_t addr,
-                                          unsigned size)
-{
-    CirrusVGAState *s = opaque;
-
-    switch (size) {
-    case 1: return cirrus_linear_bitblt_readb(s, addr);
-    case 2: return cirrus_linear_bitblt_readw(s, addr);
-    case 4: return cirrus_linear_bitblt_readl(s, addr);
-    default: abort();
-    }
-};
-
-static void cirrus_linear_bitblt_write(void *opaque,
-                                       target_phys_addr_t addr,
-                                       uint64_t data,
-                                       unsigned size)
-{
-    CirrusVGAState *s = opaque;
-
-    switch (size) {
-    case 1: return cirrus_linear_bitblt_writeb(s, addr, data);
-    case 2: return cirrus_linear_bitblt_writew(s, addr, data);
-    case 4: return cirrus_linear_bitblt_writel(s, addr, data);
-    default: abort();
-    }
-};
-
 static const MemoryRegionOps cirrus_linear_bitblt_io_ops = {
     .read = cirrus_linear_bitblt_read,
     .write = cirrus_linear_bitblt_write,
     .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
 };
 
 static void unmap_bank(CirrusVGAState *s, unsigned bank)
commit 1e04d4d66a27f9677bc0c3580d13c1c778387ac7
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:08:58 2011 +0300

    cirrus: simplify mmio BAR access functions
    
    Make use of the memory API's ability to satisfy multi-byte accesses via
    multiple single-byte accesses.
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index ad23c4a..4f57b92 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -2827,12 +2827,11 @@ static void cirrus_vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
  *
  ***************************************/
 
-static uint32_t cirrus_mmio_readb(void *opaque, target_phys_addr_t addr)
+static uint64_t cirrus_mmio_read(void *opaque, target_phys_addr_t addr,
+                                 unsigned size)
 {
     CirrusVGAState *s = opaque;
 
-    addr &= CIRRUS_PNPMMIO_SIZE - 1;
-
     if (addr >= 0x100) {
         return cirrus_mmio_blt_read(s, addr - 0x100);
     } else {
@@ -2840,33 +2839,11 @@ static uint32_t cirrus_mmio_readb(void *opaque, target_phys_addr_t addr)
     }
 }
 
-static uint32_t cirrus_mmio_readw(void *opaque, target_phys_addr_t addr)
-{
-    uint32_t v;
-
-    v = cirrus_mmio_readb(opaque, addr);
-    v |= cirrus_mmio_readb(opaque, addr + 1) << 8;
-    return v;
-}
-
-static uint32_t cirrus_mmio_readl(void *opaque, target_phys_addr_t addr)
-{
-    uint32_t v;
-
-    v = cirrus_mmio_readb(opaque, addr);
-    v |= cirrus_mmio_readb(opaque, addr + 1) << 8;
-    v |= cirrus_mmio_readb(opaque, addr + 2) << 16;
-    v |= cirrus_mmio_readb(opaque, addr + 3) << 24;
-    return v;
-}
-
-static void cirrus_mmio_writeb(void *opaque, target_phys_addr_t addr,
-			       uint32_t val)
+static void cirrus_mmio_write(void *opaque, target_phys_addr_t addr,
+                              uint64_t val, unsigned size)
 {
     CirrusVGAState *s = opaque;
 
-    addr &= CIRRUS_PNPMMIO_SIZE - 1;
-
     if (addr >= 0x100) {
 	cirrus_mmio_blt_write(s, addr - 0x100, val);
     } else {
@@ -2874,53 +2851,14 @@ static void cirrus_mmio_writeb(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static void cirrus_mmio_writew(void *opaque, target_phys_addr_t addr,
-			       uint32_t val)
-{
-    cirrus_mmio_writeb(opaque, addr, val & 0xff);
-    cirrus_mmio_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-}
-
-static void cirrus_mmio_writel(void *opaque, target_phys_addr_t addr,
-			       uint32_t val)
-{
-    cirrus_mmio_writeb(opaque, addr, val & 0xff);
-    cirrus_mmio_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-    cirrus_mmio_writeb(opaque, addr + 2, (val >> 16) & 0xff);
-    cirrus_mmio_writeb(opaque, addr + 3, (val >> 24) & 0xff);
-}
-
-
-static uint64_t cirrus_mmio_read(void *opaque, target_phys_addr_t addr,
-                                 unsigned size)
-{
-    CirrusVGAState *s = opaque;
-
-    switch (size) {
-    case 1: return cirrus_mmio_readb(s, addr);
-    case 2: return cirrus_mmio_readw(s, addr);
-    case 4: return cirrus_mmio_readl(s, addr);
-    default: abort();
-    }
-};
-
-static void cirrus_mmio_write(void *opaque, target_phys_addr_t addr,
-                              uint64_t data, unsigned size)
-{
-    CirrusVGAState *s = opaque;
-
-    switch (size) {
-    case 1: return cirrus_mmio_writeb(s, addr, data);
-    case 2: return cirrus_mmio_writew(s, addr, data);
-    case 4: return cirrus_mmio_writel(s, addr, data);
-    default: abort();
-    }
-};
-
 static const MemoryRegionOps cirrus_mmio_io_ops = {
     .read = cirrus_mmio_read,
     .write = cirrus_mmio_write,
     .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
 };
 
 /* load/save state */
commit b195043003d90ea4027ea01cc7a6c974ac915108
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:08:57 2011 +0300

    vga: convert vga and its derivatives to the memory API
    
    Convert all vga memory to the memory API.  Note we need to fall back to
    get_system_memory(), since the various buses don't pass the vga window
    as a memory region.
    
    We no longer need to sync the dirty bitmap of the cirrus mapped memory
    banks, since the memory API takes care of that for us.
    
    [jan: fix vga-pci logging]
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index f39d1f8..ad23c4a 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -32,6 +32,7 @@
 #include "console.h"
 #include "vga_int.h"
 #include "loader.h"
+#include "exec-memory.h"
 
 /*
  * TODO:
@@ -200,9 +201,14 @@ typedef void (*cirrus_fill_t)(struct CirrusVGAState *s,
 typedef struct CirrusVGAState {
     VGACommonState vga;
 
-    int cirrus_linear_io_addr;
-    int cirrus_linear_bitblt_io_addr;
-    int cirrus_mmio_io_addr;
+    MemoryRegion cirrus_linear_io;
+    MemoryRegion cirrus_linear_bitblt_io;
+    MemoryRegion cirrus_mmio_io;
+    MemoryRegion pci_bar;
+    bool linear_vram;  /* vga.vram mapped over cirrus_linear_io */
+    MemoryRegion low_mem_container; /* container for 0xa0000-0xc0000 */
+    MemoryRegion low_mem;           /* always mapped, overridden by: */
+    MemoryRegion *cirrus_bank[2];   /*   aliases at 0xa0000-0xb0000  */
     uint32_t cirrus_addr_mask;
     uint32_t linear_mmio_mask;
     uint8_t cirrus_shadow_gr0;
@@ -612,7 +618,7 @@ static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin,
 	off_cur_end = (off_cur + bytesperline) & s->cirrus_addr_mask;
 	off_cur &= TARGET_PAGE_MASK;
 	while (off_cur < off_cur_end) {
-	    cpu_physical_memory_set_dirty(s->vga.vram_offset + off_cur);
+	    memory_region_set_dirty(&s->vga.vram, off_cur);
 	    off_cur += TARGET_PAGE_SIZE;
 	}
 	off_begin += off_pitch;
@@ -1177,12 +1183,6 @@ static void cirrus_update_bank_ptr(CirrusVGAState * s, unsigned bank_index)
     }
 
     if (limit > 0) {
-        /* Thinking about changing bank base? First, drop the dirty bitmap information
-         * on the current location, otherwise we lose this pointer forever */
-        if (s->vga.lfb_vram_mapped) {
-            target_phys_addr_t base_addr = isa_mem_base + 0xa0000 + bank_index * 0x8000;
-            cpu_physical_sync_dirty_bitmap(base_addr, base_addr + 0x8000);
-        }
 	s->cirrus_bank_base[bank_index] = offset;
 	s->cirrus_bank_limit[bank_index] = limit;
     } else {
@@ -1921,8 +1921,8 @@ static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s,
 	val <<= 1;
 	dst++;
     }
-    cpu_physical_memory_set_dirty(s->vga.vram_offset + offset);
-    cpu_physical_memory_set_dirty(s->vga.vram_offset + offset + 7);
+    memory_region_set_dirty(&s->vga.vram, offset);
+    memory_region_set_dirty(&s->vga.vram, offset + 7);
 }
 
 static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s,
@@ -1946,8 +1946,8 @@ static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s,
 	val <<= 1;
 	dst += 2;
     }
-    cpu_physical_memory_set_dirty(s->vga.vram_offset + offset);
-    cpu_physical_memory_set_dirty(s->vga.vram_offset + offset + 15);
+    memory_region_set_dirty(&s->vga.vram, offset);
+    memory_region_set_dirty(&s->vga.vram, offset + 15);
 }
 
 /***************************************
@@ -2057,8 +2057,7 @@ static void cirrus_vga_mem_writeb(void *opaque, target_phys_addr_t addr,
 		mode = s->vga.gr[0x05] & 0x7;
 		if (mode < 4 || mode > 5 || ((s->vga.gr[0x0B] & 0x4) == 0)) {
 		    *(s->vga.vram_ptr + bank_offset) = mem_value;
-		    cpu_physical_memory_set_dirty(s->vga.vram_offset +
-						  bank_offset);
+		    memory_region_set_dirty(&s->vga.vram, bank_offset);
 		} else {
 		    if ((s->vga.gr[0x0B] & 0x14) != 0x14) {
 			cirrus_mem_writeb_mode4and5_8bpp(s, mode,
@@ -2099,16 +2098,37 @@ static void cirrus_vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_
     cirrus_vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
 }
 
-static CPUReadMemoryFunc * const cirrus_vga_mem_read[3] = {
-    cirrus_vga_mem_readb,
-    cirrus_vga_mem_readw,
-    cirrus_vga_mem_readl,
+static uint64_t cirrus_vga_mem_read(void *opaque,
+                                    target_phys_addr_t addr,
+                                    uint32_t size)
+{
+    CirrusVGAState *s = opaque;
+
+    switch (size) {
+    case 1: return cirrus_vga_mem_readb(s, addr);
+    case 2: return cirrus_vga_mem_readw(s, addr);
+    case 4: return cirrus_vga_mem_readl(s, addr);
+    default: abort();
+    }
+}
+
+static void cirrus_vga_mem_write(void *opaque, target_phys_addr_t addr,
+                                 uint64_t data, unsigned size)
+{
+    CirrusVGAState *s = opaque;
+
+    switch (size) {
+    case 1: return cirrus_vga_mem_writeb(s, addr, data);
+    case 2: return cirrus_vga_mem_writew(s, addr, data);
+    case 4: return cirrus_vga_mem_writel(s, addr, data);
+    default: abort();
+    }
 };
 
-static CPUWriteMemoryFunc * const cirrus_vga_mem_write[3] = {
-    cirrus_vga_mem_writeb,
-    cirrus_vga_mem_writew,
-    cirrus_vga_mem_writel,
+static const MemoryRegionOps cirrus_vga_mem_ops = {
+    .read = cirrus_vga_mem_read,
+    .write = cirrus_vga_mem_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
 /***************************************
@@ -2365,7 +2385,7 @@ static void cirrus_linear_writeb(void *opaque, target_phys_addr_t addr,
 	mode = s->vga.gr[0x05] & 0x7;
 	if (mode < 4 || mode > 5 || ((s->vga.gr[0x0B] & 0x4) == 0)) {
 	    *(s->vga.vram_ptr + addr) = (uint8_t) val;
-	    cpu_physical_memory_set_dirty(s->vga.vram_offset + addr);
+	    memory_region_set_dirty(&s->vga.vram, addr);
 	} else {
 	    if ((s->vga.gr[0x0B] & 0x14) != 0x14) {
 		cirrus_mem_writeb_mode4and5_8bpp(s, mode, addr, val);
@@ -2393,17 +2413,31 @@ static void cirrus_linear_writel(void *opaque, target_phys_addr_t addr,
 }
 
 
-static CPUReadMemoryFunc * const cirrus_linear_read[3] = {
-    cirrus_linear_readb,
-    cirrus_linear_readw,
-    cirrus_linear_readl,
-};
+static uint64_t cirrus_linear_read(void *opaque, target_phys_addr_t addr,
+                                   unsigned size)
+{
+    CirrusVGAState *s = opaque;
 
-static CPUWriteMemoryFunc * const cirrus_linear_write[3] = {
-    cirrus_linear_writeb,
-    cirrus_linear_writew,
-    cirrus_linear_writel,
-};
+    switch (size) {
+    case 1: return cirrus_linear_readb(s, addr);
+    case 2: return cirrus_linear_readw(s, addr);
+    case 4: return cirrus_linear_readl(s, addr);
+    default: abort();
+    }
+}
+
+static void cirrus_linear_write(void *opaque, target_phys_addr_t addr,
+                                uint64_t data, unsigned size)
+{
+    CirrusVGAState *s = opaque;
+
+    switch (size) {
+    case 1: return cirrus_linear_writeb(s, addr, data);
+    case 2: return cirrus_linear_writew(s, addr, data);
+    case 4: return cirrus_linear_writel(s, addr, data);
+    default: abort();
+    }
+}
 
 /***************************************
  *
@@ -2471,67 +2505,95 @@ static void cirrus_linear_bitblt_writel(void *opaque, target_phys_addr_t addr,
     cirrus_linear_bitblt_writeb(opaque, addr + 3, (val >> 24) & 0xff);
 }
 
+static uint64_t cirrus_linear_bitblt_read(void *opaque,
+                                          target_phys_addr_t addr,
+                                          unsigned size)
+{
+    CirrusVGAState *s = opaque;
+
+    switch (size) {
+    case 1: return cirrus_linear_bitblt_readb(s, addr);
+    case 2: return cirrus_linear_bitblt_readw(s, addr);
+    case 4: return cirrus_linear_bitblt_readl(s, addr);
+    default: abort();
+    }
+};
+
+static void cirrus_linear_bitblt_write(void *opaque,
+                                       target_phys_addr_t addr,
+                                       uint64_t data,
+                                       unsigned size)
+{
+    CirrusVGAState *s = opaque;
 
-static CPUReadMemoryFunc * const cirrus_linear_bitblt_read[3] = {
-    cirrus_linear_bitblt_readb,
-    cirrus_linear_bitblt_readw,
-    cirrus_linear_bitblt_readl,
+    switch (size) {
+    case 1: return cirrus_linear_bitblt_writeb(s, addr, data);
+    case 2: return cirrus_linear_bitblt_writew(s, addr, data);
+    case 4: return cirrus_linear_bitblt_writel(s, addr, data);
+    default: abort();
+    }
 };
 
-static CPUWriteMemoryFunc * const cirrus_linear_bitblt_write[3] = {
-    cirrus_linear_bitblt_writeb,
-    cirrus_linear_bitblt_writew,
-    cirrus_linear_bitblt_writel,
+static const MemoryRegionOps cirrus_linear_bitblt_io_ops = {
+    .read = cirrus_linear_bitblt_read,
+    .write = cirrus_linear_bitblt_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
-static void map_linear_vram(CirrusVGAState *s)
+static void unmap_bank(CirrusVGAState *s, unsigned bank)
 {
-    if (!s->vga.map_addr && s->vga.lfb_addr && s->vga.lfb_end) {
-        s->vga.map_addr = s->vga.lfb_addr;
-        s->vga.map_end = s->vga.lfb_end;
-        cpu_register_physical_memory_log(s->vga.map_addr,
-					 s->vga.map_end - s->vga.map_addr,
-					 s->vga.vram_offset, 0, true);
+    if (s->cirrus_bank[bank]) {
+        memory_region_del_subregion(&s->low_mem_container,
+                                    s->cirrus_bank[bank]);
+        memory_region_destroy(s->cirrus_bank[bank]);
+        qemu_free(s->cirrus_bank[bank]);
+        s->cirrus_bank[bank] = NULL;
     }
+}
 
-    if (!s->vga.map_addr)
-        return;
-
-    s->vga.lfb_vram_mapped = 0;
+static void map_linear_vram_bank(CirrusVGAState *s, unsigned bank)
+{
+    MemoryRegion *mr;
+    static const char *names[] = { "vga.bank0", "vga.bank1" };
 
     if (!(s->cirrus_srcptr != s->cirrus_srcptr_end)
         && !((s->vga.sr[0x07] & 0x01) == 0)
         && !((s->vga.gr[0x0B] & 0x14) == 0x14)
         && !(s->vga.gr[0x0B] & 0x02)) {
 
-        cpu_register_physical_memory_log(isa_mem_base + 0xa0000, 0x8000,
-					 (s->vga.vram_offset +
-					  s->cirrus_bank_base[0]) |
-					 IO_MEM_RAM, 0, true);
-        cpu_register_physical_memory_log(isa_mem_base + 0xa8000, 0x8000,
-					 (s->vga.vram_offset +
-					  s->cirrus_bank_base[1]) |
-					 IO_MEM_RAM, 0, true);
-
-        s->vga.lfb_vram_mapped = 1;
-    }
-    else {
-        cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x20000,
-                                     s->vga.vga_io_memory);
+        mr = qemu_malloc(sizeof(*mr));
+        memory_region_init_alias(mr, names[bank], &s->vga.vram,
+                                 s->cirrus_bank_base[bank], 0x8000);
+        memory_region_add_subregion_overlap(
+            &s->low_mem_container,
+            0x8000 * bank,
+            mr,
+            1);
+        unmap_bank(s, bank);
+        s->cirrus_bank[bank] = mr;
+    } else {
+        unmap_bank(s, bank);
     }
+}
 
-    vga_dirty_log_start(&s->vga);
+static void map_linear_vram(CirrusVGAState *s)
+{
+    if (!s->linear_vram) {
+        s->linear_vram = true;
+        memory_region_add_subregion_overlap(&s->pci_bar, 0, &s->vga.vram, 1);
+    }
+    map_linear_vram_bank(s, 0);
+    map_linear_vram_bank(s, 1);
 }
 
 static void unmap_linear_vram(CirrusVGAState *s)
 {
-    if (s->vga.map_addr && s->vga.lfb_addr && s->vga.lfb_end) {
-        s->vga.map_addr = s->vga.map_end = 0;
-         cpu_register_physical_memory(s->vga.lfb_addr, s->vga.vram_size,
-                                      s->cirrus_linear_io_addr);
+    if (s->linear_vram) {
+        s->linear_vram = false;
+        memory_region_del_subregion(&s->pci_bar, &s->vga.vram);
     }
-    cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x20000,
-                                 s->vga.vga_io_memory);
+    unmap_bank(s, 0);
+    unmap_bank(s, 1);
 }
 
 /* Compute the memory access functions */
@@ -2829,16 +2891,36 @@ static void cirrus_mmio_writel(void *opaque, target_phys_addr_t addr,
 }
 
 
-static CPUReadMemoryFunc * const cirrus_mmio_read[3] = {
-    cirrus_mmio_readb,
-    cirrus_mmio_readw,
-    cirrus_mmio_readl,
+static uint64_t cirrus_mmio_read(void *opaque, target_phys_addr_t addr,
+                                 unsigned size)
+{
+    CirrusVGAState *s = opaque;
+
+    switch (size) {
+    case 1: return cirrus_mmio_readb(s, addr);
+    case 2: return cirrus_mmio_readw(s, addr);
+    case 4: return cirrus_mmio_readl(s, addr);
+    default: abort();
+    }
+};
+
+static void cirrus_mmio_write(void *opaque, target_phys_addr_t addr,
+                              uint64_t data, unsigned size)
+{
+    CirrusVGAState *s = opaque;
+
+    switch (size) {
+    case 1: return cirrus_mmio_writeb(s, addr, data);
+    case 2: return cirrus_mmio_writew(s, addr, data);
+    case 4: return cirrus_mmio_writel(s, addr, data);
+    default: abort();
+    }
 };
 
-static CPUWriteMemoryFunc * const cirrus_mmio_write[3] = {
-    cirrus_mmio_writeb,
-    cirrus_mmio_writew,
-    cirrus_mmio_writel,
+static const MemoryRegionOps cirrus_mmio_io_ops = {
+    .read = cirrus_mmio_read,
+    .write = cirrus_mmio_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
 /* load/save state */
@@ -2947,6 +3029,12 @@ static void cirrus_reset(void *opaque)
     s->cirrus_hidden_dac_data = 0;
 }
 
+static const MemoryRegionOps cirrus_linear_io_ops = {
+    .read = cirrus_linear_read,
+    .write = cirrus_linear_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
 static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci)
 {
     int i;
@@ -2993,28 +3081,33 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci)
     register_ioport_read(0x3ba, 1, 1, cirrus_vga_ioport_read, s);
     register_ioport_read(0x3da, 1, 1, cirrus_vga_ioport_read, s);
 
-    s->vga.vga_io_memory = cpu_register_io_memory(cirrus_vga_mem_read,
-                                                  cirrus_vga_mem_write, s,
-                                                  DEVICE_LITTLE_ENDIAN);
-    cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
-                                 s->vga.vga_io_memory);
-    qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000);
+    memory_region_init(&s->low_mem_container,
+                       "cirrus-lowmem-container",
+                       0x20000);
+
+    memory_region_init_io(&s->low_mem, &cirrus_vga_mem_ops, s,
+                          "cirrus-low-memory", 0x20000);
+    memory_region_add_subregion(&s->low_mem_container, 0, &s->low_mem);
+    memory_region_add_subregion_overlap(get_system_memory(),
+                                        isa_mem_base + 0x000a0000,
+                                        &s->low_mem_container,
+                                        1);
+    memory_region_set_coalescing(&s->low_mem);
 
     /* I/O handler for LFB */
-    s->cirrus_linear_io_addr =
-        cpu_register_io_memory(cirrus_linear_read, cirrus_linear_write, s,
-                               DEVICE_LITTLE_ENDIAN);
+    memory_region_init_io(&s->cirrus_linear_io, &cirrus_linear_io_ops, s,
+                          "cirrus-linear-io", VGA_RAM_SIZE);
 
     /* I/O handler for LFB */
-    s->cirrus_linear_bitblt_io_addr =
-        cpu_register_io_memory(cirrus_linear_bitblt_read,
-                               cirrus_linear_bitblt_write, s,
-                               DEVICE_LITTLE_ENDIAN);
+    memory_region_init_io(&s->cirrus_linear_bitblt_io,
+                          &cirrus_linear_bitblt_io_ops,
+                          s,
+                          "cirrus-bitblt-mmio",
+                          0x400000);
 
     /* I/O handler for memory-mapped I/O */
-    s->cirrus_mmio_io_addr =
-        cpu_register_io_memory(cirrus_mmio_read, cirrus_mmio_write, s,
-                               DEVICE_LITTLE_ENDIAN);
+    memory_region_init_io(&s->cirrus_mmio_io, &cirrus_mmio_io_ops, s,
+                          "cirrus-mmio", CIRRUS_PNPMMIO_SIZE);
 
     s->real_vram_size =
         (s->device_id == CIRRUS_ID_CLGD5446) ? 4096 * 1024 : 2048 * 1024;
@@ -3060,42 +3153,6 @@ void isa_cirrus_vga_init(void)
  *
  ***************************************/
 
-static void cirrus_pci_lfb_map(PCIDevice *d, int region_num,
-			       pcibus_t addr, pcibus_t size, int type)
-{
-    CirrusVGAState *s = &DO_UPCAST(PCICirrusVGAState, dev, d)->cirrus_vga;
-
-    /* XXX: add byte swapping apertures */
-    cpu_register_physical_memory(addr, s->vga.vram_size,
-				 s->cirrus_linear_io_addr);
-    cpu_register_physical_memory(addr + 0x1000000, 0x400000,
-				 s->cirrus_linear_bitblt_io_addr);
-
-    s->vga.map_addr = s->vga.map_end = 0;
-    s->vga.lfb_addr = addr & TARGET_PAGE_MASK;
-    s->vga.lfb_end = ((addr + VGA_RAM_SIZE) + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
-    /* account for overflow */
-    if (s->vga.lfb_end < addr + VGA_RAM_SIZE)
-        s->vga.lfb_end = addr + VGA_RAM_SIZE;
-
-    vga_dirty_log_start(&s->vga);
-}
-
-static void pci_cirrus_write_config(PCIDevice *d,
-                                    uint32_t address, uint32_t val, int len)
-{
-    PCICirrusVGAState *pvs = DO_UPCAST(PCICirrusVGAState, dev, d);
-    CirrusVGAState *s = &pvs->cirrus_vga;
-
-    pci_default_write_config(d, address, val, len);
-    if (s->vga.map_addr && d->io_regions[0].addr == PCI_BAR_UNMAPPED) {
-        s->vga.map_addr = 0;
-        s->vga.lfb_addr = 0;
-        s->vga.lfb_end = 0;
-    }
-    cirrus_update_memory_access(s);
-}
-
 static int pci_cirrus_vga_initfn(PCIDevice *dev)
 {
      PCICirrusVGAState *d = DO_UPCAST(PCICirrusVGAState, dev, dev);
@@ -3112,15 +3169,21 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev)
 
      /* setup PCI */
 
+    memory_region_init(&s->pci_bar, "cirrus-pci-bar0", 0x2000000);
+
+    /* XXX: add byte swapping apertures */
+    memory_region_add_subregion(&s->pci_bar, 0, &s->cirrus_linear_io);
+    memory_region_add_subregion(&s->pci_bar, 0x1000000,
+                                &s->cirrus_linear_bitblt_io);
+
      /* setup memory space */
      /* memory #0 LFB */
      /* memory #1 memory-mapped I/O */
      /* XXX: s->vga.vram_size must be a power of two */
-     pci_register_bar(&d->dev, 0, 0x2000000,
-                      PCI_BASE_ADDRESS_MEM_PREFETCH, cirrus_pci_lfb_map);
+     pci_register_bar_region(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH,
+                             &s->pci_bar);
      if (device_id == CIRRUS_ID_CLGD5446) {
-         pci_register_bar_simple(&d->dev, 1, CIRRUS_PNPMMIO_SIZE, 0,
-                                 s->cirrus_mmio_io_addr);
+         pci_register_bar_region(&d->dev, 1, 0, &s->cirrus_mmio_io);
      }
      return 0;
 }
@@ -3138,7 +3201,6 @@ static PCIDeviceInfo cirrus_vga_info = {
     .no_hotplug   = 1,
     .init         = pci_cirrus_vga_initfn,
     .romfile      = VGABIOS_CIRRUS_FILENAME,
-    .config_write = pci_cirrus_write_config,
     .vendor_id    = PCI_VENDOR_ID_CIRRUS,
     .device_id    = CIRRUS_ID_CLGD5446,
     .class_id     = PCI_CLASS_DISPLAY_VGA,
diff --git a/hw/qxl-render.c b/hw/qxl-render.c
index 643ff2d..1b77577 100644
--- a/hw/qxl-render.c
+++ b/hw/qxl-render.c
@@ -86,7 +86,7 @@ void qxl_render_update(PCIQXLDevice *qxl)
         }
         qemu_free_displaysurface(vga->ds);
 
-        qxl->guest_primary.data = qemu_get_ram_ptr(qxl->vga.vram_offset);
+        qxl->guest_primary.data = memory_region_get_ram_ptr(&qxl->vga.vram);
         if (qxl->guest_primary.stride < 0) {
             /* spice surface is upside down -> need extra buffer to flip */
             qxl->guest_primary.stride = -qxl->guest_primary.stride;
diff --git a/hw/qxl.c b/hw/qxl.c
index b684608..17c5fc7 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -263,7 +263,7 @@ static ram_addr_t qxl_rom_size(void)
 
 static void init_qxl_rom(PCIQXLDevice *d)
 {
-    QXLRom *rom = qemu_get_ram_ptr(d->rom_offset);
+    QXLRom *rom = memory_region_get_ram_ptr(&d->rom_bar);
     QXLModes *modes = (QXLModes *)(rom + 1);
     uint32_t ram_header_size;
     uint32_t surface0_area_size;
@@ -339,39 +339,37 @@ static void init_qxl_ram(PCIQXLDevice *d)
 }
 
 /* can be called from spice server thread context */
-static void qxl_set_dirty(ram_addr_t addr, ram_addr_t end)
+static void qxl_set_dirty(MemoryRegion *mr, ram_addr_t addr, ram_addr_t end)
 {
     while (addr < end) {
-        cpu_physical_memory_set_dirty(addr);
+        memory_region_set_dirty(mr, addr);
         addr += TARGET_PAGE_SIZE;
     }
 }
 
 static void qxl_rom_set_dirty(PCIQXLDevice *qxl)
 {
-    ram_addr_t addr = qxl->rom_offset;
-    qxl_set_dirty(addr, addr + qxl->rom_size);
+    qxl_set_dirty(&qxl->rom_bar, 0, qxl->rom_size);
 }
 
 /* called from spice server thread context only */
 static void qxl_ram_set_dirty(PCIQXLDevice *qxl, void *ptr)
 {
-    ram_addr_t addr = qxl->vga.vram_offset;
     void *base = qxl->vga.vram_ptr;
     intptr_t offset;
 
     offset = ptr - base;
     offset &= ~(TARGET_PAGE_SIZE-1);
     assert(offset < qxl->vga.vram_size);
-    qxl_set_dirty(addr + offset, addr + offset + TARGET_PAGE_SIZE);
+    qxl_set_dirty(&qxl->vga.vram, offset, offset + TARGET_PAGE_SIZE);
 }
 
 /* can be called from spice server thread context */
 static void qxl_ring_set_dirty(PCIQXLDevice *qxl)
 {
-    ram_addr_t addr = qxl->vga.vram_offset + qxl->shadow_rom.ram_header_offset;
-    ram_addr_t end  = qxl->vga.vram_offset + qxl->vga.vram_size;
-    qxl_set_dirty(addr, end);
+    ram_addr_t addr = qxl->shadow_rom.ram_header_offset;
+    ram_addr_t end  = qxl->vga.vram_size;
+    qxl_set_dirty(&qxl->vga.vram, addr, end);
 }
 
 /*
@@ -819,20 +817,6 @@ static void qxl_set_irq(PCIQXLDevice *d)
     qxl_ring_set_dirty(d);
 }
 
-static void qxl_write_config(PCIDevice *d, uint32_t address,
-                             uint32_t val, int len)
-{
-    PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, d);
-    VGACommonState *vga = &qxl->vga;
-
-    vga_dirty_log_stop(vga);
-    pci_default_write_config(d, address, val, len);
-    if (vga->map_addr && qxl->pci.io_regions[0].addr == -1) {
-        vga->map_addr = 0;
-    }
-    vga_dirty_log_start(vga);
-}
-
 static void qxl_check_state(PCIQXLDevice *d)
 {
     QXLRam *ram = d->ram;
@@ -959,10 +943,10 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta,
 
     switch (pci_region) {
     case QXL_RAM_RANGE_INDEX:
-        virt_start = (intptr_t)qemu_get_ram_ptr(d->vga.vram_offset);
+        virt_start = (intptr_t)memory_region_get_ram_ptr(&d->vga.vram);
         break;
     case QXL_VRAM_RANGE_INDEX:
-        virt_start = (intptr_t)qemu_get_ram_ptr(d->vram_offset);
+        virt_start = (intptr_t)memory_region_get_ram_ptr(&d->vram_bar);
         break;
     default:
         /* should not happen */
@@ -1132,10 +1116,11 @@ static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm)
     qxl_rom_set_dirty(d);
 }
 
-static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
+static void ioport_write(void *opaque, target_phys_addr_t addr,
+                         uint64_t val, unsigned size)
 {
     PCIQXLDevice *d = opaque;
-    uint32_t io_port = addr - d->io_base;
+    uint32_t io_port = addr;
     qxl_async_io async = QXL_SYNC;
 #if SPICE_INTERFACE_QXL_MINOR >= 1
     uint32_t orig_io_port = io_port;
@@ -1241,7 +1226,7 @@ async_common:
         d->oom_running = 0;
         break;
     case QXL_IO_SET_MODE:
-        dprint(d, 1, "QXL_SET_MODE %d\n", val);
+        dprint(d, 1, "QXL_SET_MODE %d\n", (int)val);
         qxl_set_mode(d, val, 0);
         break;
     case QXL_IO_LOG:
@@ -1348,7 +1333,8 @@ cancel_async:
 #endif
 }
 
-static uint32_t ioport_read(void *opaque, uint32_t addr)
+static uint64_t ioport_read(void *opaque, target_phys_addr_t addr,
+                            unsigned size)
 {
     PCIQXLDevice *d = opaque;
 
@@ -1356,42 +1342,14 @@ static uint32_t ioport_read(void *opaque, uint32_t addr)
     return 0xff;
 }
 
-static void qxl_map(PCIDevice *pci, int region_num,
-                    pcibus_t addr, pcibus_t size, int type)
-{
-    static const char *names[] = {
-        [ QXL_IO_RANGE_INDEX ]   = "ioports",
-        [ QXL_RAM_RANGE_INDEX ]  = "devram",
-        [ QXL_ROM_RANGE_INDEX ]  = "rom",
-        [ QXL_VRAM_RANGE_INDEX ] = "vram",
-    };
-    PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, pci);
-
-    dprint(qxl, 1, "%s: bar %d [%s] addr 0x%lx size 0x%lx\n", __FUNCTION__,
-            region_num, names[region_num], addr, size);
-
-    switch (region_num) {
-    case QXL_IO_RANGE_INDEX:
-        register_ioport_write(addr, size, 1, ioport_write, pci);
-        register_ioport_read(addr, size, 1, ioport_read, pci);
-        qxl->io_base = addr;
-        break;
-    case QXL_RAM_RANGE_INDEX:
-        cpu_register_physical_memory(addr, size, qxl->vga.vram_offset | IO_MEM_RAM);
-        qxl->vga.map_addr = addr;
-        qxl->vga.map_end = addr + size;
-        if (qxl->id == 0) {
-            vga_dirty_log_start(&qxl->vga);
-        }
-        break;
-    case QXL_ROM_RANGE_INDEX:
-        cpu_register_physical_memory(addr, size, qxl->rom_offset | IO_MEM_ROM);
-        break;
-    case QXL_VRAM_RANGE_INDEX:
-        cpu_register_physical_memory(addr, size, qxl->vram_offset | IO_MEM_RAM);
-        break;
-    }
-}
+static const MemoryRegionOps qxl_io_ops = {
+    .read = ioport_read,
+    .write = ioport_write,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
 
 static void pipe_read(void *opaque)
 {
@@ -1511,10 +1469,9 @@ static void qxl_vm_change_state_handler(void *opaque, int running, int reason)
          * to make sure they are saved */
         /* FIXME #1: should go out during "live" stage */
         /* FIXME #2: we only need to save the areas which are actually used */
-        ram_addr_t vram_addr = qxl->vram_offset;
-        ram_addr_t surface0_addr = qxl->vga.vram_offset + qxl->shadow_rom.draw_area_offset;
-        qxl_set_dirty(vram_addr, vram_addr + qxl->vram_size);
-        qxl_set_dirty(surface0_addr, surface0_addr + qxl->shadow_rom.surface0_area_size);
+        qxl_set_dirty(&qxl->vram_bar, 0, qxl->vram_size);
+        qxl_set_dirty(&qxl->vga.vram, qxl->shadow_rom.draw_area_offset,
+                      qxl->shadow_rom.surface0_area_size);
     }
 }
 
@@ -1580,7 +1537,8 @@ static int qxl_init_common(PCIQXLDevice *qxl)
     pci_set_byte(&config[PCI_INTERRUPT_PIN], 1);
 
     qxl->rom_size = qxl_rom_size();
-    qxl->rom_offset = qemu_ram_alloc(&qxl->pci.qdev, "qxl.vrom", qxl->rom_size);
+    memory_region_init_ram(&qxl->rom_bar, &qxl->pci.qdev, "qxl.vrom",
+                           qxl->rom_size);
     init_qxl_rom(qxl);
     init_qxl_ram(qxl);
 
@@ -1591,26 +1549,32 @@ static int qxl_init_common(PCIQXLDevice *qxl)
         qxl->vram_size = 4096;
     }
     qxl->vram_size = msb_mask(qxl->vram_size * 2 - 1);
-    qxl->vram_offset = qemu_ram_alloc(&qxl->pci.qdev, "qxl.vram", qxl->vram_size);
+    memory_region_init_ram(&qxl->vram_bar, &qxl->pci.qdev, "qxl.vram",
+                           qxl->vram_size);
 
     io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1);
     if (qxl->revision == 1) {
         io_size = 8;
     }
 
-    pci_register_bar(&qxl->pci, QXL_IO_RANGE_INDEX,
-                     io_size, PCI_BASE_ADDRESS_SPACE_IO, qxl_map);
+    memory_region_init_io(&qxl->io_bar, &qxl_io_ops, qxl,
+                          "qxl-ioports", io_size);
+    if (qxl->id == 0) {
+        vga_dirty_log_start(&qxl->vga);
+    }
+
+
+    pci_register_bar_region(&qxl->pci, QXL_IO_RANGE_INDEX,
+                            PCI_BASE_ADDRESS_SPACE_IO, &qxl->io_bar);
 
-    pci_register_bar(&qxl->pci, QXL_ROM_RANGE_INDEX,
-                     qxl->rom_size, PCI_BASE_ADDRESS_SPACE_MEMORY,
-                     qxl_map);
+    pci_register_bar_region(&qxl->pci, QXL_ROM_RANGE_INDEX,
+                            PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->rom_bar);
 
-    pci_register_bar(&qxl->pci, QXL_RAM_RANGE_INDEX,
-                     qxl->vga.vram_size, PCI_BASE_ADDRESS_SPACE_MEMORY,
-                     qxl_map);
+    pci_register_bar_region(&qxl->pci, QXL_RAM_RANGE_INDEX,
+                            PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->vga.vram);
 
-    pci_register_bar(&qxl->pci, QXL_VRAM_RANGE_INDEX, qxl->vram_size,
-                     PCI_BASE_ADDRESS_SPACE_MEMORY, qxl_map);
+    pci_register_bar_region(&qxl->pci, QXL_VRAM_RANGE_INDEX,
+                            PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->vram_bar);
 
     qxl->ssd.qxl.base.sif = &qxl_interface.base;
     qxl->ssd.qxl.id = qxl->id;
@@ -1664,9 +1628,9 @@ static int qxl_init_secondary(PCIDevice *dev)
         ram_size = 16 * 1024 * 1024;
     }
     qxl->vga.vram_size = ram_size;
-    qxl->vga.vram_offset = qemu_ram_alloc(&qxl->pci.qdev, "qxl.vgavram",
-                                          qxl->vga.vram_size);
-    qxl->vga.vram_ptr = qemu_get_ram_ptr(qxl->vga.vram_offset);
+    memory_region_init_ram(&qxl->vga.vram, &qxl->pci.qdev, "qxl.vgavram",
+                           qxl->vga.vram_size);
+    qxl->vga.vram_ptr = memory_region_get_ram_ptr(&qxl->vga.vram);
 
     return qxl_init_common(qxl);
 }
@@ -1829,7 +1793,6 @@ static PCIDeviceInfo qxl_info_primary = {
     .qdev.vmsd    = &qxl_vmstate,
     .no_hotplug   = 1,
     .init         = qxl_init_primary,
-    .config_write = qxl_write_config,
     .romfile      = "vgabios-qxl.bin",
     .vendor_id    = REDHAT_PCI_VENDOR_ID,
     .device_id    = QXL_DEVICE_ID_STABLE,
diff --git a/hw/qxl.h b/hw/qxl.h
index 4bcf7e1..868db81 100644
--- a/hw/qxl.h
+++ b/hw/qxl.h
@@ -79,14 +79,14 @@ typedef struct PCIQXLDevice {
     QXLRom             *rom;
     QXLModes           *modes;
     uint32_t           rom_size;
-    uint64_t           rom_offset;
+    MemoryRegion       rom_bar;
 
     /* vram pci bar */
     uint32_t           vram_size;
-    uint64_t           vram_offset;
+    MemoryRegion       vram_bar;
 
     /* io bar */
-    uint32_t           io_base;
+    MemoryRegion       io_bar;
 } PCIQXLDevice;
 
 #define PANIC_ON(x) if ((x)) {                         \
diff --git a/hw/vga-isa-mm.c b/hw/vga-isa-mm.c
index 4954bb1..96e6e7d 100644
--- a/hw/vga-isa-mm.c
+++ b/hw/vga-isa-mm.c
@@ -27,6 +27,7 @@
 #include "vga_int.h"
 #include "pixel_ops.h"
 #include "qemu-timer.h"
+#include "exec-memory.h"
 
 typedef struct ISAVGAMMState {
     VGACommonState vga;
@@ -79,35 +80,44 @@ static void vga_mm_writel (void *opaque,
     vga_ioport_write(&s->vga, addr >> s->it_shift, value);
 }
 
-static CPUReadMemoryFunc * const vga_mm_read_ctrl[] = {
-    &vga_mm_readb,
-    &vga_mm_readw,
-    &vga_mm_readl,
-};
-
-static CPUWriteMemoryFunc * const vga_mm_write_ctrl[] = {
-    &vga_mm_writeb,
-    &vga_mm_writew,
-    &vga_mm_writel,
+static const MemoryRegionOps vga_mm_ctrl_ops = {
+    .old_mmio = {
+        .read = {
+            vga_mm_readb,
+            vga_mm_readw,
+            vga_mm_readl,
+        },
+        .write = {
+            vga_mm_writeb,
+            vga_mm_writew,
+            vga_mm_writel,
+        },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void vga_mm_init(ISAVGAMMState *s, target_phys_addr_t vram_base,
                         target_phys_addr_t ctrl_base, int it_shift)
 {
-    int s_ioport_ctrl, vga_io_memory;
+    MemoryRegion *s_ioport_ctrl, *vga_io_memory;
 
     s->it_shift = it_shift;
-    s_ioport_ctrl = cpu_register_io_memory(vga_mm_read_ctrl, vga_mm_write_ctrl, s,
-                                           DEVICE_NATIVE_ENDIAN);
-    vga_io_memory = cpu_register_io_memory(vga_mem_read, vga_mem_write, s,
-                                           DEVICE_NATIVE_ENDIAN);
+    s_ioport_ctrl = qemu_malloc(sizeof(*s_ioport_ctrl));
+    memory_region_init_io(s_ioport_ctrl, &vga_mm_ctrl_ops, s,
+                          "vga-mm-ctrl", 0x100000);
+
+    vga_io_memory = qemu_malloc(sizeof(*vga_io_memory));
+    /* XXX: endianness? */
+    memory_region_init_io(vga_io_memory, &vga_mem_ops, &s->vga,
+                          "vga-mem", 0x20000);
 
     vmstate_register(NULL, 0, &vmstate_vga_common, s);
 
-    cpu_register_physical_memory(ctrl_base, 0x100000, s_ioport_ctrl);
+    memory_region_add_subregion(get_system_memory(), ctrl_base, s_ioport_ctrl);
     s->vga.bank_offset = 0;
-    cpu_register_physical_memory(vram_base + 0x000a0000, 0x20000, vga_io_memory);
-    qemu_register_coalesced_mmio(vram_base + 0x000a0000, 0x20000);
+    memory_region_add_subregion(get_system_memory(),
+                                vram_base + 0x000a0000, vga_io_memory);
+    memory_region_set_coalescing(vga_io_memory);
 }
 
 int isa_vga_mm_init(target_phys_addr_t vram_base,
diff --git a/hw/vga-isa.c b/hw/vga-isa.c
index 245841f..fef7f58 100644
--- a/hw/vga-isa.c
+++ b/hw/vga-isa.c
@@ -28,6 +28,7 @@
 #include "pixel_ops.h"
 #include "qemu-timer.h"
 #include "loader.h"
+#include "exec-memory.h"
 
 typedef struct ISAVGAState {
     ISADevice dev;
@@ -46,13 +47,14 @@ static int vga_initfn(ISADevice *dev)
 {
     ISAVGAState *d = DO_UPCAST(ISAVGAState, dev, dev);
     VGACommonState *s = &d->state;
-    int vga_io_memory;
+    MemoryRegion *vga_io_memory;
 
     vga_common_init(s, VGA_RAM_SIZE);
     vga_io_memory = vga_init_io(s);
-    cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
-                                 vga_io_memory);
-    qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000);
+    memory_region_add_subregion_overlap(get_system_memory(),
+                                        isa_mem_base + 0x000a0000,
+                                        vga_io_memory, 1);
+    memory_region_set_coalescing(vga_io_memory);
     isa_init_ioport(dev, 0x3c0);
     isa_init_ioport(dev, 0x3b4);
     isa_init_ioport(dev, 0x3ba);
diff --git a/hw/vga-pci.c b/hw/vga-pci.c
index 481f448..7062c4d 100644
--- a/hw/vga-pci.c
+++ b/hw/vga-pci.c
@@ -47,29 +47,6 @@ static const VMStateDescription vmstate_vga_pci = {
     }
 };
 
-static void vga_map(PCIDevice *pci_dev, int region_num,
-                    pcibus_t addr, pcibus_t size, int type)
-{
-    PCIVGAState *d = (PCIVGAState *)pci_dev;
-    VGACommonState *s = &d->vga;
-
-    cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
-    s->map_addr = addr;
-    s->map_end = addr + s->vram_size;
-    vga_dirty_log_start(s);
-}
-
-static void pci_vga_write_config(PCIDevice *d,
-                                 uint32_t address, uint32_t val, int len)
-{
-    PCIVGAState *pvs = container_of(d, PCIVGAState, dev);
-    VGACommonState *s = &pvs->vga;
-
-    pci_default_write_config(d, address, val, len);
-    if (s->map_addr && pvs->dev.io_regions[0].addr == -1)
-        s->map_addr = 0;
-}
-
 static int pci_vga_initfn(PCIDevice *dev)
 {
      PCIVGAState *d = DO_UPCAST(PCIVGAState, dev, dev);
@@ -83,8 +60,8 @@ static int pci_vga_initfn(PCIDevice *dev)
                                   s->screen_dump, s->text_update, s);
 
      /* XXX: VGA_RAM_SIZE must be a power of two */
-     pci_register_bar(&d->dev, 0, VGA_RAM_SIZE,
-                      PCI_BASE_ADDRESS_MEM_PREFETCH, vga_map);
+     pci_register_bar_region(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH,
+                             &s->vram);
 
      if (!dev->rom_bar) {
          /* compatibility with pc-0.13 and older */
@@ -106,7 +83,6 @@ static PCIDeviceInfo vga_info = {
     .qdev.vmsd    = &vmstate_vga_pci,
     .no_hotplug   = 1,
     .init         = pci_vga_initfn,
-    .config_write = pci_vga_write_config,
     .romfile      = "vgabios-stdvga.bin",
 
     /* dummy VGA (same as Bochs ID) */
diff --git a/hw/vga.c b/hw/vga.c
index 0f54734..8b6e6b6 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -28,6 +28,7 @@
 #include "vga_int.h"
 #include "pixel_ops.h"
 #include "qemu-timer.h"
+#include "exec-memory.h"
 
 //#define DEBUG_VGA
 //#define DEBUG_VGA_MEM
@@ -825,7 +826,7 @@ void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
             printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
 #endif
             s->plane_updated |= mask; /* only used to detect font change */
-            cpu_physical_memory_set_dirty(s->vram_offset + addr);
+            memory_region_set_dirty(&s->vram, addr);
         }
     } else if (s->gr[5] & 0x10) {
         /* odd/even mode (aka text mode mapping) */
@@ -838,7 +839,7 @@ void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
             printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
 #endif
             s->plane_updated |= mask; /* only used to detect font change */
-            cpu_physical_memory_set_dirty(s->vram_offset + addr);
+            memory_region_set_dirty(&s->vram, addr);
         }
     } else {
         /* standard VGA latched access */
@@ -912,7 +913,7 @@ void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
         printf("vga: latch: [0x" TARGET_FMT_plx "] mask=0x%08x val=0x%08x\n",
                addr * 4, write_mask, val);
 #endif
-        cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
+        memory_region_set_dirty(&s->vram, addr << 2);
     }
 }
 
@@ -1553,57 +1554,17 @@ void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2)
 
 static void vga_sync_dirty_bitmap(VGACommonState *s)
 {
-    if (s->map_addr)
-        cpu_physical_sync_dirty_bitmap(s->map_addr, s->map_end);
-
-    if (s->lfb_vram_mapped) {
-        cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa0000, 0xa8000);
-        cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa8000, 0xb0000);
-    }
-
-#ifdef CONFIG_BOCHS_VBE
-    if (s->vbe_mapped) {
-        cpu_physical_sync_dirty_bitmap(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
-                                       VBE_DISPI_LFB_PHYSICAL_ADDRESS + s->vram_size);
-    }
-#endif
-
+    memory_region_sync_dirty_bitmap(&s->vram);
 }
 
 void vga_dirty_log_start(VGACommonState *s)
 {
-    if (s->map_addr) {
-        cpu_physical_log_start(s->map_addr, s->map_end - s->map_addr);
-    }
-
-    if (s->lfb_vram_mapped) {
-        cpu_physical_log_start(isa_mem_base + 0xa0000, 0x8000);
-        cpu_physical_log_start(isa_mem_base + 0xa8000, 0x8000);
-    }
-
-#ifdef CONFIG_BOCHS_VBE
-    if (s->vbe_mapped) {
-        cpu_physical_log_start(VBE_DISPI_LFB_PHYSICAL_ADDRESS, s->vram_size);
-    }
-#endif
+    memory_region_set_log(&s->vram, true, DIRTY_MEMORY_VGA);
 }
 
 void vga_dirty_log_stop(VGACommonState *s)
 {
-    if (s->map_addr) {
-        cpu_physical_log_stop(s->map_addr, s->map_end - s->map_addr);
-    }
-
-    if (s->lfb_vram_mapped) {
-        cpu_physical_log_stop(isa_mem_base + 0xa0000, 0x8000);
-        cpu_physical_log_stop(isa_mem_base + 0xa8000, 0x8000);
-    }
-
-#ifdef CONFIG_BOCHS_VBE
-    if (s->vbe_mapped) {
-        cpu_physical_log_stop(VBE_DISPI_LFB_PHYSICAL_ADDRESS, s->vram_size);
-    }
-#endif
+    memory_region_set_log(&s->vram, false, DIRTY_MEMORY_VGA);
 }
 
 void vga_dirty_log_restart(VGACommonState *s)
@@ -1773,15 +1734,16 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
         if (!(s->cr[0x17] & 2)) {
             addr = (addr & ~0x8000) | ((y1 & 2) << 14);
         }
-        page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
-        page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
+        page0 = addr & TARGET_PAGE_MASK;
+        page1 = (addr + bwidth - 1) & TARGET_PAGE_MASK;
         update = full_update |
-            cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) |
-            cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG);
+            memory_region_get_dirty(&s->vram, page0, DIRTY_MEMORY_VGA) |
+            memory_region_get_dirty(&s->vram, page1, DIRTY_MEMORY_VGA);
         if ((page1 - page0) > TARGET_PAGE_SIZE) {
             /* if wide line, can use another page */
-            update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE,
-                                                    VGA_DIRTY_FLAG);
+            update |= memory_region_get_dirty(&s->vram,
+                                              page0 + TARGET_PAGE_SIZE,
+                                              DIRTY_MEMORY_VGA);
         }
         /* explicit invalidation for the hardware cursor */
         update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
@@ -1826,8 +1788,10 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
     }
     /* reset modified pages */
     if (page_max >= page_min) {
-        cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
-                                        VGA_DIRTY_FLAG);
+        memory_region_reset_dirty(&s->vram,
+                                  page_min,
+                                  page_max + TARGET_PAGE_SIZE - page_min,
+                                  DIRTY_MEMORY_VGA);
     }
     memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
 }
@@ -1906,11 +1870,6 @@ static void vga_invalidate_display(void *opaque)
 
 void vga_common_reset(VGACommonState *s)
 {
-    s->lfb_addr = 0;
-    s->lfb_end = 0;
-    s->map_addr = 0;
-    s->map_end = 0;
-    s->lfb_vram_mapped = 0;
     s->sr_index = 0;
     memset(s->sr, '\0', sizeof(s->sr));
     s->gr_index = 0;
@@ -2141,16 +2100,36 @@ static void vga_update_text(void *opaque, console_ch_t *chardata)
     dpy_update(s->ds, 0, 0, s->last_width, height);
 }
 
-CPUReadMemoryFunc * const vga_mem_read[3] = {
-    vga_mem_readb,
-    vga_mem_readw,
-    vga_mem_readl,
-};
+static uint64_t vga_mem_read(void *opaque, target_phys_addr_t addr,
+                             unsigned size)
+{
+    VGACommonState *s = opaque;
+
+    switch (size) {
+    case 1: return vga_mem_readb(s, addr);
+    case 2: return vga_mem_readw(s, addr);
+    case 4: return vga_mem_readl(s, addr);
+    default: abort();
+    }
+}
 
-CPUWriteMemoryFunc * const vga_mem_write[3] = {
-    vga_mem_writeb,
-    vga_mem_writew,
-    vga_mem_writel,
+static void vga_mem_write(void *opaque, target_phys_addr_t addr,
+                          uint64_t data, unsigned size)
+{
+    VGACommonState *s = opaque;
+
+    switch (size) {
+    case 1: return vga_mem_writeb(s, addr, data);
+    case 2: return vga_mem_writew(s, addr, data);
+    case 4: return vga_mem_writel(s, addr, data);
+    default: abort();
+    }
+}
+
+const MemoryRegionOps vga_mem_ops = {
+    .read = vga_mem_read,
+    .write = vga_mem_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
 static int vga_common_post_load(void *opaque, int version_id)
@@ -2236,8 +2215,8 @@ void vga_common_init(VGACommonState *s, int vga_ram_size)
 #else
     s->is_vbe_vmstate = 0;
 #endif
-    s->vram_offset = qemu_ram_alloc(NULL, "vga.vram", vga_ram_size);
-    s->vram_ptr = qemu_get_ram_ptr(s->vram_offset);
+    memory_region_init_ram(&s->vram, NULL, "vga.vram", vga_ram_size);
+    s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
     s->vram_size = vga_ram_size;
     s->get_bpp = vga_get_bpp;
     s->get_offsets = vga_get_offsets;
@@ -2257,11 +2236,14 @@ void vga_common_init(VGACommonState *s, int vga_ram_size)
         s->update_retrace_info = vga_precise_update_retrace_info;
         break;
     }
+    vga_dirty_log_start(s);
 }
 
 /* used by both ISA and PCI */
-int vga_init_io(VGACommonState *s)
+MemoryRegion *vga_init_io(VGACommonState *s)
 {
+    MemoryRegion *vga_mem;
+
     register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
 
     register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
@@ -2292,30 +2274,36 @@ int vga_init_io(VGACommonState *s)
 #endif
 #endif /* CONFIG_BOCHS_VBE */
 
-    return cpu_register_io_memory(vga_mem_read, vga_mem_write, s,
-                                  DEVICE_LITTLE_ENDIAN);
+    vga_mem = qemu_malloc(sizeof(*vga_mem));
+    memory_region_init_io(vga_mem, &vga_mem_ops, s,
+                          "vga-lowmem", 0x20000);
+
+    return vga_mem;
 }
 
 void vga_init(VGACommonState *s)
 {
-    int vga_io_memory;
+    MemoryRegion *vga_io_memory;
 
     qemu_register_reset(vga_reset, s);
 
     s->bank_offset = 0;
 
     vga_io_memory = vga_init_io(s);
-    cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
-                                 vga_io_memory);
-    qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000);
+    memory_region_add_subregion_overlap(get_system_memory(),
+                                        isa_mem_base + 0x000a0000,
+                                        vga_io_memory,
+                                        1);
+    memory_region_set_coalescing(vga_io_memory);
 }
 
 void vga_init_vbe(VGACommonState *s)
 {
 #ifdef CONFIG_BOCHS_VBE
     /* XXX: use optimized standard vga accesses */
-    cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
-                                 VGA_RAM_SIZE, s->vram_offset);
+    memory_region_add_subregion(get_system_memory(),
+                                VBE_DISPI_LFB_PHYSICAL_ADDRESS,
+                                &s->vram);
     s->vbe_mapped = 1;
 #endif 
 }
diff --git a/hw/vga_int.h b/hw/vga_int.h
index eee91a8..4592d2c 100644
--- a/hw/vga_int.h
+++ b/hw/vga_int.h
@@ -23,6 +23,7 @@
  */
 
 #include <hw/hw.h>
+#include "memory.h"
 
 #define MSR_COLOR_EMULATION 0x01
 #define MSR_PAGE_SELECT     0x20
@@ -105,11 +106,7 @@ typedef void (* vga_update_retrace_info_fn)(struct VGACommonState *s);
 
 typedef struct VGACommonState {
     uint8_t *vram_ptr;
-    ram_addr_t vram_offset;
-    target_phys_addr_t lfb_addr;
-    target_phys_addr_t lfb_end;
-    target_phys_addr_t map_addr;
-    target_phys_addr_t map_end;
+    MemoryRegion vram;
     uint32_t vram_size;
     uint32_t latch;
     uint32_t lfb_vram_mapped; /* whether 0xa0000 is mapped as ram */
@@ -134,7 +131,7 @@ typedef struct VGACommonState {
     int dac_8bit;
     uint8_t palette[768];
     int32_t bank_offset;
-    int vga_io_memory;
+    MemoryRegion *vga_io_memory;
     int (*get_bpp)(struct VGACommonState *s);
     void (*get_offsets)(struct VGACommonState *s,
                         uint32_t *pline_offset,
@@ -191,7 +188,7 @@ static inline int c6_to_8(int v)
 
 void vga_common_init(VGACommonState *s, int vga_ram_size);
 void vga_init(VGACommonState *s);
-int vga_init_io(VGACommonState *s);
+MemoryRegion *vga_init_io(VGACommonState *s);
 void vga_common_reset(VGACommonState *s);
 
 void vga_dirty_log_start(VGACommonState *s);
@@ -229,5 +226,4 @@ extern const uint8_t gr_mask[16];
 #define VGABIOS_FILENAME "vgabios.bin"
 #define VGABIOS_CIRRUS_FILENAME "vgabios-cirrus.bin"
 
-extern CPUReadMemoryFunc * const vga_mem_read[3];
-extern CPUWriteMemoryFunc * const vga_mem_write[3];
+extern const MemoryRegionOps vga_mem_ops;
diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
index 190b005..02b7478 100644
--- a/hw/vmware_vga.c
+++ b/hw/vmware_vga.c
@@ -65,10 +65,9 @@ struct vmsvga_state_s {
     int syncing;
     int fb_size;
 
-    ram_addr_t fifo_offset;
+    MemoryRegion fifo_ram;
     uint8_t *fifo_ptr;
     unsigned int fifo_size;
-    target_phys_addr_t fifo_base;
 
     union {
         uint32_t *fifo;
@@ -92,6 +91,7 @@ struct vmsvga_state_s {
 struct pci_vmsvga_state_s {
     PCIDevice card;
     struct vmsvga_state_s chip;
+    MemoryRegion io_bar;
 };
 
 #define SVGA_MAGIC		0x900000UL
@@ -789,8 +789,11 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address)
 #endif
         return caps;
 
-    case SVGA_REG_MEM_START:
-        return s->fifo_base;
+    case SVGA_REG_MEM_START: {
+        struct pci_vmsvga_state_s *pci_vmsvga
+            = container_of(s, struct pci_vmsvga_state_s, chip);
+        return pci_get_bar_addr(&pci_vmsvga->card, 2);
+    }
 
     case SVGA_REG_MEM_SIZE:
         return s->fifo_size;
@@ -1135,17 +1138,22 @@ static void vmsvga_vram_writel(void *opaque, target_phys_addr_t addr,
         *(uint32_t *) (s->vram_ptr + addr) = value;
 }
 
-static CPUReadMemoryFunc * const vmsvga_vram_read[] = {
-    vmsvga_vram_readb,
-    vmsvga_vram_readw,
-    vmsvga_vram_readl,
-};
+static const MemoryRegionOps vmsvga_vram_io_ops = {
+    .old_mmio = {
+        .read = {
+            vmsvga_vram_readb,
+            vmsvga_vram_readw,
+            vmsvga_vram_readl,
+        },
+        .write = {
+            vmsvga_vram_writeb,
+            vmsvga_vram_writew,
+            vmsvga_vram_writel,
+        },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+}
 
-static CPUWriteMemoryFunc * const vmsvga_vram_write[] = {
-    vmsvga_vram_writeb,
-    vmsvga_vram_writew,
-    vmsvga_vram_writel,
-};
 #endif
 
 static int vmsvga_post_load(void *opaque, int version_id)
@@ -1211,8 +1219,8 @@ static void vmsvga_init(struct vmsvga_state_s *s, int vga_ram_size)
 
 
     s->fifo_size = SVGA_FIFO_SIZE;
-    s->fifo_offset = qemu_ram_alloc(NULL, "vmsvga.fifo", s->fifo_size);
-    s->fifo_ptr = qemu_get_ram_ptr(s->fifo_offset);
+    memory_region_init_ram(&s->fifo_ram, NULL, "vmsvga.fifo", s->fifo_size);
+    s->fifo_ptr = memory_region_get_ram_ptr(&s->fifo_ram);
 
     vga_common_init(&s->vga, vga_ram_size);
     vga_init(&s->vga);
@@ -1221,79 +1229,76 @@ static void vmsvga_init(struct vmsvga_state_s *s, int vga_ram_size)
     vmsvga_reset(s);
 }
 
-static void pci_vmsvga_map_ioport(PCIDevice *pci_dev, int region_num,
-                pcibus_t addr, pcibus_t size, int type)
+static uint64_t vmsvga_io_read(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
 {
-    struct pci_vmsvga_state_s *d = (struct pci_vmsvga_state_s *) pci_dev;
-    struct vmsvga_state_s *s = &d->chip;
-
-    register_ioport_read(addr + SVGA_IO_MUL * SVGA_INDEX_PORT,
-                    1, 4, vmsvga_index_read, s);
-    register_ioport_write(addr + SVGA_IO_MUL * SVGA_INDEX_PORT,
-                    1, 4, vmsvga_index_write, s);
-    register_ioport_read(addr + SVGA_IO_MUL * SVGA_VALUE_PORT,
-                    1, 4, vmsvga_value_read, s);
-    register_ioport_write(addr + SVGA_IO_MUL * SVGA_VALUE_PORT,
-                    1, 4, vmsvga_value_write, s);
-    register_ioport_read(addr + SVGA_IO_MUL * SVGA_BIOS_PORT,
-                    1, 4, vmsvga_bios_read, s);
-    register_ioport_write(addr + SVGA_IO_MUL * SVGA_BIOS_PORT,
-                    1, 4, vmsvga_bios_write, s);
+    struct vmsvga_state_s *s = opaque;
+
+    switch (addr) {
+    case SVGA_IO_MUL * SVGA_INDEX_PORT: return vmsvga_index_read(s, addr);
+    case SVGA_IO_MUL * SVGA_VALUE_PORT: return vmsvga_value_read(s, addr);
+    case SVGA_IO_MUL * SVGA_BIOS_PORT: return vmsvga_bios_read(s, addr);
+    default: return -1u;
+    }
 }
 
-static void pci_vmsvga_map_mem(PCIDevice *pci_dev, int region_num,
-                pcibus_t addr, pcibus_t size, int type)
+static void vmsvga_io_write(void *opaque, target_phys_addr_t addr,
+                            uint64_t data, unsigned size)
 {
-    struct pci_vmsvga_state_s *d = (struct pci_vmsvga_state_s *) pci_dev;
-    struct vmsvga_state_s *s = &d->chip;
-    ram_addr_t iomemtype;
-
-#ifdef DIRECT_VRAM
-    iomemtype = cpu_register_io_memory(vmsvga_vram_read,
-                    vmsvga_vram_write, s, DEVICE_NATIVE_ENDIAN);
-#else
-    iomemtype = s->vga.vram_offset | IO_MEM_RAM;
-#endif
-    cpu_register_physical_memory(addr, s->vga.vram_size,
-                    iomemtype);
+    struct vmsvga_state_s *s = opaque;
 
-    s->vga.map_addr = addr;
-    s->vga.map_end = addr + s->vga.vram_size;
-    vga_dirty_log_restart(&s->vga);
+    switch (addr) {
+    case SVGA_IO_MUL * SVGA_INDEX_PORT:
+        return vmsvga_index_write(s, addr, data);
+    case SVGA_IO_MUL * SVGA_VALUE_PORT:
+        return vmsvga_value_write(s, addr, data);
+    case SVGA_IO_MUL * SVGA_BIOS_PORT:
+        return vmsvga_bios_write(s, addr, data);
+    }
 }
 
-static void pci_vmsvga_map_fifo(PCIDevice *pci_dev, int region_num,
-                pcibus_t addr, pcibus_t size, int type)
-{
-    struct pci_vmsvga_state_s *d = (struct pci_vmsvga_state_s *) pci_dev;
-    struct vmsvga_state_s *s = &d->chip;
-    ram_addr_t iomemtype;
-
-    s->fifo_base = addr;
-    iomemtype = s->fifo_offset | IO_MEM_RAM;
-    cpu_register_physical_memory(s->fifo_base, s->fifo_size,
-                    iomemtype);
-}
+static const MemoryRegionOps vmsvga_io_ops = {
+    .read = vmsvga_io_read,
+    .write = vmsvga_io_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
 
 static int pci_vmsvga_initfn(PCIDevice *dev)
 {
     struct pci_vmsvga_state_s *s =
         DO_UPCAST(struct pci_vmsvga_state_s, card, dev);
+    MemoryRegion *iomem;
+
+#ifdef DIRECT_VRAM
+    DirectMem *directmem = qemu_malloc(sizeof(*directmem));
+
+    iomem = &directmem->mr;
+    memory_region_init_io(iomem, &vmsvga_vram_io_ops, &s->chip, "vmsvga",
+                          memory_region_size(&s->chip.vga.vram));
+#else
+    iomem = &s->chip.vga.vram;
+#endif
+
+    vga_dirty_log_restart(&s->chip.vga);
 
     s->card.config[PCI_CACHE_LINE_SIZE]	= 0x08;		/* Cache line size */
     s->card.config[PCI_LATENCY_TIMER] = 0x40;		/* Latency timer */
     s->card.config[PCI_INTERRUPT_LINE] = 0xff;		/* End */
 
-    pci_register_bar(&s->card, 0, 0x10,
-                    PCI_BASE_ADDRESS_SPACE_IO, pci_vmsvga_map_ioport);
-    pci_register_bar(&s->card, 1, VGA_RAM_SIZE,
-                    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);
+    memory_region_init_io(&s->io_bar, &vmsvga_io_ops, &s->chip,
+                          "vmsvga-io", 0x10);
+    pci_register_bar_region(&s->card, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_bar);
 
     vmsvga_init(&s->chip, VGA_RAM_SIZE);
 
+    pci_register_bar_region(&s->card, 1, PCI_BASE_ADDRESS_MEM_PREFETCH, iomem);
+    pci_register_bar_region(&s->card, 2, PCI_BASE_ADDRESS_MEM_PREFETCH,
+                            &s->chip.fifo_ram);
+
     if (!dev->rom_bar) {
         /* compatibility with pc-0.13 and older */
         vga_init_vbe(&s->chip.vga);
commit 7b619b9ae5c55eb443da19183f98f62138bd012a
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:08:56 2011 +0300

    vmsvga: don't remember pci BAR address in callback any more
    
    We're going to remove the callback, so we can't use it to save the
    address.  Use the pci API instead.
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
index 354c221..190b005 100644
--- a/hw/vmware_vga.c
+++ b/hw/vmware_vga.c
@@ -52,8 +52,6 @@ struct vmsvga_state_s {
         int on;
     } cursor;
 
-    target_phys_addr_t vram_base;
-
     int index;
     int scratch_size;
     uint32_t *scratch;
@@ -761,8 +759,11 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address)
     case SVGA_REG_BYTES_PER_LINE:
         return ((s->depth + 7) >> 3) * s->new_width;
 
-    case SVGA_REG_FB_START:
-        return s->vram_base;
+    case SVGA_REG_FB_START: {
+        struct pci_vmsvga_state_s *pci_vmsvga
+            = container_of(s, struct pci_vmsvga_state_s, chip);
+        return pci_get_bar_addr(&pci_vmsvga->card, 1);
+    }
 
     case SVGA_REG_FB_OFFSET:
         return 0x0;
@@ -1247,14 +1248,13 @@ static void pci_vmsvga_map_mem(PCIDevice *pci_dev, int region_num,
     struct vmsvga_state_s *s = &d->chip;
     ram_addr_t iomemtype;
 
-    s->vram_base = addr;
 #ifdef DIRECT_VRAM
     iomemtype = cpu_register_io_memory(vmsvga_vram_read,
                     vmsvga_vram_write, s, DEVICE_NATIVE_ENDIAN);
 #else
     iomemtype = s->vga.vram_offset | IO_MEM_RAM;
 #endif
-    cpu_register_physical_memory(s->vram_base, s->vga.vram_size,
+    cpu_register_physical_memory(addr, s->vga.vram_size,
                     iomemtype);
 
     s->vga.map_addr = addr;
commit 16a96f288adccdd84c17c7d1696042a2a2009bfc
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:08:55 2011 +0300

    pci: add API to get a BAR's mapped address
    
    Some (hacky) devices that have a back-channel to read this
    address back outside the normal configuration mechanisms, such
    as VMware svga.
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/pci.c b/hw/pci.c
index 8621d3d..c2c2699 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -952,6 +952,11 @@ void pci_register_bar_region(PCIDevice *pci_dev, int region_num,
     pci_dev->io_regions[region_num].memory = memory;
 }
 
+pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num)
+{
+    return pci_dev->io_regions[region_num].addr;
+}
+
 static void pci_bridge_filter(PCIDevice *d, pcibus_t *addr, pcibus_t *size,
                               uint8_t type)
 {
diff --git a/hw/pci.h b/hw/pci.h
index c51156d..64282ad 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -207,6 +207,7 @@ void pci_register_bar_simple(PCIDevice *pci_dev, int region_num,
                              pcibus_t size, uint8_t attr, ram_addr_t ram_addr);
 void pci_register_bar_region(PCIDevice *pci_dev, int region_num,
                              uint8_t attr, MemoryRegion *memory);
+pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num);
 
 int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
                        uint8_t offset, uint8_t size);
commit 2dd3022826bb1ced27d12493a8f1f4b6d4bc71b7
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 16:08:54 2011 +0300

    memory: rename PORTIO_END to PORTIO_END_OF_LIST
    
    For consistency with other _END_OF_LIST macros.
    
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/memory.h b/memory.h
index 4e518b2..da00a3b 100644
--- a/memory.h
+++ b/memory.h
@@ -133,7 +133,7 @@ struct MemoryRegionPortio {
     IOPortWriteFunc *write;
 };
 
-#define PORTIO_END { }
+#define PORTIO_END_OF_LIST() { }
 
 /**
  * memory_region_init: Initialize a memory region
commit 32b746775d828b016cd19ef99fcd9bf1d085c7bc
Author: malc <av1474 at comtv.ru>
Date:   Mon Aug 8 13:46:51 2011 +0400

    Unbreak the build on ppc32
    
    Signed-off-by: malc <av1474 at comtv.ru>

diff --git a/coroutine-ucontext.c b/coroutine-ucontext.c
index 41c2379..42dc3e2 100644
--- a/coroutine-ucontext.c
+++ b/coroutine-ucontext.c
@@ -133,7 +133,7 @@ static Coroutine *coroutine_new(void)
     CoroutineUContext *co;
     ucontext_t old_uc, uc;
     jmp_buf old_env;
-    union cc_arg arg;
+    union cc_arg arg = {0};
 
     /* The ucontext functions preserve signal masks which incurs a system call
      * overhead.  setjmp()/longjmp() does not preserve signal masks but only
commit 9f058c19fcf53c77af15894937ccb380381649c3
Merge: a67a47d... 23ddf2b...
Author: malc <av1474 at comtv.ru>
Date:   Mon Aug 8 13:37:44 2011 +0400

    Merge branch 'master' of git://git.qemu.org/qemu

commit 23ddf2bb1e4bfe2b72a726fe5e828807b65941ad
Author: Brad <brad at comstyle.com>
Date:   Sun Aug 7 11:06:43 2011 +0000

    Fix forcing multicast msgs to loopback on OpenBSD.
    
    Fix forcing multicast msgs to loopback on OpenBSD.
    e.g.
    $ sudo qemu -m 128 -no-fd-bootchk \
            -hda virtual.img -boot n -nographic \
            -net nic,vlan=0,model=rtl8139,macaddr=52:54:00:12:34:03 \
            -net user -tftp /usr/src/sys/arch/i386/compile/TEST -bootp pxeboot \
            -net nic,vlan=1,model=rtl8139,macaddr=52:54:00:23:03:01 \
            -net tap,vlan=1,script=no \
            -net nic,vlan=3,model=rtl8139,macaddr=52:54:00:23:03:03 \
            -net socket,vlan=3,mcast=230.0.0.1:10003
    setsockopt(SOL_IP, IP_MULTICAST_LOOP): Invalid argument
    qemu: -net socket,vlan=3,mcast=230.0.0.1:10003: Device 'socket' could not be initialized
    
    Signed-off-by: Brad Smith <brad at comstyle.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/net/socket.c b/net/socket.c
index 11fe5f3..5cd0b9a 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -154,6 +154,12 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr
     struct ip_mreq imr;
     int fd;
     int val, ret;
+#ifdef __OpenBSD__
+    unsigned char loop;
+#else
+    int loop;
+#endif
+
     if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) {
 	fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) does not contain a multicast address\n",
 		inet_ntoa(mcastaddr->sin_addr),
@@ -197,9 +203,9 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr
     }
 
     /* Force mcast msgs to loopback (eg. several QEMUs in same host */
-    val = 1;
+    loop = 1;
     ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
-                   (const char *)&val, sizeof(val));
+                   (const char *)&loop, sizeof(loop));
     if (ret < 0) {
 	perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)");
 	goto fail;
commit 9f4b09a4cd2f65f972b0b334658aaab8760bff73
Author: Tobias Nygren <tnn at netbsd.org>
Date:   Sun Aug 7 09:57:05 2011 +0000

    Use mmap to allocate execute memory
    
    Use mmap to allocate executable memory on NetBSD as well.
    
    Signed-off-by: Christoph Egger <Christoph.Egger at amd.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/exec.c b/exec.c
index 5bc9203..719fff9 100644
--- a/exec.c
+++ b/exec.c
@@ -526,7 +526,8 @@ static void code_gen_alloc(unsigned long tb_size)
         }
     }
 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) \
-    || defined(__DragonFly__) || defined(__OpenBSD__)
+    || defined(__DragonFly__) || defined(__OpenBSD__) \
+    || defined(__NetBSD__)
     {
         int flags;
         void *addr = NULL;
commit 45c245bf808a48cb7c6c99aaa43d8fb9054fc84e
Author: Manuel Bouyer <bouyer at netbsd.org>
Date:   Sun Aug 7 09:48:59 2011 +0000

    Fix network interface tap backend
    
    Fix network interface tap backend work on NetBSD.
    It uses an ioctl to get the tap name.
    
    Signed-off-by: Christoph Egger<Christoph.Egger at amd.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/net/tap-bsd.c b/net/tap-bsd.c
index 2f3efde..4b6b3a4 100644
--- a/net/tap-bsd.c
+++ b/net/tap-bsd.c
@@ -28,6 +28,8 @@
 #include "qemu-error.h"
 
 #ifdef __NetBSD__
+#include <sys/ioctl.h>
+#include <net/if.h>
 #include <net/if_tap.h>
 #endif
 
@@ -40,8 +42,12 @@
 int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required)
 {
     int fd;
+#ifdef TAPGIFNAME
+    struct ifreq ifr;
+#else
     char *dev;
     struct stat s;
+#endif
 
 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__)
     /* if no ifname is given, always start the search from tap0/tun0. */
@@ -77,14 +83,30 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required
 #else
     TFR(fd = open("/dev/tap", O_RDWR));
     if (fd < 0) {
-        fprintf(stderr, "warning: could not open /dev/tap: no virtual network emulation\n");
+        fprintf(stderr,
+            "warning: could not open /dev/tap: no virtual network emulation: %s\n",
+            strerror(errno));
         return -1;
     }
 #endif
 
-    fstat(fd, &s);
+#ifdef TAPGIFNAME
+    if (ioctl(fd, TAPGIFNAME, (void *)&ifr) < 0) {
+        fprintf(stderr, "warning: could not get tap name: %s\n",
+            strerror(errno));
+        return -1;
+    }
+    pstrcpy(ifname, ifname_size, ifr.ifr_name);
+#else
+    if (fstat(fd, &s) < 0) {
+        fprintf(stderr,
+            "warning: could not stat /dev/tap: no virtual network emulation: %s\n",
+            strerror(errno));
+        return -1;
+    }
     dev = devname(s.st_rdev, S_IFCHR);
     pstrcpy(ifname, ifname_size, dev);
+#endif
 
     if (*vnet_hdr) {
         /* BSD doesn't have IFF_VNET_HDR */
commit c7c37b5d702b7f93b03133420460970a8fa8724f
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Wed Jul 20 21:40:18 2011 +0200

    darwin-user: Remove two unused variables
    
    cppcheck report:
    
    darwin-user/signal.c:322: style: Unused variable: i
    darwin-user/signal.c:322: style:
    Variable 'err' is assigned a value that is never used
    
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/darwin-user/signal.c b/darwin-user/signal.c
index e2adca3..c530227 100644
--- a/darwin-user/signal.c
+++ b/darwin-user/signal.c
@@ -319,7 +319,6 @@ static void setup_frame(int sig, struct emulated_sigaction *ka,
 			void *set, CPUState *env)
 {
 	void *frame;
-	int i, err = 0;
 
     fprintf(stderr, "setup_frame %d\n", sig);
 	frame = get_sigframe(ka, env, sizeof(*frame));
commit e31b0a7c050711884ad570fe73df806520953618
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sat Aug 6 13:58:47 2011 +0000

    TCG: fix copy propagation
    
    Copy propagation introduced in 22613af4a6d9602001e6d0e7b6d98aa40aa018dc
    considered only global registers. However, register temps and stack
    allocated locals must be handled differently because register temps
    don't survive across brcond.
    
    Fix by propagating only within same class of temps.
    
    Tested-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/tcg/optimize.c b/tcg/optimize.c
index a3bfa5e..7eb5eb1 100644
--- a/tcg/optimize.c
+++ b/tcg/optimize.c
@@ -185,12 +185,15 @@ static int op_to_movi(int op)
     }
 }
 
-static void tcg_opt_gen_mov(TCGArg *gen_args, TCGArg dst, TCGArg src,
-                            int nb_temps, int nb_globals)
+static void tcg_opt_gen_mov(TCGContext *s, TCGArg *gen_args, TCGArg dst,
+                            TCGArg src, int nb_temps, int nb_globals)
 {
         reset_temp(dst, nb_temps, nb_globals);
         assert(temps[src].state != TCG_TEMP_COPY);
-        if (src >= nb_globals) {
+        /* Don't try to copy if one of temps is a global or either one
+           is local and another is register */
+        if (src >= nb_globals && dst >= nb_globals &&
+            tcg_arg_is_local(s, src) == tcg_arg_is_local(s, dst)) {
             assert(temps[src].state != TCG_TEMP_CONST);
             if (temps[src].state != TCG_TEMP_HAS_COPY) {
                 temps[src].state = TCG_TEMP_HAS_COPY;
@@ -474,7 +477,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
                     gen_opc_buf[op_index] = INDEX_op_nop;
                 } else {
                     gen_opc_buf[op_index] = op_to_mov(op);
-                    tcg_opt_gen_mov(gen_args, args[0], args[1],
+                    tcg_opt_gen_mov(s, gen_args, args[0], args[1],
                                     nb_temps, nb_globals);
                     gen_args += 2;
                     args += 3;
@@ -500,7 +503,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
                     gen_opc_buf[op_index] = INDEX_op_nop;
                 } else {
                     gen_opc_buf[op_index] = op_to_mov(op);
-                    tcg_opt_gen_mov(gen_args, args[0], args[1], nb_temps,
+                    tcg_opt_gen_mov(s, gen_args, args[0], args[1], nb_temps,
                                     nb_globals);
                     gen_args += 2;
                     args += 3;
@@ -523,7 +526,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
                 break;
             }
             if (temps[args[1]].state != TCG_TEMP_CONST) {
-                tcg_opt_gen_mov(gen_args, args[0], args[1],
+                tcg_opt_gen_mov(s, gen_args, args[0], args[1],
                                 nb_temps, nb_globals);
                 gen_args += 2;
                 args += 2;
diff --git a/tcg/tcg.h b/tcg/tcg.h
index e76f9af..e2a7095 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -410,6 +410,11 @@ static inline TCGv_i64 tcg_temp_local_new_i64(void)
 void tcg_temp_free_i64(TCGv_i64 arg);
 char *tcg_get_arg_str_i64(TCGContext *s, char *buf, int buf_size, TCGv_i64 arg);
 
+static inline bool tcg_arg_is_local(TCGContext *s, TCGArg arg)
+{
+    return s->temps[arg].temp_local;
+}
+
 #if defined(CONFIG_DEBUG_TCG)
 /* If you call tcg_clear_temp_count() at the start of a section of
  * code which is not supposed to leak any TCG temporaries, then
commit 97b348e7d221c94ddde609346407bd2cd6f85044
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Mon Aug 1 16:12:17 2011 +0000

    Remove unused is_softmmu parameter from cpu_handle_mmu_fault
    
    Parameter is_softmmu (and its evil mutant twin brother is_softmuu)
    is not used in cpu_*_handle_mmu_fault() functions, remove them
    and adjust callers.
    
    Acked-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index 919be12..c2e7bb3 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -426,7 +426,7 @@ int cpu_alpha_exec(CPUAlphaState *s);
 int cpu_alpha_signal_handler(int host_signum, void *pinfo,
                              void *puc);
 int cpu_alpha_handle_mmu_fault (CPUState *env, uint64_t address, int rw,
-                                int mmu_idx, int is_softmmu);
+                                int mmu_idx);
 #define cpu_handle_mmu_fault cpu_alpha_handle_mmu_fault
 void do_interrupt (CPUState *env);
 
diff --git a/target-alpha/helper.c b/target-alpha/helper.c
index 7049c80..06d2565 100644
--- a/target-alpha/helper.c
+++ b/target-alpha/helper.c
@@ -160,7 +160,7 @@ void cpu_alpha_store_fpcr (CPUState *env, uint64_t val)
 
 #if defined(CONFIG_USER_ONLY)
 int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                                int mmu_idx, int is_softmmu)
+                                int mmu_idx)
 {
     env->exception_index = EXCP_MMFAULT;
     env->trap_arg0 = address;
@@ -316,7 +316,7 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
 }
 
 int cpu_alpha_handle_mmu_fault(CPUState *env, target_ulong addr, int rw,
-                               int mmu_idx, int is_softmmu)
+                               int mmu_idx)
 {
     target_ulong phys;
     int prot, fail;
diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c
index c2bb679..38be234 100644
--- a/target-alpha/op_helper.c
+++ b/target-alpha/op_helper.c
@@ -1344,7 +1344,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
        generated code */
     saved_env = env;
     env = cpu_single_env;
-    ret = cpu_alpha_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    ret = cpu_alpha_handle_mmu_fault(env, addr, is_write, mmu_idx);
     if (unlikely(ret != 0)) {
         do_restore_state(retaddr);
         /* Exception index and error code are already set */
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index adef427..f17fd6b 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -244,7 +244,7 @@ uint32_t do_arm_semihosting(CPUARMState *env);
 int cpu_arm_signal_handler(int host_signum, void *pinfo,
                            void *puc);
 int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address, int rw,
-                              int mmu_idx, int is_softmuu);
+                              int mmu_idx);
 #define cpu_handle_mmu_fault cpu_arm_handle_mmu_fault
 
 static inline void cpu_set_tls(CPUARMState *env, target_ulong newtls)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index ae4f334..1ee199d 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -542,7 +542,7 @@ void do_interrupt (CPUState *env)
 }
 
 int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                              int mmu_idx, int is_softmmu)
+                              int mmu_idx)
 {
     if (rw == 2) {
         env->exception_index = EXCP_PREFETCH_ABORT;
@@ -1254,7 +1254,7 @@ static inline int get_phys_addr(CPUState *env, uint32_t address,
 }
 
 int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address,
-                              int access_type, int mmu_idx, int is_softmmu)
+                              int access_type, int mmu_idx)
 {
     uint32_t phys_addr;
     target_ulong page_size;
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index 57e4977..37b77e1 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -86,7 +86,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
        generated code */
     saved_env = env;
     env = cpu_single_env;
-    ret = cpu_arm_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    ret = cpu_arm_handle_mmu_fault(env, addr, is_write, mmu_idx);
     if (unlikely(ret)) {
         if (retaddr) {
             /* now we have a real cpu fault */
diff --git a/target-cris/cpu.h b/target-cris/cpu.h
index ecb0df1..8ae0ce3 100644
--- a/target-cris/cpu.h
+++ b/target-cris/cpu.h
@@ -226,7 +226,7 @@ static inline int cpu_mmu_index (CPUState *env)
 }
 
 int cpu_cris_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
-                              int mmu_idx, int is_softmmu);
+                              int mmu_idx);
 #define cpu_handle_mmu_fault cpu_cris_handle_mmu_fault
 
 #if defined(CONFIG_USER_ONLY)
diff --git a/target-cris/helper.c b/target-cris/helper.c
index 962d214..75f0035 100644
--- a/target-cris/helper.c
+++ b/target-cris/helper.c
@@ -47,7 +47,7 @@ void do_interrupt (CPUState *env)
 }
 
 int cpu_cris_handle_mmu_fault(CPUState * env, target_ulong address, int rw,
-                             int mmu_idx, int is_softmmu)
+                              int mmu_idx)
 {
 	env->exception_index = 0xaa;
 	env->pregs[PR_EDA] = address;
@@ -68,7 +68,7 @@ static void cris_shift_ccs(CPUState *env)
 }
 
 int cpu_cris_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                               int mmu_idx, int is_softmmu)
+                               int mmu_idx)
 {
 	struct cris_mmu_result res;
 	int prot, miss;
@@ -104,10 +104,9 @@ int cpu_cris_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
                 r = 0;
 	}
 	if (r > 0)
-		D_LOG("%s returns %d irqreq=%x addr=%x"
-			  " phy=%x ismmu=%d vec=%x pc=%x\n", 
-			  __func__, r, env->interrupt_request, 
-			  address, res.phy, is_softmmu, res.bf_vec, env->pc);
+            D_LOG("%s returns %d irqreq=%x addr=%x phy=%x vec=%x pc=%x\n",
+                  __func__, r, env->interrupt_request, address, res.phy,
+                  res.bf_vec, env->pc);
 	return r;
 }
 
diff --git a/target-cris/op_helper.c b/target-cris/op_helper.c
index 246f08f..0cfe1b1 100644
--- a/target-cris/op_helper.c
+++ b/target-cris/op_helper.c
@@ -70,7 +70,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
 
     D_LOG("%s pc=%x tpc=%x ra=%x\n", __func__, 
 	     env->pc, env->debug1, retaddr);
-    ret = cpu_cris_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    ret = cpu_cris_handle_mmu_fault(env, addr, is_write, mmu_idx);
     if (unlikely(ret)) {
         if (retaddr) {
             /* now we have a real cpu fault */
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index dd6c5fa..ae0e4b1 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -889,7 +889,7 @@ void host_cpuid(uint32_t function, uint32_t count,
 
 /* helper.c */
 int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
-                             int is_write, int mmu_idx, int is_softmmu);
+                             int is_write, int mmu_idx);
 #define cpu_handle_mmu_fault cpu_x86_handle_mmu_fault
 void cpu_x86_set_a20(CPUX86State *env, int a20_state);
 
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 3332195..f8c8633 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -546,7 +546,7 @@ void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
 #if defined(CONFIG_USER_ONLY)
 
 int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
-                             int is_write, int mmu_idx, int is_softmmu)
+                             int is_write, int mmu_idx)
 {
     /* user mode only emulation */
     is_write &= 1;
@@ -573,7 +573,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
    1  = generate PF fault
 */
 int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
-                             int is_write1, int mmu_idx, int is_softmmu)
+                             int is_write1, int mmu_idx)
 {
     uint64_t ptep, pte;
     target_ulong pde_addr, pte_addr;
diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c
index 1380934..1bbc3b5 100644
--- a/target-i386/op_helper.c
+++ b/target-i386/op_helper.c
@@ -5009,7 +5009,7 @@ void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
     saved_env = env;
     env = cpu_single_env;
 
-    ret = cpu_x86_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    ret = cpu_x86_handle_mmu_fault(env, addr, is_write, mmu_idx);
     if (ret) {
         if (retaddr) {
             /* now we have a real cpu fault */
diff --git a/target-lm32/cpu.h b/target-lm32/cpu.h
index 876b5be..037ef52 100644
--- a/target-lm32/cpu.h
+++ b/target-lm32/cpu.h
@@ -205,7 +205,7 @@ void cpu_lm32_set_phys_msb_ignore(CPUState *env, int value);
 #define CPU_SAVE_VERSION 1
 
 int cpu_lm32_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
-                            int mmu_idx, int is_softmmu);
+                              int mmu_idx);
 #define cpu_handle_mmu_fault cpu_lm32_handle_mmu_fault
 
 #if defined(CONFIG_USER_ONLY)
diff --git a/target-lm32/helper.c b/target-lm32/helper.c
index e79428d..48c402e 100644
--- a/target-lm32/helper.c
+++ b/target-lm32/helper.c
@@ -26,7 +26,7 @@
 #include "host-utils.h"
 
 int cpu_lm32_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
-                               int mmu_idx, int is_softmmu)
+                              int mmu_idx)
 {
     int prot;
 
diff --git a/target-lm32/op_helper.c b/target-lm32/op_helper.c
index 32b9a03..557da6c 100644
--- a/target-lm32/op_helper.c
+++ b/target-lm32/op_helper.c
@@ -87,7 +87,7 @@ void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
     saved_env = env;
     env = cpu_single_env;
 
-    ret = cpu_lm32_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    ret = cpu_lm32_handle_mmu_fault(env, addr, is_write, mmu_idx);
     if (unlikely(ret)) {
         if (retaddr) {
             /* now we have a real cpu fault */
diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h
index e0f9b32..0667f82 100644
--- a/target-m68k/cpu.h
+++ b/target-m68k/cpu.h
@@ -231,7 +231,7 @@ static inline int cpu_mmu_index (CPUState *env)
 }
 
 int cpu_m68k_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
-                              int mmu_idx, int is_softmmu);
+                              int mmu_idx);
 #define cpu_handle_mmu_fault cpu_m68k_handle_mmu_fault
 
 #if defined(CONFIG_USER_ONLY)
diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index a936fe7..7ca75fb 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -344,7 +344,7 @@ void m68k_switch_sp(CPUM68KState *env)
 #if defined(CONFIG_USER_ONLY)
 
 int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                               int mmu_idx, int is_softmmu)
+                               int mmu_idx)
 {
     env->exception_index = EXCP_ACCESS;
     env->mmu.ar = address;
@@ -362,7 +362,7 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
 }
 
 int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                               int mmu_idx, int is_softmmu)
+                               int mmu_idx)
 {
     int prot;
 
diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c
index 764b6a0..c66fa0c 100644
--- a/target-m68k/op_helper.c
+++ b/target-m68k/op_helper.c
@@ -66,7 +66,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
        generated code */
     saved_env = env;
     env = cpu_single_env;
-    ret = cpu_m68k_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    ret = cpu_m68k_handle_mmu_fault(env, addr, is_write, mmu_idx);
     if (unlikely(ret)) {
         if (retaddr) {
             /* now we have a real cpu fault */
diff --git a/target-microblaze/cpu.h b/target-microblaze/cpu.h
index 76f4fc4..a81da62 100644
--- a/target-microblaze/cpu.h
+++ b/target-microblaze/cpu.h
@@ -309,7 +309,7 @@ static inline int cpu_mmu_index (CPUState *env)
 }
 
 int cpu_mb_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
-                            int mmu_idx, int is_softmmu);
+                            int mmu_idx);
 #define cpu_handle_mmu_fault cpu_mb_handle_mmu_fault
 
 #if defined(CONFIG_USER_ONLY)
diff --git a/target-microblaze/helper.c b/target-microblaze/helper.c
index 299259c..2cf2802 100644
--- a/target-microblaze/helper.c
+++ b/target-microblaze/helper.c
@@ -37,7 +37,7 @@ void do_interrupt (CPUState *env)
 }
 
 int cpu_mb_handle_mmu_fault(CPUState * env, target_ulong address, int rw,
-                             int mmu_idx, int is_softmmu)
+                            int mmu_idx)
 {
     env->exception_index = 0xaa;
     cpu_dump_state(env, stderr, fprintf, 0);
@@ -47,7 +47,7 @@ int cpu_mb_handle_mmu_fault(CPUState * env, target_ulong address, int rw,
 #else /* !CONFIG_USER_ONLY */
 
 int cpu_mb_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                               int mmu_idx, int is_softmmu)
+                             int mmu_idx)
 {
     unsigned int hit;
     unsigned int mmu_available;
diff --git a/target-microblaze/op_helper.c b/target-microblaze/op_helper.c
index 189c59c..8a7deac 100644
--- a/target-microblaze/op_helper.c
+++ b/target-microblaze/op_helper.c
@@ -54,7 +54,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
     saved_env = env;
     env = cpu_single_env;
 
-    ret = cpu_mb_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    ret = cpu_mb_handle_mmu_fault(env, addr, is_write, mmu_idx);
     if (unlikely(ret)) {
         if (retaddr) {
             /* now we have a real cpu fault */
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index 030f499..c5f70fa 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -636,7 +636,7 @@ void cpu_mips_soft_irq(CPUState *env, int irq, int level);
 
 /* helper.c */
 int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                               int mmu_idx, int is_softmmu);
+                               int mmu_idx);
 #define cpu_handle_mmu_fault cpu_mips_handle_mmu_fault
 void do_interrupt (CPUState *env);
 #if !defined(CONFIG_USER_ONLY)
diff --git a/target-mips/helper.c b/target-mips/helper.c
index ecf6182..024caa2 100644
--- a/target-mips/helper.c
+++ b/target-mips/helper.c
@@ -266,7 +266,7 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
 #endif
 
 int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                               int mmu_idx, int is_softmmu)
+                               int mmu_idx)
 {
 #if !defined(CONFIG_USER_ONLY)
     target_phys_addr_t physical;
@@ -278,8 +278,8 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
 #if 0
     log_cpu_state(env, 0);
 #endif
-    qemu_log("%s pc " TARGET_FMT_lx " ad " TARGET_FMT_lx " rw %d mmu_idx %d smmu %d\n",
-              __func__, env->active_tc.PC, address, rw, mmu_idx, is_softmmu);
+    qemu_log("%s pc " TARGET_FMT_lx " ad " TARGET_FMT_lx " rw %d mmu_idx %d\n",
+              __func__, env->active_tc.PC, address, rw, mmu_idx);
 
     rw &= 1;
 
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 185ae40..056011f 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -2017,7 +2017,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
        generated code */
     saved_env = env;
     env = cpu_single_env;
-    ret = cpu_mips_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    ret = cpu_mips_handle_mmu_fault(env, addr, is_write, mmu_idx);
     if (ret) {
         if (retaddr) {
             /* now we have a real cpu fault */
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index d903366..024eb6f 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1022,7 +1022,7 @@ void cpu_ppc_close (CPUPPCState *s);
 int cpu_ppc_signal_handler (int host_signum, void *pinfo,
                             void *puc);
 int cpu_ppc_handle_mmu_fault (CPUPPCState *env, target_ulong address, int rw,
-                              int mmu_idx, int is_softmmu);
+                              int mmu_idx);
 #define cpu_handle_mmu_fault cpu_ppc_handle_mmu_fault
 #if !defined(CONFIG_USER_ONLY)
 int get_physical_address (CPUPPCState *env, mmu_ctx_t *ctx, target_ulong vaddr,
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index e00b3e6..789e6aa 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -78,7 +78,7 @@ void (*cpu_ppc_hypercall)(CPUState *);
 
 #if defined(CONFIG_USER_ONLY)
 int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                              int mmu_idx, int is_softmmu)
+                              int mmu_idx)
 {
     int exception, error_code;
 
@@ -1658,7 +1658,7 @@ static void booke206_update_mas_tlb_miss(CPUState *env, target_ulong address,
 
 /* Perform address translation */
 int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                              int mmu_idx, int is_softmmu)
+                              int mmu_idx)
 {
     mmu_ctx_t ctx;
     int access_type;
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index 6e100d9..c5e0601 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -3725,7 +3725,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
        generated code */
     saved_env = env;
     env = cpu_single_env;
-    ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx);
     if (unlikely(ret != 0)) {
         if (likely(retaddr)) {
             /* now we have a real cpu fault */
diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index d48a9b7..f8f0c82 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -280,7 +280,7 @@ void do_interrupt (CPUState *env);
 int cpu_s390x_signal_handler(int host_signum, void *pinfo,
                            void *puc);
 int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong address, int rw,
-                              int mmu_idx, int is_softmuu);
+                                int mmu_idx);
 #define cpu_handle_mmu_fault cpu_s390x_handle_mmu_fault
 
 
diff --git a/target-s390x/helper.c b/target-s390x/helper.c
index 443bb1d..db88603 100644
--- a/target-s390x/helper.c
+++ b/target-s390x/helper.c
@@ -110,10 +110,10 @@ void do_interrupt (CPUState *env)
 }
 
 int cpu_s390x_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                              int mmu_idx, int is_softmmu)
+                                int mmu_idx)
 {
-    /* fprintf(stderr,"%s: address 0x%lx rw %d mmu_idx %d is_softmmu %d\n",
-            __FUNCTION__, address, rw, mmu_idx, is_softmmu); */
+    /* fprintf(stderr,"%s: address 0x%lx rw %d mmu_idx %d\n",
+            __FUNCTION__, address, rw, mmu_idx); */
     env->exception_index = EXCP_ADDR;
     env->__excp_addr = address; /* FIXME: find out how this works on a real machine */
     return 1;
@@ -394,14 +394,14 @@ out:
 }
 
 int cpu_s390x_handle_mmu_fault (CPUState *env, target_ulong _vaddr, int rw,
-                                int mmu_idx, int is_softmmu)
+                                int mmu_idx)
 {
     uint64_t asc = env->psw.mask & PSW_MASK_ASC;
     target_ulong vaddr, raddr;
     int prot;
 
-    DPRINTF("%s: address 0x%" PRIx64 " rw %d mmu_idx %d is_softmmu %d\n",
-            __FUNCTION__, _vaddr, rw, mmu_idx, is_softmmu);
+    DPRINTF("%s: address 0x%" PRIx64 " rw %d mmu_idx %d\n",
+            __FUNCTION__, _vaddr, rw, mmu_idx);
 
     _vaddr &= TARGET_PAGE_MASK;
     vaddr = _vaddr;
diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c
index 25a1e81..b3ac630 100644
--- a/target-s390x/op_helper.c
+++ b/target-s390x/op_helper.c
@@ -63,7 +63,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
        generated code */
     saved_env = env;
     env = cpu_single_env;
-    ret = cpu_s390x_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    ret = cpu_s390x_handle_mmu_fault(env, addr, is_write, mmu_idx);
     if (unlikely(ret != 0)) {
         if (likely(retaddr)) {
             /* now we have a real cpu fault */
diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h
index 00e32f2..7d7fdde 100644
--- a/target-sh4/cpu.h
+++ b/target-sh4/cpu.h
@@ -194,7 +194,7 @@ int cpu_sh4_exec(CPUSH4State * s);
 int cpu_sh4_signal_handler(int host_signum, void *pinfo,
                            void *puc);
 int cpu_sh4_handle_mmu_fault(CPUSH4State * env, target_ulong address, int rw,
-			     int mmu_idx, int is_softmmu);
+                             int mmu_idx);
 #define cpu_handle_mmu_fault cpu_sh4_handle_mmu_fault
 void do_interrupt(CPUSH4State * env);
 
diff --git a/target-sh4/helper.c b/target-sh4/helper.c
index 20e9b13..5a1e15e 100644
--- a/target-sh4/helper.c
+++ b/target-sh4/helper.c
@@ -34,7 +34,7 @@ void do_interrupt (CPUState *env)
 }
 
 int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw,
-			     int mmu_idx, int is_softmmu)
+                             int mmu_idx)
 {
     env->tea = address;
     env->exception_index = -1;
@@ -440,7 +440,7 @@ static int get_physical_address(CPUState * env, target_ulong * physical,
 }
 
 int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw,
-			     int mmu_idx, int is_softmmu)
+                             int mmu_idx)
 {
     target_ulong physical;
     int prot, ret, access_type;
diff --git a/target-sh4/op_helper.c b/target-sh4/op_helper.c
index 568bf0d..163858f 100644
--- a/target-sh4/op_helper.c
+++ b/target-sh4/op_helper.c
@@ -64,7 +64,7 @@ void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
        generated code */
     saved_env = env;
     env = cpu_single_env;
-    ret = cpu_sh4_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    ret = cpu_sh4_handle_mmu_fault(env, addr, is_write, mmu_idx);
     if (ret) {
         /* now we have a real cpu fault */
         cpu_restore_state_from_retaddr(retaddr);
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index a51863c..8654f26 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -490,7 +490,7 @@ CPUSPARCState *cpu_sparc_init(const char *cpu_model);
 void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu);
 void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf);
 int cpu_sparc_handle_mmu_fault(CPUSPARCState *env1, target_ulong address, int rw,
-                               int mmu_idx, int is_softmmu);
+                               int mmu_idx);
 #define cpu_handle_mmu_fault cpu_sparc_handle_mmu_fault
 target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev);
 void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env);
diff --git a/target-sparc/helper.c b/target-sparc/helper.c
index efab885..47110a5 100644
--- a/target-sparc/helper.c
+++ b/target-sparc/helper.c
@@ -42,7 +42,7 @@ static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model);
 #if defined(CONFIG_USER_ONLY)
 
 int cpu_sparc_handle_mmu_fault(CPUState *env1, target_ulong address, int rw,
-                               int mmu_idx, int is_softmmu)
+                               int mmu_idx)
 {
     if (rw & 2)
         env1->exception_index = TT_TFAULT;
@@ -212,7 +212,7 @@ static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
 
 /* Perform address translation */
 int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                              int mmu_idx, int is_softmmu)
+                              int mmu_idx)
 {
     target_phys_addr_t paddr;
     target_ulong vaddr;
@@ -638,7 +638,7 @@ static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
 
 /* Perform address translation */
 int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                              int mmu_idx, int is_softmmu)
+                              int mmu_idx)
 {
     target_ulong virt_addr, vaddr;
     target_phys_addr_t paddr;
diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
index 5aeca2b..d1a8dd9 100644
--- a/target-sparc/op_helper.c
+++ b/target-sparc/op_helper.c
@@ -4237,7 +4237,7 @@ void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
     saved_env = env;
     env = cpu_single_env;
 
-    ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+    ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, mmu_idx);
     if (ret) {
         cpu_restore_state2(retaddr);
         cpu_loop_exit(env);
diff --git a/target-unicore32/cpu.h b/target-unicore32/cpu.h
index 9817607..b4e72cf 100644
--- a/target-unicore32/cpu.h
+++ b/target-unicore32/cpu.h
@@ -130,7 +130,7 @@ CPUState *uc32_cpu_init(const char *cpu_model);
 int uc32_cpu_exec(CPUState *s);
 int uc32_cpu_signal_handler(int host_signum, void *pinfo, void *puc);
 int uc32_cpu_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
-                              int mmu_idx, int is_softmuu);
+                              int mmu_idx);
 
 #define CPU_SAVE_VERSION 2
 
diff --git a/target-unicore32/helper.c b/target-unicore32/helper.c
index 02707d5..8edfcb7 100644
--- a/target-unicore32/helper.c
+++ b/target-unicore32/helper.c
@@ -104,7 +104,7 @@ void do_interrupt(CPUState *env)
 }
 
 int uc32_cpu_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
-                              int mmu_idx, int is_softmmu)
+                              int mmu_idx)
 {
     env->exception_index = UC32_EXCP_TRAP;
     env->cp0.c4_faultaddr = address;
diff --git a/user-exec.c b/user-exec.c
index 14c0f25..abf6885 100644
--- a/user-exec.c
+++ b/user-exec.c
@@ -102,7 +102,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
     }
 
     /* see if it is an MMU fault */
-    ret = cpu_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
+    ret = cpu_handle_mmu_fault(env, address, is_write, MMU_USER_IDX);
     if (ret < 0) {
         return 0; /* not an MMU fault */
     }
commit 548f66db33b91bf305c4e5228bb29585701ab58d
Author: Artyom Tarasenko <atar4qemu at gmail.com>
Date:   Sat Aug 6 17:01:24 2011 +0200

    Fix handling of conditional branches in delay slot of a conditional branch
    
    Check whether dc->npc is dynamic before using its value for branch.
    
    Signed-off-by: Artyom Tarasenko <atar4qemu at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 958fbc5..dee67b3 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -1286,7 +1286,6 @@ static inline void gen_cond_reg(TCGv r_dst, int cond, TCGv r_src)
 }
 #endif
 
-/* XXX: potentially incorrect if dynamic npc */
 static void do_branch(DisasContext *dc, int32_t offset, uint32_t insn, int cc,
                       TCGv r_cond)
 {
@@ -1321,13 +1320,17 @@ static void do_branch(DisasContext *dc, int32_t offset, uint32_t insn, int cc,
         } else {
             dc->pc = dc->npc;
             dc->jump_pc[0] = target;
-            dc->jump_pc[1] = dc->npc + 4;
-            dc->npc = JUMP_PC;
+            if (unlikely(dc->npc == DYNAMIC_PC)) {
+                dc->jump_pc[1] = DYNAMIC_PC;
+                tcg_gen_addi_tl(cpu_pc, cpu_npc, 4);
+            } else {
+                dc->jump_pc[1] = dc->npc + 4;
+                dc->npc = JUMP_PC;
+            }
         }
     }
 }
 
-/* XXX: potentially incorrect if dynamic npc */
 static void do_fbranch(DisasContext *dc, int32_t offset, uint32_t insn, int cc,
                       TCGv r_cond)
 {
@@ -1362,14 +1365,18 @@ static void do_fbranch(DisasContext *dc, int32_t offset, uint32_t insn, int cc,
         } else {
             dc->pc = dc->npc;
             dc->jump_pc[0] = target;
-            dc->jump_pc[1] = dc->npc + 4;
-            dc->npc = JUMP_PC;
+            if (unlikely(dc->npc == DYNAMIC_PC)) {
+                dc->jump_pc[1] = DYNAMIC_PC;
+                tcg_gen_addi_tl(cpu_pc, cpu_npc, 4);
+            } else {
+                dc->jump_pc[1] = dc->npc + 4;
+                dc->npc = JUMP_PC;
+            }
         }
     }
 }
 
 #ifdef TARGET_SPARC64
-/* XXX: potentially incorrect if dynamic npc */
 static void do_branch_reg(DisasContext *dc, int32_t offset, uint32_t insn,
                           TCGv r_cond, TCGv r_reg)
 {
@@ -1384,8 +1391,13 @@ static void do_branch_reg(DisasContext *dc, int32_t offset, uint32_t insn,
     } else {
         dc->pc = dc->npc;
         dc->jump_pc[0] = target;
-        dc->jump_pc[1] = dc->npc + 4;
-        dc->npc = JUMP_PC;
+        if (unlikely(dc->npc == DYNAMIC_PC)) {
+            dc->jump_pc[1] = DYNAMIC_PC;
+            tcg_gen_addi_tl(cpu_pc, cpu_npc, 4);
+        } else {
+            dc->jump_pc[1] = dc->npc + 4;
+            dc->npc = JUMP_PC;
+        }
     }
 }
 
commit 6546bc3713035dff7b5840f6d15f43b99c834a4e
Merge: b3198cc... e3a110b...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Aug 5 12:17:04 2011 -0500

    Merge remote-tracking branch 'kiszka/queues/slirp' into staging

commit b3198cc2eff816b6305bb5aba5b2a48f1cd944f4
Author: Stuart Yoder <stuart.yoder at freescale.com>
Date:   Thu Aug 4 17:10:08 2011 -0500

    when overriding default tool names don't add cross-prefix
    
    When overriding a tool name via a shell variable, don't
    tack on the cross-prefix.  This specifically allows the
    pkg-config command to be overridden and work where it
    does not exist in some cross build environments.
    
    Signed-off-by: Stuart Yoder <stuart.yoder at freescale.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/configure b/configure
index 408d454..0c67a4a 100755
--- a/configure
+++ b/configure
@@ -220,14 +220,14 @@ done
 # Using uname is really, really broken.  Once we have the right set of checks
 # we can eliminate it's usage altogether
 
-cc="${cross_prefix}${CC-gcc}"
-ar="${cross_prefix}${AR-ar}"
-objcopy="${cross_prefix}${OBJCOPY-objcopy}"
-ld="${cross_prefix}${LD-ld}"
-strip="${cross_prefix}${STRIP-strip}"
-windres="${cross_prefix}${WINDRES-windres}"
-pkg_config="${cross_prefix}${PKG_CONFIG-pkg-config}"
-sdl_config="${cross_prefix}${SDL_CONFIG-sdl-config}"
+cc="${CC-${cross_prefix}gcc}"
+ar="${AR-${cross_prefix}ar}"
+objcopy="${OBJCOPY-${cross_prefix}objcopy}"
+ld="${LD-${cross_prefix}ld}"
+strip="${STRIP-${cross_prefix}strip}"
+windres="${WINDRES-${cross_prefix}windres}"
+pkg_config="${PKG_CONFIG-${cross_prefix}pkg-config}"
+sdl_config="${SDL_CONFIG-${cross_prefix}sdl-config}"
 
 # default flags for all hosts
 QEMU_CFLAGS="-fno-strict-aliasing $QEMU_CFLAGS"
commit 84ec65520bbcc249b50ba9ab3c2c29fcc4ea95b0
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Fri Aug 5 09:11:26 2011 +0200

    Reorganize and fix monitor resume after migration
    
    If migration failed in migrate_fd_put_buffer, the monitor may have been
    resumed not only in the error path of that function but also once again
    in migrate_fd_put_ready which is called unconditionally by
    migrate_fd_connect.
    
    Fix this by establishing a cleaner policy: the monitor shall be resumed
    when the migration file is closed, either via callback
    (migrate_fd_close) or in migrate_fd_cleanup if no file is open (i.e. no
    callback invoked).
    
    Reported-By: Michael Tokarev <mjt at tls.msk.ru>
    Tested-By: Michael Tokarev <mjt at tls.msk.ru>
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/migration.c b/migration.c
index 2a15b98..756fa62 100644
--- a/migration.c
+++ b/migration.c
@@ -292,18 +292,17 @@ int migrate_fd_cleanup(FdMigrationState *s)
             ret = -1;
         }
         s->file = NULL;
+    } else {
+        if (s->mon) {
+            monitor_resume(s->mon);
+        }
     }
 
-    if (s->fd != -1)
+    if (s->fd != -1) {
         close(s->fd);
-
-    /* Don't resume monitor until we've flushed all of the buffers */
-    if (s->mon) {
-        monitor_resume(s->mon);
+        s->fd = -1;
     }
 
-    s->fd = -1;
-
     return ret;
 }
 
@@ -330,9 +329,6 @@ ssize_t migrate_fd_put_buffer(void *opaque, const void *data, size_t size)
     if (ret == -EAGAIN) {
         qemu_set_fd_handler2(s->fd, NULL, NULL, migrate_fd_put_notify, s);
     } else if (ret < 0) {
-        if (s->mon) {
-            monitor_resume(s->mon);
-        }
         s->state = MIG_STATE_ERROR;
         notifier_list_notify(&migration_state_notifiers, NULL);
     }
@@ -458,6 +454,9 @@ int migrate_fd_close(void *opaque)
 {
     FdMigrationState *s = opaque;
 
+    if (s->mon) {
+        monitor_resume(s->mon);
+    }
     qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
     return s->close(s);
 }
commit 2da8bb92fb128e686dc9e055defbc5652f7c001d
Author: Isaku Yamahata <yamahata at valinux.co.jp>
Date:   Tue Aug 2 10:59:13 2011 +0900

    qdev: Eliminate duplicate reset
    
    qbus_reset_all_fn was registered twice, so a lot of device reset
    functions were also called twice when QEMU started.
    Which was introduced by 80376c3fc2c38fdd45354e4b0eb45031f35587ed
    This patch fixes it by making the main_system_bus creation not register
    reset handler.
    
    Cc: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
    Tested-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/qdev.c b/hw/qdev.c
index b4ea8e1..6819537 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -36,6 +36,7 @@ static bool qdev_hot_removed = false;
 
 /* This is a nasty hack to allow passing a NULL bus to qdev_create.  */
 static BusState *main_system_bus;
+static void main_system_bus_create(void);
 
 DeviceInfo *device_info_list;
 
@@ -328,8 +329,7 @@ static int qdev_reset_one(DeviceState *dev, void *opaque)
 BusState *sysbus_get_default(void)
 {
     if (!main_system_bus) {
-        main_system_bus = qbus_create(&system_bus_info, NULL,
-                                      "main-system-bus");
+        main_system_bus_create();
     }
     return main_system_bus;
 }
@@ -784,6 +784,16 @@ BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
     return bus;
 }
 
+static void main_system_bus_create(void)
+{
+    /* assign main_system_bus before qbus_create_inplace()
+     * in order to make "if (bus != main_system_bus)" work */
+    main_system_bus = qemu_mallocz(system_bus_info.size);
+    main_system_bus->qdev_allocated = 1;
+    qbus_create_inplace(main_system_bus, &system_bus_info, NULL,
+                        "main-system-bus");
+}
+
 void qbus_free(BusState *bus)
 {
     DeviceState *dev;
commit d5ab9713d2d4037fd56b0adddd26c8d4dc11cf09
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Tue Aug 2 16:10:21 2011 +0200

    Avoid allocating TCG resources in non-TCG mode
    
    Do not allocate TCG-only resources like the translation buffer when
    running over KVM or XEN. Saves a "few" bytes in the qemu address space
    and is also conceptually cleaner.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/bsd-user/main.c b/bsd-user/main.c
index a63b877..cc7d4a3 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -905,7 +905,8 @@ int main(int argc, char **argv)
         cpu_model = "any";
 #endif
     }
-    cpu_exec_init_all(0);
+    tcg_exec_init(0);
+    cpu_exec_init_all();
     /* NOTE: we need to init the CPU at this stage to get
        qemu_host_page_size */
     env = cpu_init(cpu_model);
diff --git a/darwin-user/main.c b/darwin-user/main.c
index 72307ad..1a881a0 100644
--- a/darwin-user/main.c
+++ b/darwin-user/main.c
@@ -852,8 +852,8 @@ int main(int argc, char **argv)
 #error unsupported CPU
 #endif
     }
-    
-    cpu_exec_init_all(0);
+    tcg_exec_init(0);
+    cpu_exec_init_all();
     /* NOTE: we need to init the CPU at this stage to get
        qemu_host_page_size */
     env = cpu_init(cpu_model);
diff --git a/exec.c b/exec.c
index 751fd89..5bc9203 100644
--- a/exec.c
+++ b/exec.c
@@ -570,16 +570,12 @@ static void code_gen_alloc(unsigned long tb_size)
 /* Must be called before using the QEMU cpus. 'tb_size' is the size
    (in bytes) allocated to the translation buffer. Zero means default
    size. */
-void cpu_exec_init_all(unsigned long tb_size)
+void tcg_exec_init(unsigned long tb_size)
 {
     cpu_gen_init();
     code_gen_alloc(tb_size);
     code_gen_ptr = code_gen_buffer;
     page_init();
-#if !defined(CONFIG_USER_ONLY)
-    memory_map_init();
-    io_mem_init();
-#endif
 #if !defined(CONFIG_USER_ONLY) || !defined(CONFIG_USE_GUEST_BASE)
     /* There's no guest base to take into account, so go ahead and
        initialize the prologue now.  */
@@ -587,6 +583,19 @@ void cpu_exec_init_all(unsigned long tb_size)
 #endif
 }
 
+bool tcg_enabled(void)
+{
+    return code_gen_buffer != NULL;
+}
+
+void cpu_exec_init_all(void)
+{
+#if !defined(CONFIG_USER_ONLY)
+    memory_map_init();
+    io_mem_init();
+#endif
+}
+
 #if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
 
 static int cpu_common_post_load(void *opaque, int version_id)
diff --git a/linux-user/main.c b/linux-user/main.c
index 6a8f4bd..8e15474 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -3117,7 +3117,8 @@ int main(int argc, char **argv, char **envp)
         cpu_model = "any";
 #endif
     }
-    cpu_exec_init_all(0);
+    tcg_exec_init(0);
+    cpu_exec_init_all();
     /* NOTE: we need to init the CPU at this stage to get
        qemu_host_page_size */
     env = cpu_init(cpu_model);
diff --git a/qemu-common.h b/qemu-common.h
index afbd04d..0fdecf1 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -270,7 +270,10 @@ typedef struct QEMUSGList QEMUSGList;
 
 typedef uint64_t pcibus_t;
 
-void cpu_exec_init_all(unsigned long tb_size);
+void tcg_exec_init(unsigned long tb_size);
+bool tcg_enabled(void);
+
+void cpu_exec_init_all(void);
 
 /* CPU save/load.  */
 void cpu_save(QEMUFile *f, void *opaque);
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 182009a..3332195 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -1243,8 +1243,8 @@ CPUX86State *cpu_x86_init(const char *cpu_model)
     cpu_exec_init(env);
     env->cpu_model_str = cpu_model;
 
-    /* init various static tables */
-    if (!inited) {
+    /* init various static tables used in TCG mode */
+    if (tcg_enabled() && !inited) {
         inited = 1;
         optimize_flags_init();
 #ifndef CONFIG_USER_ONLY
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 176128a..e00b3e6 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -3091,7 +3091,9 @@ CPUPPCState *cpu_ppc_init (const char *cpu_model)
 
     env = qemu_mallocz(sizeof(CPUPPCState));
     cpu_exec_init(env);
-    ppc_translate_init();
+    if (tcg_enabled()) {
+        ppc_translate_init();
+    }
     env->cpu_model_str = cpu_model;
     cpu_ppc_register_internal(env, def);
 
diff --git a/target-s390x/helper.c b/target-s390x/helper.c
index 1ce7079..443bb1d 100644
--- a/target-s390x/helper.c
+++ b/target-s390x/helper.c
@@ -81,7 +81,7 @@ CPUS390XState *cpu_s390x_init(const char *cpu_model)
 
     env = qemu_mallocz(sizeof(CPUS390XState));
     cpu_exec_init(env);
-    if (!inited) {
+    if (tcg_enabled() && !inited) {
         inited = 1;
         s390x_translate_init();
     }
diff --git a/vl.c b/vl.c
index 426cea7..c714127 100644
--- a/vl.c
+++ b/vl.c
@@ -265,6 +265,7 @@ int kvm_allowed = 0;
 int xen_allowed = 0;
 uint32_t xen_domid;
 enum xen_mode xen_mode = XEN_EMULATE;
+static int tcg_tb_size;
 
 static int default_serial = 1;
 static int default_parallel = 1;
@@ -1932,6 +1933,7 @@ static QEMUMachine *machine_parse(const char *name)
 
 static int tcg_init(void)
 {
+    tcg_exec_init(tcg_tb_size * 1024 * 1024);
     return 0;
 }
 
@@ -2092,7 +2094,6 @@ int main(int argc, char **argv, char **envp)
     const char *loadvm = NULL;
     QEMUMachine *machine;
     const char *cpu_model;
-    int tb_size;
     const char *pid_file = NULL;
     const char *incoming = NULL;
 #ifdef CONFIG_VNC
@@ -2132,7 +2133,6 @@ int main(int argc, char **argv, char **envp)
     nb_numa_nodes = 0;
     nb_nics = 0;
 
-    tb_size = 0;
     autostart= 1;
 
     /* first pass of option parsing */
@@ -2847,9 +2847,10 @@ int main(int argc, char **argv, char **envp)
                 configure_rtc(opts);
                 break;
             case QEMU_OPTION_tb_size:
-                tb_size = strtol(optarg, NULL, 0);
-                if (tb_size < 0)
-                    tb_size = 0;
+                tcg_tb_size = strtol(optarg, NULL, 0);
+                if (tcg_tb_size < 0) {
+                    tcg_tb_size = 0;
+                }
                 break;
             case QEMU_OPTION_icount:
                 icount_option = optarg;
@@ -3123,8 +3124,7 @@ int main(int argc, char **argv, char **envp)
         }
     }
 
-    /* init the dynamic translator */
-    cpu_exec_init_all(tb_size * 1024 * 1024);
+    cpu_exec_init_all();
 
     bdrv_init_with_whitelist();
 
commit 8417cebfda193c7f9ca70be5e308eaa92cf84b94
Author: Avi Kivity <avi at redhat.com>
Date:   Wed Aug 3 11:56:14 2011 +0300

    memory: use signed arithmetic
    
    When trying to map an alias of a ram region, where the alias starts at
    address A and we map it into address B, and A > B, we had an arithmetic
    underflow.  Because we use unsigned arithmetic, the underflow converted
    into a large number which failed addrrange_intersects() tests.
    
    The concrete example which triggered this was cirrus vga mapping
    the framebuffer at offsets 0xc0000-0xc7fff (relative to the start of
    the framebuffer) into offsets 0xa0000 (relative to system addres space
    start).
    
    With our favorite analogy of a windowing system, this is equivalent to
    dragging a subwindow off the left edge of the screen, and failing to clip
    it into its parent window which is on screen.
    
    Fix by switching to signed arithmetic.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/exec.c b/exec.c
index 476b507..751fd89 100644
--- a/exec.c
+++ b/exec.c
@@ -3818,7 +3818,7 @@ static void io_mem_init(void)
 static void memory_map_init(void)
 {
     system_memory = qemu_malloc(sizeof(*system_memory));
-    memory_region_init(system_memory, "system", UINT64_MAX);
+    memory_region_init(system_memory, "system", INT64_MAX);
     set_system_memory_map(system_memory);
 }
 
diff --git a/memory.c b/memory.c
index 5f20320..be891c6 100644
--- a/memory.c
+++ b/memory.c
@@ -22,12 +22,17 @@ unsigned memory_region_transaction_depth = 0;
 
 typedef struct AddrRange AddrRange;
 
+/*
+ * Note using signed integers limits us to physical addresses at most
+ * 63 bits wide.  They are needed for negative offsetting in aliases
+ * (large MemoryRegion::alias_offset).
+ */
 struct AddrRange {
-    uint64_t start;
-    uint64_t size;
+    int64_t start;
+    int64_t size;
 };
 
-static AddrRange addrrange_make(uint64_t start, uint64_t size)
+static AddrRange addrrange_make(int64_t start, int64_t size)
 {
     return (AddrRange) { start, size };
 }
@@ -37,7 +42,7 @@ static bool addrrange_equal(AddrRange r1, AddrRange r2)
     return r1.start == r2.start && r1.size == r2.size;
 }
 
-static uint64_t addrrange_end(AddrRange r)
+static int64_t addrrange_end(AddrRange r)
 {
     return r.start + r.size;
 }
@@ -56,9 +61,9 @@ static bool addrrange_intersects(AddrRange r1, AddrRange r2)
 
 static AddrRange addrrange_intersection(AddrRange r1, AddrRange r2)
 {
-    uint64_t start = MAX(r1.start, r2.start);
+    int64_t start = MAX(r1.start, r2.start);
     /* off-by-one arithmetic to prevent overflow */
-    uint64_t end = MIN(addrrange_end(r1) - 1, addrrange_end(r2) - 1);
+    int64_t end = MIN(addrrange_end(r1) - 1, addrrange_end(r2) - 1);
     return addrrange_make(start, end - start + 1);
 }
 
@@ -411,8 +416,8 @@ static void render_memory_region(FlatView *view,
     MemoryRegion *subregion;
     unsigned i;
     target_phys_addr_t offset_in_region;
-    uint64_t remain;
-    uint64_t now;
+    int64_t remain;
+    int64_t now;
     FlatRange fr;
     AddrRange tmp;
 
@@ -486,7 +491,7 @@ static FlatView generate_memory_topology(MemoryRegion *mr)
 
     flatview_init(&view);
 
-    render_memory_region(&view, mr, 0, addrrange_make(0, UINT64_MAX));
+    render_memory_region(&view, mr, 0, addrrange_make(0, INT64_MAX));
     flatview_simplify(&view);
 
     return view;
commit 39b796f28c7b42cbecdba56612b5f9c505572f07
Author: Avi Kivity <avi at redhat.com>
Date:   Sun Jul 31 22:47:58 2011 +0300

    memory: synchronize dirty bitmap before unmapping a range
    
    When a range is being unmapped, ask accelerators (e.g. kvm) to synchronize the
    dirty bitmap to avoid losing information forever.
    
    Fixes grub2 screen update.
    
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/memory.c b/memory.c
index 5c6e63d..5f20320 100644
--- a/memory.c
+++ b/memory.c
@@ -245,6 +245,10 @@ static void as_memory_range_add(AddressSpace *as, FlatRange *fr)
 
 static void as_memory_range_del(AddressSpace *as, FlatRange *fr)
 {
+    if (fr->dirty_log_mask) {
+        cpu_physical_sync_dirty_bitmap(fr->addr.start,
+                                       fr->addr.start + fr->addr.size);
+    }
     cpu_register_physical_memory(fr->addr.start, fr->addr.size,
                                  IO_MEM_UNASSIGNED);
 }
commit 9510a486381c073a98d96db85b1102313fea9e03
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Sat Jul 30 11:39:18 2011 +0200

    sdl: Refactor sdl_send_mouse_event
    
    Replace width/height globals with the identical values from real_screen,
    refactor the function according to our coding style.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/ui/sdl.c b/ui/sdl.c
index e5b8a5f..30cde86 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -49,7 +49,6 @@ static int gui_key_modifier_pressed;
 static int gui_keysym;
 static int gui_grab_code = KMOD_LALT | KMOD_LCTRL;
 static uint8_t modifiers_state[256];
-static int width, height;
 static SDL_Cursor *sdl_cursor_normal;
 static SDL_Cursor *sdl_cursor_hidden;
 static int absolute_enabled = 0;
@@ -93,7 +92,7 @@ static void sdl_setdata(DisplayState *ds)
                                             ds->surface->pf.bmask, ds->surface->pf.amask);
 }
 
-static void do_sdl_resize(int new_width, int new_height, int bpp)
+static void do_sdl_resize(int width, int height, int bpp)
 {
     int flags;
 
@@ -108,8 +107,6 @@ static void do_sdl_resize(int new_width, int new_height, int bpp)
     if (gui_noframe)
         flags |= SDL_NOFRAME;
 
-    width = new_width;
-    height = new_height;
     real_screen = SDL_SetVideoMode(width, height, bpp, flags);
     if (!real_screen) {
 	fprintf(stderr, "Could not open SDL display (%dx%dx%d): %s\n", width, 
@@ -501,18 +498,21 @@ static void sdl_mouse_mode_change(Notifier *notify, void *data)
 
 static void sdl_send_mouse_event(int dx, int dy, int dz, int x, int y, int state)
 {
-    int buttons;
-    buttons = 0;
-    if (state & SDL_BUTTON(SDL_BUTTON_LEFT))
+    int buttons = 0;
+
+    if (state & SDL_BUTTON(SDL_BUTTON_LEFT)) {
         buttons |= MOUSE_EVENT_LBUTTON;
-    if (state & SDL_BUTTON(SDL_BUTTON_RIGHT))
+    }
+    if (state & SDL_BUTTON(SDL_BUTTON_RIGHT)) {
         buttons |= MOUSE_EVENT_RBUTTON;
-    if (state & SDL_BUTTON(SDL_BUTTON_MIDDLE))
+    }
+    if (state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) {
         buttons |= MOUSE_EVENT_MBUTTON;
+    }
 
     if (kbd_mouse_is_absolute()) {
-       dx = x * 0x7FFF / (width - 1);
-       dy = y * 0x7FFF / (height - 1);
+        dx = x * 0x7FFF / (real_screen->w - 1);
+        dy = y * 0x7FFF / (real_screen->h - 1);
     } else if (guest_cursor) {
         x -= guest_x;
         y -= guest_y;
commit 1ae1caf1c54c8fe93bdaf557ea07cf5d26156b2a
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Sat Jul 30 11:39:17 2011 +0200

    sdl: Factor out event handlers from sdl_refresh
    
    No functional changes.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/ui/sdl.c b/ui/sdl.c
index fc63c8e..e5b8a5f 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -582,11 +582,274 @@ static void absolute_mouse_grab(void)
     }
 }
 
-static void sdl_refresh(DisplayState *ds)
+static void handle_keydown(DisplayState *ds, SDL_Event *ev)
 {
-    SDL_Event ev1, *ev = &ev1;
     int mod_state;
+    int keycode;
+
+    if (alt_grab) {
+        mod_state = (SDL_GetModState() & (gui_grab_code | KMOD_LSHIFT)) ==
+                    (gui_grab_code | KMOD_LSHIFT);
+    } else if (ctrl_grab) {
+        mod_state = (SDL_GetModState() & KMOD_RCTRL) == KMOD_RCTRL;
+    } else {
+        mod_state = (SDL_GetModState() & gui_grab_code) == gui_grab_code;
+    }
+    gui_key_modifier_pressed = mod_state;
+
+    if (gui_key_modifier_pressed) {
+        keycode = sdl_keyevent_to_keycode(&ev->key);
+        switch (keycode) {
+        case 0x21: /* 'f' key on US keyboard */
+            toggle_full_screen(ds);
+            gui_keysym = 1;
+            break;
+        case 0x16: /* 'u' key on US keyboard */
+            if (scaling_active) {
+                scaling_active = 0;
+                sdl_resize(ds);
+                vga_hw_invalidate();
+                vga_hw_update();
+            }
+            gui_keysym = 1;
+            break;
+        case 0x02 ... 0x0a: /* '1' to '9' keys */
+            /* Reset the modifiers sent to the current console */
+            reset_keys();
+            console_select(keycode - 0x02);
+            gui_keysym = 1;
+            if (gui_fullscreen) {
+                break;
+            }
+            if (!is_graphic_console()) {
+                /* release grab if going to a text console */
+                if (gui_grab) {
+                    sdl_grab_end();
+                } else if (absolute_enabled) {
+                    sdl_show_cursor();
+                }
+            } else if (absolute_enabled) {
+                sdl_hide_cursor();
+                absolute_mouse_grab();
+            }
+            break;
+        case 0x1b: /* '+' */
+        case 0x35: /* '-' */
+            if (!gui_fullscreen) {
+                int width = MAX(real_screen->w + (keycode == 0x1b ? 50 : -50),
+                                160);
+                int height = (ds_get_height(ds) * width) / ds_get_width(ds);
+
+                sdl_scale(ds, width, height);
+                vga_hw_invalidate();
+                vga_hw_update();
+                gui_keysym = 1;
+            }
+        default:
+            break;
+        }
+    } else if (!is_graphic_console()) {
+        int keysym = 0;
+
+        if (ev->key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL)) {
+            switch (ev->key.keysym.sym) {
+            case SDLK_UP:
+                keysym = QEMU_KEY_CTRL_UP;
+                break;
+            case SDLK_DOWN:
+                keysym = QEMU_KEY_CTRL_DOWN;
+                break;
+            case SDLK_LEFT:
+                keysym = QEMU_KEY_CTRL_LEFT;
+                break;
+            case SDLK_RIGHT:
+                keysym = QEMU_KEY_CTRL_RIGHT;
+                break;
+            case SDLK_HOME:
+                keysym = QEMU_KEY_CTRL_HOME;
+                break;
+            case SDLK_END:
+                keysym = QEMU_KEY_CTRL_END;
+                break;
+            case SDLK_PAGEUP:
+                keysym = QEMU_KEY_CTRL_PAGEUP;
+                break;
+            case SDLK_PAGEDOWN:
+                keysym = QEMU_KEY_CTRL_PAGEDOWN;
+                break;
+            default:
+                break;
+            }
+        } else {
+            switch (ev->key.keysym.sym) {
+            case SDLK_UP:
+                keysym = QEMU_KEY_UP;
+                break;
+            case SDLK_DOWN:
+                keysym = QEMU_KEY_DOWN;
+                break;
+            case SDLK_LEFT:
+                keysym = QEMU_KEY_LEFT;
+                break;
+            case SDLK_RIGHT:
+                keysym = QEMU_KEY_RIGHT;
+                break;
+            case SDLK_HOME:
+                keysym = QEMU_KEY_HOME;
+                break;
+            case SDLK_END:
+                keysym = QEMU_KEY_END;
+                break;
+            case SDLK_PAGEUP:
+                keysym = QEMU_KEY_PAGEUP;
+                break;
+            case SDLK_PAGEDOWN:
+                keysym = QEMU_KEY_PAGEDOWN;
+                break;
+            case SDLK_BACKSPACE:
+                keysym = QEMU_KEY_BACKSPACE;
+                break;
+            case SDLK_DELETE:
+                keysym = QEMU_KEY_DELETE;
+                break;
+            default:
+                break;
+            }
+        }
+        if (keysym) {
+            kbd_put_keysym(keysym);
+        } else if (ev->key.keysym.unicode != 0) {
+            kbd_put_keysym(ev->key.keysym.unicode);
+        }
+    }
+    if (is_graphic_console() && !gui_keysym) {
+        sdl_process_key(&ev->key);
+    }
+}
+
+static void handle_keyup(DisplayState *ds, SDL_Event *ev)
+{
+    int mod_state;
+
+    if (!alt_grab) {
+        mod_state = (ev->key.keysym.mod & gui_grab_code);
+    } else {
+        mod_state = (ev->key.keysym.mod & (gui_grab_code | KMOD_LSHIFT));
+    }
+    if (!mod_state && gui_key_modifier_pressed) {
+        gui_key_modifier_pressed = 0;
+        if (gui_keysym == 0) {
+            /* exit/enter grab if pressing Ctrl-Alt */
+            if (!gui_grab) {
+                /* If the application is not active, do not try to enter grab
+                 * state. It prevents 'SDL_WM_GrabInput(SDL_GRAB_ON)' from
+                 * blocking all the application (SDL bug). */
+                if (is_graphic_console() &&
+                    SDL_GetAppState() & SDL_APPACTIVE) {
+                    sdl_grab_start();
+                }
+            } else if (!gui_fullscreen) {
+                sdl_grab_end();
+            }
+            /* SDL does not send back all the modifiers key, so we must
+             * correct it. */
+            reset_keys();
+            return;
+        }
+        gui_keysym = 0;
+    }
+    if (is_graphic_console() && !gui_keysym) {
+        sdl_process_key(&ev->key);
+    }
+}
+
+static void handle_mousemotion(DisplayState *ds, SDL_Event *ev)
+{
+    int max_x, max_y;
+
+    if (is_graphic_console() &&
+        (kbd_mouse_is_absolute() || absolute_enabled)) {
+        max_x = real_screen->w - 1;
+        max_y = real_screen->h - 1;
+        if (gui_grab && (ev->motion.x == 0 || ev->motion.y == 0 ||
+            ev->motion.x == max_x || ev->motion.y == max_y)) {
+            sdl_grab_end();
+        }
+        if (!gui_grab && SDL_GetAppState() & SDL_APPINPUTFOCUS &&
+            (ev->motion.x > 0 && ev->motion.x < max_x &&
+            ev->motion.y > 0 && ev->motion.y < max_y)) {
+            sdl_grab_start();
+        }
+    }
+    if (gui_grab || kbd_mouse_is_absolute() || absolute_enabled) {
+        sdl_send_mouse_event(ev->motion.xrel, ev->motion.yrel, 0,
+                             ev->motion.x, ev->motion.y, ev->motion.state);
+    }
+}
+
+static void handle_mousebutton(DisplayState *ds, SDL_Event *ev)
+{
     int buttonstate = SDL_GetMouseState(NULL, NULL);
+    SDL_MouseButtonEvent *bev;
+    int dz;
+
+    if (!is_graphic_console()) {
+        return;
+    }
+
+    bev = &ev->button;
+    if (!gui_grab && !kbd_mouse_is_absolute()) {
+        if (ev->type == SDL_MOUSEBUTTONDOWN &&
+            (bev->button == SDL_BUTTON_LEFT)) {
+            /* start grabbing all events */
+            sdl_grab_start();
+        }
+    } else {
+        dz = 0;
+        if (ev->type == SDL_MOUSEBUTTONDOWN) {
+            buttonstate |= SDL_BUTTON(bev->button);
+        } else {
+            buttonstate &= ~SDL_BUTTON(bev->button);
+        }
+#ifdef SDL_BUTTON_WHEELUP
+        if (bev->button == SDL_BUTTON_WHEELUP &&
+            ev->type == SDL_MOUSEBUTTONDOWN) {
+            dz = -1;
+        } else if (bev->button == SDL_BUTTON_WHEELDOWN &&
+                   ev->type == SDL_MOUSEBUTTONDOWN) {
+            dz = 1;
+        }
+#endif
+        sdl_send_mouse_event(0, 0, dz, bev->x, bev->y, buttonstate);
+    }
+}
+
+static void handle_activation(DisplayState *ds, SDL_Event *ev)
+{
+    if (gui_grab && ev->active.state == SDL_APPINPUTFOCUS &&
+        !ev->active.gain && !gui_fullscreen) {
+        sdl_grab_end();
+    }
+    if (!gui_grab && ev->active.gain && is_graphic_console() &&
+        (kbd_mouse_is_absolute() || absolute_enabled)) {
+        absolute_mouse_grab();
+    }
+    if (ev->active.state & SDL_APPACTIVE) {
+        if (ev->active.gain) {
+            /* Back to default interval */
+            dcl->gui_timer_interval = 0;
+            dcl->idle = 0;
+        } else {
+            /* Sleeping interval */
+            dcl->gui_timer_interval = 500;
+            dcl->idle = 1;
+        }
+    }
+}
+
+static void sdl_refresh(DisplayState *ds)
+{
+    SDL_Event ev1, *ev = &ev1;
 
     if (last_vm_running != vm_running) {
         last_vm_running = vm_running;
@@ -602,144 +865,10 @@ static void sdl_refresh(DisplayState *ds)
             sdl_update(ds, 0, 0, real_screen->w, real_screen->h);
             break;
         case SDL_KEYDOWN:
+            handle_keydown(ds, ev);
+            break;
         case SDL_KEYUP:
-            if (ev->type == SDL_KEYDOWN) {
-                if (alt_grab) {
-                    mod_state = (SDL_GetModState() & (gui_grab_code | KMOD_LSHIFT)) ==
-                                (gui_grab_code | KMOD_LSHIFT);
-                } else if (ctrl_grab) {
-                    mod_state = (SDL_GetModState() & KMOD_RCTRL) == KMOD_RCTRL;
-                } else {
-                    mod_state = (SDL_GetModState() & gui_grab_code) ==
-                                gui_grab_code;
-                }
-                gui_key_modifier_pressed = mod_state;
-                if (gui_key_modifier_pressed) {
-                    int keycode;
-                    keycode = sdl_keyevent_to_keycode(&ev->key);
-                    switch(keycode) {
-                    case 0x21: /* 'f' key on US keyboard */
-                        toggle_full_screen(ds);
-                        gui_keysym = 1;
-                        break;
-                    case 0x16: /* 'u' key on US keyboard */
-                        if (scaling_active) {
-                            scaling_active = 0;
-                            sdl_resize(ds);
-                            vga_hw_invalidate();
-                            vga_hw_update();
-                        }
-                        gui_keysym = 1;
-                        break;
-                    case 0x02 ... 0x0a: /* '1' to '9' keys */
-                        /* Reset the modifiers sent to the current console */
-                        reset_keys();
-                        console_select(keycode - 0x02);
-                        gui_keysym = 1;
-                        if (gui_fullscreen) {
-                            break;
-                        }
-                        if (!is_graphic_console()) {
-                            /* release grab if going to a text console */
-                            if (gui_grab) {
-                                sdl_grab_end();
-                            } else if (absolute_enabled) {
-                                sdl_show_cursor();
-                            }
-                        } else if (absolute_enabled) {
-                            sdl_hide_cursor();
-                            absolute_mouse_grab();
-                        }
-                        break;
-                    case 0x1b: /* '+' */
-                    case 0x35: /* '-' */
-                        if (!gui_fullscreen) {
-                            int width = MAX(real_screen->w +
-                                            (keycode == 0x1b ? 50 : -50), 160);
-                            int height = (ds_get_height(ds) * width) /
-                                         ds_get_width(ds);
-
-                            sdl_scale(ds, width, height);
-                            vga_hw_invalidate();
-                            vga_hw_update();
-                            gui_keysym = 1;
-                        }
-                    default:
-                        break;
-                    }
-                } else if (!is_graphic_console()) {
-                    int keysym;
-                    keysym = 0;
-                    if (ev->key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL)) {
-                        switch(ev->key.keysym.sym) {
-                        case SDLK_UP: keysym = QEMU_KEY_CTRL_UP; break;
-                        case SDLK_DOWN: keysym = QEMU_KEY_CTRL_DOWN; break;
-                        case SDLK_LEFT: keysym = QEMU_KEY_CTRL_LEFT; break;
-                        case SDLK_RIGHT: keysym = QEMU_KEY_CTRL_RIGHT; break;
-                        case SDLK_HOME: keysym = QEMU_KEY_CTRL_HOME; break;
-                        case SDLK_END: keysym = QEMU_KEY_CTRL_END; break;
-                        case SDLK_PAGEUP: keysym = QEMU_KEY_CTRL_PAGEUP; break;
-                        case SDLK_PAGEDOWN: keysym = QEMU_KEY_CTRL_PAGEDOWN; break;
-                        default: break;
-                        }
-                    } else {
-                        switch(ev->key.keysym.sym) {
-                        case SDLK_UP: keysym = QEMU_KEY_UP; break;
-                        case SDLK_DOWN: keysym = QEMU_KEY_DOWN; break;
-                        case SDLK_LEFT: keysym = QEMU_KEY_LEFT; break;
-                        case SDLK_RIGHT: keysym = QEMU_KEY_RIGHT; break;
-                        case SDLK_HOME: keysym = QEMU_KEY_HOME; break;
-                        case SDLK_END: keysym = QEMU_KEY_END; break;
-                        case SDLK_PAGEUP: keysym = QEMU_KEY_PAGEUP; break;
-                        case SDLK_PAGEDOWN: keysym = QEMU_KEY_PAGEDOWN; break;
-                        case SDLK_BACKSPACE: keysym = QEMU_KEY_BACKSPACE; break;
-                        case SDLK_DELETE: keysym = QEMU_KEY_DELETE; break;
-                        default: break;
-                        }
-                    }
-                    if (keysym) {
-                        kbd_put_keysym(keysym);
-                    } else if (ev->key.keysym.unicode != 0) {
-                        kbd_put_keysym(ev->key.keysym.unicode);
-                    }
-                }
-            } else if (ev->type == SDL_KEYUP) {
-                if (!alt_grab) {
-                    mod_state = (ev->key.keysym.mod & gui_grab_code);
-                } else {
-                    mod_state = (ev->key.keysym.mod &
-                                 (gui_grab_code | KMOD_LSHIFT));
-                }
-                if (!mod_state) {
-                    if (gui_key_modifier_pressed) {
-                        gui_key_modifier_pressed = 0;
-                        if (gui_keysym == 0) {
-                            /* exit/enter grab if pressing Ctrl-Alt */
-                            if (!gui_grab) {
-                                /* if the application is not active,
-                                   do not try to enter grab state. It
-                                   prevents
-                                   'SDL_WM_GrabInput(SDL_GRAB_ON)'
-                                   from blocking all the application
-                                   (SDL bug). */
-                                if (is_graphic_console() &&
-                                    SDL_GetAppState() & SDL_APPACTIVE) {
-                                    sdl_grab_start();
-                                }
-                            } else if (!gui_fullscreen) {
-                                sdl_grab_end();
-                            }
-                            /* SDL does not send back all the
-                               modifiers key, so we must correct it */
-                            reset_keys();
-                            break;
-                        }
-                        gui_keysym = 0;
-                    }
-                }
-            }
-            if (is_graphic_console() && !gui_keysym)
-                sdl_process_key(&ev->key);
+            handle_keyup(ds, ev);
             break;
         case SDL_QUIT:
             if (!no_quit) {
@@ -748,77 +877,14 @@ static void sdl_refresh(DisplayState *ds)
             }
             break;
         case SDL_MOUSEMOTION:
-            if (is_graphic_console() &&
-                (kbd_mouse_is_absolute() || absolute_enabled)) {
-                int max_x = real_screen->w - 1;
-                int max_y = real_screen->h - 1;
-
-                if (gui_grab &&
-                    (ev->motion.x == 0 || ev->motion.y == 0 ||
-                     ev->motion.x == max_x || ev->motion.y == max_y)) {
-                    sdl_grab_end();
-                }
-                if (!gui_grab && SDL_GetAppState() & SDL_APPINPUTFOCUS &&
-                    (ev->motion.x > 0 && ev->motion.x < max_x &&
-                     ev->motion.y > 0 && ev->motion.y < max_y)) {
-                    sdl_grab_start();
-                }
-            }
-            if (gui_grab || kbd_mouse_is_absolute() ||
-                absolute_enabled) {
-                sdl_send_mouse_event(ev->motion.xrel, ev->motion.yrel, 0,
-                       ev->motion.x, ev->motion.y, ev->motion.state);
-            }
+            handle_mousemotion(ds, ev);
             break;
         case SDL_MOUSEBUTTONDOWN:
         case SDL_MOUSEBUTTONUP:
-            if (is_graphic_console()) {
-                SDL_MouseButtonEvent *bev = &ev->button;
-                if (!gui_grab && !kbd_mouse_is_absolute()) {
-                    if (ev->type == SDL_MOUSEBUTTONDOWN &&
-                        (bev->button == SDL_BUTTON_LEFT)) {
-                        /* start grabbing all events */
-                        sdl_grab_start();
-                    }
-                } else {
-                    int dz;
-                    dz = 0;
-                    if (ev->type == SDL_MOUSEBUTTONDOWN) {
-                        buttonstate |= SDL_BUTTON(bev->button);
-                    } else {
-                        buttonstate &= ~SDL_BUTTON(bev->button);
-                    }
-#ifdef SDL_BUTTON_WHEELUP
-                    if (bev->button == SDL_BUTTON_WHEELUP && ev->type == SDL_MOUSEBUTTONDOWN) {
-                        dz = -1;
-                    } else if (bev->button == SDL_BUTTON_WHEELDOWN && ev->type == SDL_MOUSEBUTTONDOWN) {
-                        dz = 1;
-                    }
-#endif
-                    sdl_send_mouse_event(0, 0, dz, bev->x, bev->y, buttonstate);
-                }
-            }
+            handle_mousebutton(ds, ev);
             break;
         case SDL_ACTIVEEVENT:
-            if (gui_grab && ev->active.state == SDL_APPINPUTFOCUS &&
-                !ev->active.gain && !gui_fullscreen) {
-                sdl_grab_end();
-            }
-            if (!gui_grab && ev->active.gain && is_graphic_console() &&
-                (kbd_mouse_is_absolute() || absolute_enabled)) {
-                absolute_mouse_grab();
-            }
-            if (ev->active.state & SDL_APPACTIVE) {
-                if (ev->active.gain) {
-                    /* Back to default interval */
-                    dcl->gui_timer_interval = 0;
-                    dcl->idle = 0;
-                } else {
-                    /* Sleeping interval */
-                    dcl->gui_timer_interval = 500;
-                    dcl->idle = 1;
-                }
-            }
+            handle_activation(ds, ev);
             break;
         case SDL_VIDEORESIZE:
             sdl_scale(ds, ev->resize.w, ev->resize.h);
commit d6a65ba333ce3af34721e1452a1206233ac2a3e5
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Sat Jul 30 11:39:16 2011 +0200

    sdl: Add zoom hot keys
    
    Allow to enlarge or shrink the screen via CTRL-ALT-+/-. In contrast to
    scaling the window, these controls always preserve the aspect ratio of
    the current console.
    
    CC: Stefano Stabellini <stefano.stabellini at eu.citrix.com>
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/qemu-doc.texi b/qemu-doc.texi
index 47e1991..31199f6 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -288,6 +288,14 @@ then the modifier is Ctrl-Alt-Shift (instead of Ctrl-Alt) and if you use
 @kindex Ctrl-Alt-f
 Toggle full screen
 
+ at item Ctrl-Alt-+
+ at kindex Ctrl-Alt-+
+Enlarge the screen
+
+ at item Ctrl-Alt--
+ at kindex Ctrl-Alt--
+Shrink the screen
+
 @item Ctrl-Alt-u
 @kindex Ctrl-Alt-u
 Restore the screen's un-scaled dimensions
diff --git a/ui/sdl.c b/ui/sdl.c
index e8ac3bb..fc63c8e 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -651,6 +651,19 @@ static void sdl_refresh(DisplayState *ds)
                             absolute_mouse_grab();
                         }
                         break;
+                    case 0x1b: /* '+' */
+                    case 0x35: /* '-' */
+                        if (!gui_fullscreen) {
+                            int width = MAX(real_screen->w +
+                                            (keycode == 0x1b ? 50 : -50), 160);
+                            int height = (ds_get_height(ds) * width) /
+                                         ds_get_width(ds);
+
+                            sdl_scale(ds, width, height);
+                            vga_hw_invalidate();
+                            vga_hw_update();
+                            gui_keysym = 1;
+                        }
                     default:
                         break;
                     }
commit 35b0f237205dc6a5c9aa3eae14f19ef4d37dafcd
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Sat Jul 30 11:39:15 2011 +0200

    sdl: Dynamically grab input in absolute mouse mode
    
    Not grabbing the input means that special keys like ALT+TAB are still
    handled by the host. Improve the usability by grabbing input once the
    mouse is inside the guest screen, provided the SDL window has the input
    focus. Release it again when the mouse is moved to any border. Also grab
    the input when we gain the input focus and the mouse is within the
    screen limits.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/ui/sdl.c b/ui/sdl.c
index 5ad38d5..e8ac3bb 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -490,15 +490,12 @@ static void sdl_mouse_mode_change(Notifier *notify, void *data)
 {
     if (kbd_mouse_is_absolute()) {
         if (!absolute_enabled) {
-            sdl_hide_cursor();
-            if (gui_grab) {
-                sdl_grab_end();
-            }
+            sdl_grab_start();
             absolute_enabled = 1;
         }
     } else if (absolute_enabled) {
-	sdl_show_cursor();
-	absolute_enabled = 0;
+        sdl_grab_end();
+        absolute_enabled = 0;
     }
 }
 
@@ -572,6 +569,19 @@ static void toggle_full_screen(DisplayState *ds)
     vga_hw_update();
 }
 
+static void absolute_mouse_grab(void)
+{
+    int mouse_x, mouse_y;
+
+    if (SDL_GetAppState() & SDL_APPINPUTFOCUS) {
+        SDL_GetMouseState(&mouse_x, &mouse_y);
+        if (mouse_x > 0 && mouse_x < real_screen->w - 1 &&
+            mouse_y > 0 && mouse_y < real_screen->h - 1) {
+            sdl_grab_start();
+        }
+    }
+}
+
 static void sdl_refresh(DisplayState *ds)
 {
     SDL_Event ev1, *ev = &ev1;
@@ -638,6 +648,7 @@ static void sdl_refresh(DisplayState *ds)
                             }
                         } else if (absolute_enabled) {
                             sdl_hide_cursor();
+                            absolute_mouse_grab();
                         }
                         break;
                     default:
@@ -724,6 +735,22 @@ static void sdl_refresh(DisplayState *ds)
             }
             break;
         case SDL_MOUSEMOTION:
+            if (is_graphic_console() &&
+                (kbd_mouse_is_absolute() || absolute_enabled)) {
+                int max_x = real_screen->w - 1;
+                int max_y = real_screen->h - 1;
+
+                if (gui_grab &&
+                    (ev->motion.x == 0 || ev->motion.y == 0 ||
+                     ev->motion.x == max_x || ev->motion.y == max_y)) {
+                    sdl_grab_end();
+                }
+                if (!gui_grab && SDL_GetAppState() & SDL_APPINPUTFOCUS &&
+                    (ev->motion.x > 0 && ev->motion.x < max_x &&
+                     ev->motion.y > 0 && ev->motion.y < max_y)) {
+                    sdl_grab_start();
+                }
+            }
             if (gui_grab || kbd_mouse_is_absolute() ||
                 absolute_enabled) {
                 sdl_send_mouse_event(ev->motion.xrel, ev->motion.yrel, 0,
@@ -764,6 +791,10 @@ static void sdl_refresh(DisplayState *ds)
                 !ev->active.gain && !gui_fullscreen) {
                 sdl_grab_end();
             }
+            if (!gui_grab && ev->active.gain && is_graphic_console() &&
+                (kbd_mouse_is_absolute() || absolute_enabled)) {
+                absolute_mouse_grab();
+            }
             if (ev->active.state & SDL_APPACTIVE) {
                 if (ev->active.gain) {
                     /* Back to default interval */
commit 74d9dc69abebdbf22b9473708aefd47ab53475dd
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Sat Jul 30 11:39:14 2011 +0200

    sdl: Fix cursor handling when switching consoles in absolute mouse mode
    
    Restore the cursor when switching from graphic to text console while the
    mouse is in absolute mode. Disable it again when returning.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/ui/sdl.c b/ui/sdl.c
index 662ffef..5ad38d5 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -452,7 +452,7 @@ static void sdl_show_cursor(void)
     if (!cursor_hide)
         return;
 
-    if (!kbd_mouse_is_absolute()) {
+    if (!kbd_mouse_is_absolute() || !is_graphic_console()) {
         SDL_ShowCursor(1);
         if (guest_cursor &&
                 (gui_grab || kbd_mouse_is_absolute() || absolute_enabled))
@@ -625,13 +625,20 @@ static void sdl_refresh(DisplayState *ds)
                         /* Reset the modifiers sent to the current console */
                         reset_keys();
                         console_select(keycode - 0x02);
+                        gui_keysym = 1;
+                        if (gui_fullscreen) {
+                            break;
+                        }
                         if (!is_graphic_console()) {
                             /* release grab if going to a text console */
-                            if (gui_grab && !gui_fullscreen) {
+                            if (gui_grab) {
                                 sdl_grab_end();
+                            } else if (absolute_enabled) {
+                                sdl_show_cursor();
                             }
+                        } else if (absolute_enabled) {
+                            sdl_hide_cursor();
                         }
-                        gui_keysym = 1;
                         break;
                     default:
                         break;
commit f623d885480b7899a445c9ef7aaa95db52820bc1
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Sat Jul 30 11:39:13 2011 +0200

    sdl: Never release input while in full screen mode
    
    It's confusing to suddenly find two mice in full screen mode when
    switching consoles or accidentally hitting the grab hot keys.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/ui/sdl.c b/ui/sdl.c
index 27465b2..662ffef 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -626,9 +626,10 @@ static void sdl_refresh(DisplayState *ds)
                         reset_keys();
                         console_select(keycode - 0x02);
                         if (!is_graphic_console()) {
-                            /* display grab if going to a text console */
-                            if (gui_grab)
+                            /* release grab if going to a text console */
+                            if (gui_grab && !gui_fullscreen) {
                                 sdl_grab_end();
+                            }
                         }
                         gui_keysym = 1;
                         break;
@@ -694,7 +695,7 @@ static void sdl_refresh(DisplayState *ds)
                                     SDL_GetAppState() & SDL_APPACTIVE) {
                                     sdl_grab_start();
                                 }
-                            } else {
+                            } else if (!gui_fullscreen) {
                                 sdl_grab_end();
                             }
                             /* SDL does not send back all the
commit f85581004c140c09936bc63f3744a287216aa76d
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Sat Jul 30 11:39:12 2011 +0200

    sdl: Consistently avoid grabbing input for text consoles
    
    There were some preexisting bits that released the input when switching
    to text console. This patch spreads this logic consistently and also
    avoids grabbing the input while a text console is active.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/ui/sdl.c b/ui/sdl.c
index f19bae2..27465b2 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -564,8 +564,9 @@ static void toggle_full_screen(DisplayState *ds)
         } else {
             do_sdl_resize(ds_get_width(ds), ds_get_height(ds), 0);
         }
-        if (!gui_saved_grab)
+        if (!gui_saved_grab || !is_graphic_console()) {
             sdl_grab_end();
+        }
     }
     vga_hw_invalidate();
     vga_hw_update();
@@ -689,8 +690,10 @@ static void sdl_refresh(DisplayState *ds)
                                    'SDL_WM_GrabInput(SDL_GRAB_ON)'
                                    from blocking all the application
                                    (SDL bug). */
-                                if (SDL_GetAppState() & SDL_APPACTIVE)
+                                if (is_graphic_console() &&
+                                    SDL_GetAppState() & SDL_APPACTIVE) {
                                     sdl_grab_start();
+                                }
                             } else {
                                 sdl_grab_end();
                             }
@@ -721,7 +724,7 @@ static void sdl_refresh(DisplayState *ds)
             break;
         case SDL_MOUSEBUTTONDOWN:
         case SDL_MOUSEBUTTONUP:
-            {
+            if (is_graphic_console()) {
                 SDL_MouseButtonEvent *bev = &ev->button;
                 if (!gui_grab && !kbd_mouse_is_absolute()) {
                     if (ev->type == SDL_MOUSEBUTTONDOWN &&
commit 110defd753906a01d01d0cabfb2d8db77b3271ef
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Sat Jul 30 11:39:11 2011 +0200

    sdl: Initialize gui_fullscreen earlier during setup
    
    This ensures that we actually enter full screen on startup when e.g.
    '-vga none -full-screen' was specified.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/ui/sdl.c b/ui/sdl.c
index 80bf776..f19bae2 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -891,6 +891,11 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
         qemu_free(filename);
     }
 
+    if (full_screen) {
+        gui_fullscreen = 1;
+        sdl_grab_start();
+    }
+
     dcl = qemu_mallocz(sizeof(DisplayChangeListener));
     dcl->dpy_update = sdl_update;
     dcl->dpy_resize = sdl_resize;
@@ -920,8 +925,4 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
     sdl_cursor_normal = SDL_GetCursor();
 
     atexit(sdl_cleanup);
-    if (full_screen) {
-        gui_fullscreen = 1;
-        sdl_grab_start();
-    }
 }
commit 982aae66ff75dced49990d7cce8dc0be31aff7e1
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Sat Jul 30 11:39:10 2011 +0200

    sdl: Drop bogus gui_fullscreen_initial_grab
    
    There must be no difference between initial -full-screen and switching
    to this mode via the hot key.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/ui/sdl.c b/ui/sdl.c
index e18c59a..80bf776 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -47,7 +47,6 @@ static int gui_fullscreen;
 static int gui_noframe;
 static int gui_key_modifier_pressed;
 static int gui_keysym;
-static int gui_fullscreen_initial_grab;
 static int gui_grab_code = KMOD_LALT | KMOD_LCTRL;
 static uint8_t modifiers_state[256];
 static int width, height;
@@ -751,7 +750,7 @@ static void sdl_refresh(DisplayState *ds)
             break;
         case SDL_ACTIVEEVENT:
             if (gui_grab && ev->active.state == SDL_APPINPUTFOCUS &&
-                !ev->active.gain && !gui_fullscreen_initial_grab) {
+                !ev->active.gain && !gui_fullscreen) {
                 sdl_grab_end();
             }
             if (ev->active.state & SDL_APPACTIVE) {
@@ -923,7 +922,6 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
     atexit(sdl_cleanup);
     if (full_screen) {
         gui_fullscreen = 1;
-        gui_fullscreen_initial_grab = 1;
         sdl_grab_start();
     }
 }
commit f9977897eee2ed5e28e758b9e21cb4f64a260842
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Sat Jul 30 11:39:09 2011 +0200

    sdl: Restore scaling mode on return from full screen
    
    Save the scaling mode and its geometry when going full screen, restore
    it when returning to windowed mode.
    
    CC: Stefano Stabellini <stefano.stabellini at eu.citrix.com>
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/ui/sdl.c b/ui/sdl.c
index 4acfe81..e18c59a 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -39,6 +39,9 @@ static SDL_Surface *real_screen;
 static SDL_Surface *guest_screen = NULL;
 static int gui_grab; /* if true, all keyboard/mouse events are grabbed */
 static int last_vm_running;
+static bool gui_saved_scaling;
+static int gui_saved_width;
+static int gui_saved_height;
 static int gui_saved_grab;
 static int gui_fullscreen;
 static int gui_noframe;
@@ -526,16 +529,42 @@ static void sdl_send_mouse_event(int dx, int dy, int dz, int x, int y, int state
     kbd_mouse_event(dx, dy, dz, buttons);
 }
 
+static void sdl_scale(DisplayState *ds, int width, int height)
+{
+    int bpp = real_screen->format->BitsPerPixel;
+
+    if (bpp != 16 && bpp != 32) {
+        bpp = 32;
+    }
+    do_sdl_resize(width, height, bpp);
+    scaling_active = 1;
+    if (!is_buffer_shared(ds->surface)) {
+        ds->surface = qemu_resize_displaysurface(ds, ds_get_width(ds),
+                                                 ds_get_height(ds));
+        dpy_resize(ds);
+    }
+}
+
 static void toggle_full_screen(DisplayState *ds)
 {
     gui_fullscreen = !gui_fullscreen;
-    do_sdl_resize(ds_get_width(ds), ds_get_height(ds),
-                  ds_get_bits_per_pixel(ds));
     if (gui_fullscreen) {
+        gui_saved_width = real_screen->w;
+        gui_saved_height = real_screen->h;
+        gui_saved_scaling = scaling_active;
+
+        do_sdl_resize(ds_get_width(ds), ds_get_height(ds),
+                      ds_get_bits_per_pixel(ds));
         scaling_active = 0;
+
         gui_saved_grab = gui_grab;
         sdl_grab_start();
     } else {
+        if (gui_saved_scaling) {
+            sdl_scale(ds, gui_saved_width, gui_saved_height);
+        } else {
+            do_sdl_resize(ds_get_width(ds), ds_get_height(ds), 0);
+        }
         if (!gui_saved_grab)
             sdl_grab_end();
     }
@@ -737,22 +766,11 @@ static void sdl_refresh(DisplayState *ds)
                 }
             }
             break;
-	case SDL_VIDEORESIZE:
-        {
-	    SDL_ResizeEvent *rev = &ev->resize;
-            int bpp = real_screen->format->BitsPerPixel;
-            if (bpp != 16 && bpp != 32)
-                bpp = 32;
-            do_sdl_resize(rev->w, rev->h, bpp);
-            scaling_active = 1;
-            if (!is_buffer_shared(ds->surface)) {
-                ds->surface = qemu_resize_displaysurface(ds, ds_get_width(ds), ds_get_height(ds));
-                dpy_resize(ds);
-            }
+        case SDL_VIDEORESIZE:
+            sdl_scale(ds, ev->resize.w, ev->resize.h);
             vga_hw_invalidate();
             vga_hw_update();
             break;
-        }
         default:
             break;
         }
commit 2a8ad7da542dc52b98aff3219e1c202bb1b09895
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Sat Jul 30 11:39:08 2011 +0200

    sdl: Fix full screen toggling from scaled mode
    
    When switching to full screen mode from a scaled window, we need to
    resize to DisplayState's dimension, not the scaled "real" screen size.
    Moreover, scaling mode may have manipulated the bpp. So we need to
    restore it from the DisplayState as well.
    
    CC: Stefano Stabellini <stefano.stabellini at eu.citrix.com>
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/ui/sdl.c b/ui/sdl.c
index e6c9597..4acfe81 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -529,7 +529,8 @@ static void sdl_send_mouse_event(int dx, int dy, int dz, int x, int y, int state
 static void toggle_full_screen(DisplayState *ds)
 {
     gui_fullscreen = !gui_fullscreen;
-    do_sdl_resize(real_screen->w, real_screen->h, real_screen->format->BitsPerPixel);
+    do_sdl_resize(ds_get_width(ds), ds_get_height(ds),
+                  ds_get_bits_per_pixel(ds));
     if (gui_fullscreen) {
         scaling_active = 0;
         gui_saved_grab = gui_grab;
commit d71680c8f1d639bfb31958b25dfb806f6b8cda56
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Sat Jul 30 11:39:07 2011 +0200

    sdl: Properly mark modifier+u as hotkey
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/ui/sdl.c b/ui/sdl.c
index 1563ee1..e6c9597 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -589,6 +589,7 @@ static void sdl_refresh(DisplayState *ds)
                             vga_hw_invalidate();
                             vga_hw_update();
                         }
+                        gui_keysym = 1;
                         break;
                     case 0x02 ... 0x0a: /* '1' to '9' keys */
                         /* Reset the modifiers sent to the current console */
commit 97ad1c260cb76f834aa90dc6350fe405172b2cc3
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Sat Jul 30 11:39:06 2011 +0200

    sdl: Avoid redundant scaling deactivation
    
    Prevents screen flickering.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/ui/sdl.c b/ui/sdl.c
index 9a92b47..1563ee1 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -583,10 +583,12 @@ static void sdl_refresh(DisplayState *ds)
                         gui_keysym = 1;
                         break;
                     case 0x16: /* 'u' key on US keyboard */
-                        scaling_active = 0;
-                        sdl_resize(ds);
-                        vga_hw_invalidate();
-                        vga_hw_update();
+                        if (scaling_active) {
+                            scaling_active = 0;
+                            sdl_resize(ds);
+                            vga_hw_invalidate();
+                            vga_hw_update();
+                        }
                         break;
                     case 0x02 ... 0x0a: /* '1' to '9' keys */
                         /* Reset the modifiers sent to the current console */
commit 91ada9808408fcad818ced7309f47c5fb91c6075
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Sat Jul 30 11:39:05 2011 +0200

    sdl: Do not make full screen mode resizable
    
    This prevents continuous resizing events and improper screen setups when
    going full screen.
    
    CC: Stefano Stabellini <stefano.stabellini at eu.citrix.com>
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/ui/sdl.c b/ui/sdl.c
index 9efcda5..9a92b47 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -97,9 +97,12 @@ static void do_sdl_resize(int new_width, int new_height, int bpp)
 
     //    printf("resizing to %d %d\n", w, h);
 
-    flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL|SDL_RESIZABLE;
-    if (gui_fullscreen)
+    flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL;
+    if (gui_fullscreen) {
         flags |= SDL_FULLSCREEN;
+    } else {
+        flags |= SDL_RESIZABLE;
+    }
     if (gui_noframe)
         flags |= SDL_NOFRAME;
 
commit 941f511a26ebdfbeb53facc775f30b9d27f3855b
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Sat Jul 30 11:39:04 2011 +0200

    sdl: Fix termination in -no-shutdown mode
    
    Just like the monitor does, we need to clear no_shutdown before calling
    qemu_system_shutdown_request on quit requests. Otherwise, QEMU just
    stops the VM.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/ui/sdl.c b/ui/sdl.c
index 6dbc5cb..9efcda5 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -672,8 +672,10 @@ static void sdl_refresh(DisplayState *ds)
                 sdl_process_key(&ev->key);
             break;
         case SDL_QUIT:
-            if (!no_quit)
+            if (!no_quit) {
+                no_shutdown = 0;
                 qemu_system_shutdown_request();
+            }
             break;
         case SDL_MOUSEMOTION:
             if (gui_grab || kbd_mouse_is_absolute() ||
commit 257a7375582e4c3b32687c72d0f52279d28b2d85
Author: David Gibson <david at gibson.dropbear.id.au>
Date:   Mon Aug 1 16:49:59 2011 +1000

    Check fread() results to avoid gcc 4.6 warnings
    
    When compiling with gcc 4.6, some code in fw_cfg.c complains that fop_ret
    is assigned but not used (which is true).  However, it looks like the
    meaningless assignments to fop_ret were done to suppress other gcc warnings
    due to the fact that fread() is labelled as warn_unused_result in glibc.
    
    This patch avoids both errors, by actually checking the fread() result code
    and dropping out with an error message if it fails.
    
    Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Tested-by: Stefan Berger <stefanb at linux.vnet.ibm.com>
    Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c
index a29db90..e4847b7 100644
--- a/hw/fw_cfg.c
+++ b/hw/fw_cfg.c
@@ -87,6 +87,13 @@ static FILE *probe_splashfile(char *filename, int *file_sizep, int *file_typep)
     /* check magic ID */
     fseek(fp, 0L, SEEK_SET);
     fop_ret = fread(buf, 1, 2, fp);
+    if (fop_ret != 2) {
+        error_report("Could not read header from '%s': %s",
+                     filename, strerror(errno));
+        fclose(fp);
+        fp = NULL;
+        return fp;
+    }
     filehead_value = (buf[0] + (buf[1] << 8)) & 0xffff;
     if (filehead_value == 0xd8ff) {
         file_type = JPG_FILE;
@@ -181,6 +188,12 @@ static void fw_cfg_bootsplash(FWCfgState *s)
         boot_splash_filedata_size = file_size;
         fseek(fp, 0L, SEEK_SET);
         fop_ret = fread(boot_splash_filedata, 1, file_size, fp);
+        if (fop_ret != file_size) {
+            error_report("failed to read data from '%s'.",
+                         boot_splash_filename);
+            fclose(fp);
+            return;
+        }
         fclose(fp);
         /* insert data */
         if (file_type == JPG_FILE) {
commit 8a6b0cd7642f6a69700ef5c082b750140d61b7f4
Author: Stefano Stabellini <stefano.stabellini at eu.citrix.com>
Date:   Fri Jul 29 16:05:13 2011 +0100

    MAINTAINERS: add entry for Xen
    
    Acked-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Stefano Stabellini <stefano.stabellini at eu.citrix.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/MAINTAINERS b/MAINTAINERS
index 7cbcd7e..508ea1e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -143,6 +143,16 @@ L: kvm at vger.kernel.org
 S: Supported
 F: target-i386/kvm.c
 
+Guest CPU Cores (Xen):
+----------------------
+
+X86
+M: Stefano Stabellini <stefano.stabellini at eu.citrix.com>
+L: xen-devel at lists.xensource.com
+S: Supported
+F: xen-*
+F: */xen*
+
 ARM Machines
 ------------
 Gumstix
commit ac363c9042eb1010b88af0a202c09475ef909972
Author: Marcelo Tosatti <mtosatti at redhat.com>
Date:   Fri Aug 5 12:10:55 2011 -0300

    Remove #ifdef KVM_CAP_TSC_CONTROL
    
    Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>

diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 923d2d5..31b88b7 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -504,7 +504,6 @@ int kvm_arch_init_vcpu(CPUState *env)
     if (r)
 	    return r;
 
-#ifdef KVM_CAP_TSC_CONTROL
     r = kvm_check_extension(env->kvm_state, KVM_CAP_TSC_CONTROL);
     if (r && env->tsc_khz) {
         r = kvm_vcpu_ioctl(env, KVM_SET_TSC_KHZ, env->tsc_khz);
@@ -513,7 +512,6 @@ int kvm_arch_init_vcpu(CPUState *env)
             return r;
         }
     }
-#endif
 
     return 0;
 }
commit e7429073ed1a765180158622463e8e0fb1b296d7
Author: Joerg Roedel <joerg.roedel at amd.com>
Date:   Thu Jul 7 16:13:13 2011 +0200

    qemu-x86: Set tsc_khz in kvm when supported
    
    Make use of the KVM_TSC_CONTROL feature if available.
    
    Signed-off-by: Joerg Roedel <joerg.roedel at amd.com>
    Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>

diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 10fb2c4..923d2d5 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -354,6 +354,7 @@ int kvm_arch_init_vcpu(CPUState *env)
     uint32_t unused;
     struct kvm_cpuid_entry2 *c;
     uint32_t signature[3];
+    int r;
 
     env->cpuid_features &= kvm_arch_get_supported_cpuid(s, 1, 0, R_EDX);
 
@@ -499,7 +500,22 @@ int kvm_arch_init_vcpu(CPUState *env)
 
     qemu_add_vm_change_state_handler(cpu_update_state, env);
 
-    return kvm_vcpu_ioctl(env, KVM_SET_CPUID2, &cpuid_data);
+    r = kvm_vcpu_ioctl(env, KVM_SET_CPUID2, &cpuid_data);
+    if (r)
+	    return r;
+
+#ifdef KVM_CAP_TSC_CONTROL
+    r = kvm_check_extension(env->kvm_state, KVM_CAP_TSC_CONTROL);
+    if (r && env->tsc_khz) {
+        r = kvm_vcpu_ioctl(env, KVM_SET_TSC_KHZ, env->tsc_khz);
+        if (r < 0) {
+            fprintf(stderr, "KVM_SET_TSC_KHZ failed\n");
+            return r;
+        }
+    }
+#endif
+
+    return 0;
 }
 
 void kvm_arch_reset_vcpu(CPUState *env)
commit b862d1fe42363e79368ed93584fb5938b75a5ffa
Author: Joerg Roedel <joerg.roedel at amd.com>
Date:   Thu Jul 7 16:13:12 2011 +0200

    qemu-x86: Add tsc_freq option to -cpu
    
    To let the user configure the desired tsc frequency for the
    guest if running in KVM.
    
    Signed-off-by: Joerg Roedel <joerg.roedel at amd.com>
    Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>

diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index dd6c5fa..dcdd95f 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -743,6 +743,7 @@ typedef struct CPUX86State {
     uint32_t cpuid_kvm_features;
     uint32_t cpuid_svm_features;
     bool tsc_valid;
+    int tsc_khz;
     
     /* in order to simplify APIC support, we leave this pointer to the
        user */
diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c
index e1ae3af..89e9623 100644
--- a/target-i386/cpuid.c
+++ b/target-i386/cpuid.c
@@ -224,6 +224,7 @@ typedef struct x86_def_t {
     int family;
     int model;
     int stepping;
+    int tsc_khz;
     uint32_t features, ext_features, ext2_features, ext3_features;
     uint32_t kvm_features, svm_features;
     uint32_t xlevel;
@@ -704,6 +705,17 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
             } else if (!strcmp(featurestr, "model_id")) {
                 pstrcpy(x86_cpu_def->model_id, sizeof(x86_cpu_def->model_id),
                         val);
+            } else if (!strcmp(featurestr, "tsc_freq")) {
+                int64_t tsc_freq;
+                char *err;
+
+                tsc_freq = strtosz_suffix_unit(val, &err,
+                                               STRTOSZ_DEFSUFFIX_B, 1000);
+                if (!*val || *err) {
+                    fprintf(stderr, "bad numerical value %s\n", val);
+                    goto error;
+                }
+                x86_cpu_def->tsc_khz = tsc_freq / 1000;
             } else {
                 fprintf(stderr, "unrecognized feature %s\n", featurestr);
                 goto error;
@@ -872,6 +884,7 @@ int cpu_x86_register (CPUX86State *env, const char *cpu_model)
     env->cpuid_svm_features = def->svm_features;
     env->cpuid_ext4_features = def->ext4_features;
     env->cpuid_xlevel2 = def->xlevel2;
+    env->tsc_khz = def->tsc_khz;
     if (!kvm_enabled()) {
         env->cpuid_features &= TCG_FEATURES;
         env->cpuid_ext_features &= TCG_EXT_FEATURES;
commit a732e1baa864d5b10c5cfd9e3e437563b771c1a8
Author: Joerg Roedel <joerg.roedel at amd.com>
Date:   Thu Jul 7 16:13:11 2011 +0200

    qemu: Add strtosz_suffix_unit function
    
    This function does the same as the strtosz_suffix function
    except that it allows to specify the unit to which the
    k/M/B/T suffixes apply. This function will be used later to
    parse the tsc-frequency from the command-line.
    
    Signed-off-by: Joerg Roedel <joerg.roedel at amd.com>
    Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>

diff --git a/cutils.c b/cutils.c
index f9a7e36..28049e0 100644
--- a/cutils.c
+++ b/cutils.c
@@ -322,7 +322,8 @@ int fcntl_setfl(int fd, int flag)
  * value must be terminated by whitespace, ',' or '\0'. Return -1 on
  * error.
  */
-int64_t strtosz_suffix(const char *nptr, char **end, const char default_suffix)
+int64_t strtosz_suffix_unit(const char *nptr, char **end,
+                            const char default_suffix, int64_t unit)
 {
     int64_t retval = -1;
     char *endptr;
@@ -362,20 +363,20 @@ int64_t strtosz_suffix(const char *nptr, char **end, const char default_suffix)
         }
         break;
     case STRTOSZ_DEFSUFFIX_KB:
-        mul = 1 << 10;
+        mul = unit;
         break;
     case 0:
         if (mul_required) {
             goto fail;
         }
     case STRTOSZ_DEFSUFFIX_MB:
-        mul = 1ULL << 20;
+        mul = unit * unit;
         break;
     case STRTOSZ_DEFSUFFIX_GB:
-        mul = 1ULL << 30;
+        mul = unit * unit * unit;
         break;
     case STRTOSZ_DEFSUFFIX_TB:
-        mul = 1ULL << 40;
+        mul = unit * unit * unit * unit;
         break;
     default:
         goto fail;
@@ -405,6 +406,11 @@ fail:
     return retval;
 }
 
+int64_t strtosz_suffix(const char *nptr, char **end, const char default_suffix)
+{
+        return strtosz_suffix_unit(nptr, end, default_suffix, 1024);
+}
+
 int64_t strtosz(const char *nptr, char **end)
 {
     return strtosz_suffix(nptr, end, STRTOSZ_DEFSUFFIX_MB);
diff --git a/qemu-common.h b/qemu-common.h
index afbd04d..389f4d2 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -157,6 +157,8 @@ int fcntl_setfl(int fd, int flag);
 #define STRTOSZ_DEFSUFFIX_B	'B'
 int64_t strtosz(const char *nptr, char **end);
 int64_t strtosz_suffix(const char *nptr, char **end, const char default_suffix);
+int64_t strtosz_suffix_unit(const char *nptr, char **end,
+                            const char default_suffix, int64_t unit);
 
 /* path.c */
 void init_paths(const char *prefix);
commit 2a1ac12b0bb29054f5fbc8144c800ca7634c0658
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Thu Jun 23 10:26:27 2011 +0200

    kvm: Drop obsolete KVM_IOEVENTFD #ifdefs
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>

diff --git a/kvm-all.c b/kvm-all.c
index cbc2532..b9c172b 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -1328,7 +1328,6 @@ int kvm_set_signal_mask(CPUState *env, const sigset_t *sigset)
 
 int kvm_set_ioeventfd_mmio_long(int fd, uint32_t addr, uint32_t val, bool assign)
 {
-#ifdef KVM_IOEVENTFD
     int ret;
     struct kvm_ioeventfd iofd;
 
@@ -1353,14 +1352,10 @@ int kvm_set_ioeventfd_mmio_long(int fd, uint32_t addr, uint32_t val, bool assign
     }
 
     return 0;
-#else
-    return -ENOSYS;
-#endif
 }
 
 int kvm_set_ioeventfd_pio_word(int fd, uint16_t addr, uint16_t val, bool assign)
 {
-#ifdef KVM_IOEVENTFD
     struct kvm_ioeventfd kick = {
         .datamatch = val,
         .addr = addr,
@@ -1380,9 +1375,6 @@ int kvm_set_ioeventfd_pio_word(int fd, uint16_t addr, uint16_t val, bool assign)
         return r;
     }
     return 0;
-#else
-    return -ENOSYS;
-#endif
 }
 
 int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr)
commit cf7d3e64bfc48148bd7a3094fb563428d103d7ed
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Thu Jun 23 10:23:10 2011 +0200

    kvmclock: Fix feature detection
    
    Bit-wise or the feature flags and drop the obsolete #ifdef.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>

diff --git a/hw/kvmclock.c b/hw/kvmclock.c
index 692ad18..b73aec4 100644
--- a/hw/kvmclock.c
+++ b/hw/kvmclock.c
@@ -101,11 +101,8 @@ static SysBusDeviceInfo kvmclock_info = {
 void kvmclock_create(void)
 {
     if (kvm_enabled() &&
-        first_cpu->cpuid_kvm_features & ((1ULL << KVM_FEATURE_CLOCKSOURCE)
-#ifdef KVM_FEATURE_CLOCKSOURCE2
-        || (1ULL << KVM_FEATURE_CLOCKSOURCE2)
-#endif
-    )) {
+        first_cpu->cpuid_kvm_features & ((1ULL << KVM_FEATURE_CLOCKSOURCE) |
+                                         (1ULL << KVM_FEATURE_CLOCKSOURCE2))) {
         sysbus_create_simple("kvmclock", -1, NULL);
     }
 }
commit 35d7ace74bd07e3d6983c1fd7cbfab4e11175689
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Fri Aug 5 12:06:11 2011 +0200

    qcow2: Fix L1 table size after bdrv_snapshot_goto
    
    When loading an internal snapshot whose L1 table is smaller than the current L1
    table, the size of the current L1 would be shrunk to the snapshot's L1 size in
    memory, but not on disk. This lead to incorrect refcount updates and eventuelly
    to image corruption.
    
    Instead of writing the new L1 size to disk, this simply retains the bigger L1
    size that is currently in use and makes sure that the unused part is zeroed.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>
    Tested-by: Philipp Hahn <hahn at univention.de>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
index 74823a5..e32bcf0 100644
--- a/block/qcow2-snapshot.c
+++ b/block/qcow2-snapshot.c
@@ -317,7 +317,8 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
 {
     BDRVQcowState *s = bs->opaque;
     QCowSnapshot *sn;
-    int i, snapshot_index, l1_size2;
+    int i, snapshot_index;
+    int cur_l1_bytes, sn_l1_bytes;
 
     snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
     if (snapshot_index < 0)
@@ -330,14 +331,19 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
     if (qcow2_grow_l1_table(bs, sn->l1_size, true) < 0)
         goto fail;
 
-    s->l1_size = sn->l1_size;
-    l1_size2 = s->l1_size * sizeof(uint64_t);
+    cur_l1_bytes = s->l1_size * sizeof(uint64_t);
+    sn_l1_bytes = sn->l1_size * sizeof(uint64_t);
+
+    if (cur_l1_bytes > sn_l1_bytes) {
+        memset(s->l1_table + sn->l1_size, 0, cur_l1_bytes - sn_l1_bytes);
+    }
+
     /* copy the snapshot l1 table to the current l1 table */
     if (bdrv_pread(bs->file, sn->l1_table_offset,
-                   s->l1_table, l1_size2) != l1_size2)
+                   s->l1_table, sn_l1_bytes) < 0)
         goto fail;
     if (bdrv_pwrite_sync(bs->file, s->l1_table_offset,
-                    s->l1_table, l1_size2) < 0)
+                    s->l1_table, cur_l1_bytes) < 0)
         goto fail;
     for(i = 0;i < s->l1_size; i++) {
         be64_to_cpus(&s->l1_table[i]);
commit e3a110b527f749a2acec079c261f4481aadd3edc
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Fri Aug 5 14:05:53 2011 +0200

    slirp: Only start packet expiration for delayed ones
    
    The expiration timeout must only affect packets that are queued due to
    pending ARP resolutions. The old version broke ping e.g.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>

diff --git a/slirp/if.c b/slirp/if.c
index 47bebe4..2852396 100644
--- a/slirp/if.c
+++ b/slirp/if.c
@@ -106,9 +106,6 @@ if_output(struct socket *so, struct mbuf *ifm)
 	ifs_init(ifm);
 	insque(ifm, ifq);
 
-        /* Expiration date = Now + 1 second */
-        ifm->expiration_date = qemu_get_clock_ns(rt_clock) + 1000000000ULL;
-
 diddit:
 	slirp->if_queued++;
 
diff --git a/slirp/slirp.c b/slirp/slirp.c
index a86cc6e..2c242ef 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -738,6 +738,9 @@ int if_encap(Slirp *slirp, struct mbuf *ifm)
             slirp->client_ipaddr = iph->ip_dst;
             slirp_output(slirp->opaque, arp_req, sizeof(arp_req));
             ifm->arp_requested = true;
+
+            /* Expire request and drop outgoing packet after 1 second */
+            ifm->expiration_date = qemu_get_clock_ns(rt_clock) + 1000000000ULL;
         }
         return 0;
     } else {
commit fd5938799d115c966f9b2d41bbb4d5bcb5284b97
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Fri Aug 5 14:04:00 2011 +0200

    slirp: Read current time only once per if_start call
    
    No need to update the current time for each packet we send from the
    queue. Processing time is comparably short.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>

diff --git a/slirp/if.c b/slirp/if.c
index 2d79e45..47bebe4 100644
--- a/slirp/if.c
+++ b/slirp/if.c
@@ -157,9 +157,8 @@ diddit:
 void
 if_start(Slirp *slirp)
 {
+    uint64_t now = qemu_get_clock_ns(rt_clock);
     int requeued = 0;
-    uint64_t now;
-
 	struct mbuf *ifm, *ifqt;
 
 	DEBUG_CALL("if_start");
@@ -172,8 +171,6 @@ if_start(Slirp *slirp)
         if (!slirp_can_output(slirp->opaque))
             return;
 
-        now = qemu_get_clock_ns(rt_clock);
-
 	/*
 	 * See which queue to get next packet from
 	 * If there's something in the fastq, select it immediately
commit 5a371a2e52facac1f79ab2cb1cf75ed661ab11b0
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Fri Aug 5 12:51:11 2011 +0200

    slirp: Fix types of IP address parameters
    
    Should be uint32_t for IPv4, not int. Also avoid in_addr_t without
    proper includes. Fixes build regression on mingw32.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>

diff --git a/slirp/arp_table.c b/slirp/arp_table.c
index 820dee2..5d7b8ac 100644
--- a/slirp/arp_table.c
+++ b/slirp/arp_table.c
@@ -24,9 +24,9 @@
 
 #include "slirp.h"
 
-void arp_table_add(Slirp *slirp, int ip_addr, uint8_t ethaddr[ETH_ALEN])
+void arp_table_add(Slirp *slirp, uint32_t ip_addr, uint8_t ethaddr[ETH_ALEN])
 {
-    const in_addr_t broadcast_addr =
+    const uint32_t broadcast_addr =
         ~slirp->vnetwork_mask.s_addr | slirp->vnetwork_addr.s_addr;
     ArpTable *arptbl = &slirp->arp_table;
     int i;
@@ -60,29 +60,29 @@ void arp_table_add(Slirp *slirp, int ip_addr, uint8_t ethaddr[ETH_ALEN])
     arptbl->next_victim = (arptbl->next_victim + 1) % ARP_TABLE_SIZE;
 }
 
-bool arp_table_search(Slirp *slirp, int in_ip_addr,
+bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
                       uint8_t out_ethaddr[ETH_ALEN])
 {
-    const in_addr_t broadcast_addr =
+    const uint32_t broadcast_addr =
         ~slirp->vnetwork_mask.s_addr | slirp->vnetwork_addr.s_addr;
     ArpTable *arptbl = &slirp->arp_table;
     int i;
 
     DEBUG_CALL("arp_table_search");
-    DEBUG_ARG("ip = 0x%x", in_ip_addr);
+    DEBUG_ARG("ip = 0x%x", ip_addr);
 
     /* Check 0.0.0.0/8 invalid source-only addresses */
-    assert((in_ip_addr & htonl(~(0xf << 28))) != 0);
+    assert((ip_addr & htonl(~(0xf << 28))) != 0);
 
     /* If broadcast address */
-    if (in_ip_addr == 0xffffffff || in_ip_addr == broadcast_addr) {
+    if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
         /* return Ethernet broadcast address */
         memset(out_ethaddr, 0xff, ETH_ALEN);
         return 1;
     }
 
     for (i = 0; i < ARP_TABLE_SIZE; i++) {
-        if (arptbl->table[i].ar_sip == in_ip_addr) {
+        if (arptbl->table[i].ar_sip == ip_addr) {
             memcpy(out_ethaddr, arptbl->table[i].ar_sha,  ETH_ALEN);
             DEBUG_ARGS((dfd, " found hw addr = %02x:%02x:%02x:%02x:%02x:%02x\n",
                         out_ethaddr[0], out_ethaddr[1], out_ethaddr[2],
diff --git a/slirp/slirp.h b/slirp/slirp.h
index 2a070e6..dcf99d5 100644
--- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -208,9 +208,9 @@ typedef struct ArpTable {
     int next_victim;
 } ArpTable;
 
-void arp_table_add(Slirp *slirp, int ip_addr, uint8_t ethaddr[ETH_ALEN]);
+void arp_table_add(Slirp *slirp, uint32_t ip_addr, uint8_t ethaddr[ETH_ALEN]);
 
-bool arp_table_search(Slirp *slirp, int in_ip_addr,
+bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
                       uint8_t out_ethaddr[ETH_ALEN]);
 
 struct Slirp {
commit a67a47d2b559a7733c3f89aeb2d81b19d2c027e4
Merge: 670acc9... 81e34a2...
Author: malc <av1474 at comtv.ru>
Date:   Fri Aug 5 10:07:10 2011 +0400

    Merge branch 'master' of git://git.qemu.org/qemu

commit 81e34a2401f7ffd519bb7f093e833cb48734169f
Merge: e06516f... cb4b4fd...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Aug 4 17:15:22 2011 -0500

    Merge remote-tracking branch 'mst/for_anthony' into staging

commit e06516f565dca3636a4cbef770b191a5fcdf63ab
Merge: 6e855de... 4995f0d...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Aug 4 17:14:49 2011 -0500

    Merge remote-tracking branch 'alon/pull-libcacard.data' into staging

commit 6e855de900a4c5557816a662f412170b31b66d68
Merge: dfa79e8... 793553a...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Aug 4 17:14:01 2011 -0500

    Merge remote-tracking branch 'stefanha/trivial-patches' into staging

commit dfa79e8acd0ffce337d78f3e1473647f1c38dc58
Merge: c00c0dc... 9197a7c...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Aug 4 17:13:26 2011 -0500

    Merge remote-tracking branch 'spice/spice.v40' into staging

commit c00c0dc6875be609072434bd0aaf516270e33d4a
Merge: 5df0a2a... 1ab74ce...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Aug 4 17:12:34 2011 -0500

    Merge remote-tracking branch 'kiszka/queues/slirp' into staging

commit 5df0a2a5ba54114afb2bf75cab9fb184020a46a8
Merge: 47bf05d... fb8f4ce...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Aug 4 17:10:36 2011 -0500

    Merge remote-tracking branch 'kraxel/usb.22' into staging

commit 47bf05d7eb550905c635724ce72f855fb4e10b3d
Merge: d138cee... e7a8a78...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Aug 4 16:45:17 2011 -0500

    Merge remote-tracking branch 'kwolf/for-anthony' into staging

commit d138cee907b36f217ad030fb2c75c027b7d5731b
Author: Michael Roth <mdroth at linux.vnet.ibm.com>
Date:   Mon Aug 1 14:52:57 2011 -0500

    guest agent: add --enable-guest-agent config option
    
    QAPI will require glib/python, but for now the guest agent is the only
    user. For now, make these dependencies an explicit guest agent one, and
    give users the option to disable it if need be.
    
    Once QAPI is adopted in core QEMU code, we would basically revert this
    patch.
    
    Signed-off-by: Michael Roth <mdroth at linux.vnet.ibm.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/configure b/configure
index 269bf43..e41fa0f 100755
--- a/configure
+++ b/configure
@@ -181,6 +181,7 @@ smartcard_nss=""
 usb_redir=""
 opengl=""
 zlib="yes"
+guest_agent="yes"
 
 # parse CC options first
 for opt do
@@ -757,6 +758,10 @@ for opt do
   ;;
   --disable-zlib-test) zlib="no"
   ;;
+  --enable-guest-agent) guest_agent="yes"
+  ;;
+  --disable-guest-agent) guest_agent="no"
+  ;;
   *) echo "ERROR: unknown option $opt"; show_help="yes"
   ;;
   esac
@@ -1034,6 +1039,8 @@ echo "  --disable-smartcard-nss  disable smartcard nss support"
 echo "  --enable-smartcard-nss   enable smartcard nss support"
 echo "  --disable-usb-redir      disable usb network redirection support"
 echo "  --enable-usb-redir       enable usb network redirection support"
+echo "  --disable-guest-agent    disable building of the QEMU Guest Agent"
+echo "  --enable-guest-agent     enable building of the QEMU Guest Agent"
 echo ""
 echo "NOTE: The object files are built at the place where configure is launched"
 exit 1
@@ -1093,11 +1100,13 @@ if test "$solaris" = "yes" ; then
   fi
 fi
 
-if has $python; then
-  :
-else
-  echo "Python not found. Use --python=/path/to/python"
-  exit 1
+if test "$guest_agent" != "no" ; then
+  if has $python; then
+    :
+  else
+    echo "Python not found. Use --python=/path/to/python"
+    exit 1
+  fi
 fi
 
 if test -z "$target_list" ; then
@@ -1835,14 +1844,16 @@ fi
 
 ##########################################
 # glib support probe
-if $pkg_config --modversion glib-2.0 > /dev/null 2>&1 ; then
-    glib_cflags=`$pkg_config --cflags glib-2.0 2>/dev/null`
-    glib_libs=`$pkg_config --libs glib-2.0 2>/dev/null`
-    libs_softmmu="$glib_libs $libs_softmmu"
-    libs_tools="$glib_libs $libs_tools"
-else
-    echo "glib-2.0 required to compile QEMU"
-    exit 1
+if test "$guest_agent" != "no" ; then
+    if $pkg_config --modversion glib-2.0 > /dev/null 2>&1 ; then
+        glib_cflags=`$pkg_config --cflags glib-2.0 2>/dev/null`
+        glib_libs=`$pkg_config --libs glib-2.0 2>/dev/null`
+        libs_softmmu="$glib_libs $libs_softmmu"
+        libs_tools="$glib_libs $libs_tools"
+    else
+        echo "glib-2.0 required to compile QEMU"
+        exit 1
+    fi
 fi
 
 ##########################################
@@ -2602,7 +2613,9 @@ if test "$softmmu" = yes ; then
   tools="qemu-img\$(EXESUF) qemu-io\$(EXESUF) $tools"
   if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" ] ; then
       tools="qemu-nbd\$(EXESUF) $tools"
+    if [ "$guest_agent" = "yes" ]; then
       tools="qemu-ga\$(EXESUF) $tools"
+    fi
     if [ "$check_utests" = "yes" ]; then
       tools="check-qint check-qstring check-qdict check-qlist $tools"
       tools="check-qfloat check-qjson $tools"
@@ -2704,6 +2717,7 @@ echo "xfsctl support    $xfs"
 echo "nss used          $smartcard_nss"
 echo "usb net redir     $usb_redir"
 echo "OpenGL support    $opengl"
+echo "build guest agent $guest_agent"
 
 if test "$sdl_too_old" = "yes"; then
 echo "-> Your SDL version is too old - please upgrade to have SDL support"
commit 9af8025e24185172a8857ed9b32d1d0ccd6aa79b
Author: Brad <brad at comstyle.com>
Date:   Sat Jul 30 01:45:55 2011 -0400

    Add support for finding libpng via pkg-config.
    
    Signed-off-by: Brad Smith <brad at comstyle.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/configure b/configure
index fc60888..269bf43 100755
--- a/configure
+++ b/configure
@@ -1512,11 +1512,17 @@ int main(void) {
     return 0;
 }
 EOF
+  if $pkg_config libpng --modversion >/dev/null 2>&1; then
+    vnc_png_cflags=`$pkg_config libpng --cflags 2> /dev/null`
+    vnc_png_libs=`$pkg_config libpng --libs 2> /dev/null`
+  else
     vnc_png_cflags=""
     vnc_png_libs="-lpng"
+  fi
   if compile_prog "$vnc_png_cflags" "$vnc_png_libs" ; then
     vnc_png=yes
     libs_softmmu="$vnc_png_libs $libs_softmmu"
+    QEMU_CFLAGS="$QEMU_CFLAGS $vnc_png_cflags"
   else
     if test "$vnc_png" = "yes" ; then
       feature_not_found "vnc-png"
commit 46f08792bb4a69ab8aab897c174d82b006026140
Author: Richard Henderson <rth at twiddle.net>
Date:   Sun Jul 31 16:47:20 2011 -0700

    alpha-softmmu: Disable for the 0.15 release branch.
    
    The system emulation code was not merged before the branch.
    Let's leave that work for the next release.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/configure b/configure
index 8546573..fc60888 100755
--- a/configure
+++ b/configure
@@ -846,7 +846,6 @@ if [ "$softmmu" = "yes" ] ; then
     default_target_list="\
 i386-softmmu \
 x86_64-softmmu \
-alpha-softmmu \
 arm-softmmu \
 cris-softmmu \
 lm32-softmmu \
commit 1ba16968ab1920e65303d814ba65793b0a83e93e
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Fri Jul 29 22:40:45 2011 +0200

    configure: Fix bad shell expression for non-Linux hosts
    
    With vhost_net="" (most non-Linux hosts), configure prints an
    error message:
    
    test: 2551: =: unexpected operator
    
    Fix this and similar code by adding the missing "".
    
    Cc: Wolfgang Mauerer <wolfgang.mauerer at siemens.com>
    Cc: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/configure b/configure
index 77194cf..8546573 100755
--- a/configure
+++ b/configure
@@ -2521,7 +2521,7 @@ fi
 # __sync_fetch_and_and requires at least -march=i486. Many toolchains
 # use i686 as default anyway, but for those that don't, an explicit
 # specification is necessary
-if test $vhost_net = "yes" && test $cpu = "i386"; then
+if test "$vhost_net" = "yes" && test "$cpu" = "i386"; then
   cat > $TMPC << EOF
 int sfaa(unsigned *ptr)
 {
@@ -2700,7 +2700,7 @@ echo "nss used          $smartcard_nss"
 echo "usb net redir     $usb_redir"
 echo "OpenGL support    $opengl"
 
-if test $sdl_too_old = "yes"; then
+if test "$sdl_too_old" = "yes"; then
 echo "-> Your SDL version is too old - please upgrade to have SDL support"
 fi
 
@@ -2788,7 +2788,7 @@ fi
 if test "$static" = "yes" ; then
   echo "CONFIG_STATIC=y" >> $config_host_mak
 fi
-if test $profiler = "yes" ; then
+if test "$profiler" = "yes" ; then
   echo "CONFIG_PROFILER=y" >> $config_host_mak
 fi
 if test "$slirp" = "yes" ; then
@@ -3342,7 +3342,7 @@ case "$target_arch2" in
       \( "$target_arch2" = "x86_64" -a "$cpu" = "i386"   \) -o \
       \( "$target_arch2" = "i386"   -a "$cpu" = "x86_64" \) \) ; then
       echo "CONFIG_KVM=y" >> $config_target_mak
-      if test $vhost_net = "yes" ; then
+      if test "$vhost_net" = "yes" ; then
         echo "CONFIG_VHOST_NET=y" >> $config_target_mak
       fi
     fi
commit ac720400e1730ff910d42442e4393044e7c132e0
Author: Amit Shah <amit.shah at redhat.com>
Date:   Thu Jul 28 11:36:26 2011 +0530

    virtio-balloon: Unregister savevm section on device unplug
    
    Migrating after unplugging a virtio-balloon device resulted in an error
    message on the destination:
    
    Unknown savevm section or instance '0000:00:04.0/virtio-balloon' 0
    load of migration failed
    
    Fix this by unregistering the section on device unplug.
    
    Signed-off-by: Amit Shah <amit.shah at redhat.com>
    Reviewed-by: Markus Armbruster <armbru at redhat.com>
    Acked-by: Michael S. Tsirkin <mst at redhat.com>

diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c
index 0ce0049..072a88a 100644
--- a/hw/virtio-balloon.c
+++ b/hw/virtio-balloon.c
@@ -45,6 +45,7 @@ typedef struct VirtIOBalloon
     size_t stats_vq_offset;
     MonitorCompletion *stats_callback;
     void *stats_opaque_callback_data;
+    DeviceState *qdev;
 } VirtIOBalloon;
 
 static VirtIOBalloon *to_virtio_balloon(VirtIODevice *vdev)
@@ -292,6 +293,7 @@ VirtIODevice *virtio_balloon_init(DeviceState *dev)
 
     reset_stats(s);
 
+    s->qdev = dev;
     register_savevm(dev, "virtio-balloon", -1, 1,
                     virtio_balloon_save, virtio_balloon_load, s);
 
@@ -300,5 +302,7 @@ VirtIODevice *virtio_balloon_init(DeviceState *dev)
 
 void virtio_balloon_exit(VirtIODevice *vdev)
 {
+    VirtIOBalloon *s = DO_UPCAST(VirtIOBalloon, vdev, vdev);
+    unregister_savevm(s->qdev, "virtio-balloon", s);
     virtio_cleanup(vdev);
 }
commit 855d7e259fe2a804f08698ca5c97d6b07fa79da1
Author: Amit Shah <amit.shah at redhat.com>
Date:   Wed Jul 27 13:50:41 2011 +0530

    virtio-balloon: Add exit handler, fix memleaks
    
    Add an exit handler that will free up RAM after a virtio-balloon device
    is unplugged.
    
    Signed-off-by: Amit Shah <amit.shah at redhat.com>
    Reviewed-by: Markus Armbruster <armbru at redhat.com>
    Acked-by: Michael S. Tsirkin <mst at redhat.com>

diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c
index 26ee364..0ce0049 100644
--- a/hw/virtio-balloon.c
+++ b/hw/virtio-balloon.c
@@ -297,3 +297,8 @@ VirtIODevice *virtio_balloon_init(DeviceState *dev)
 
     return &s->vdev;
 }
+
+void virtio_balloon_exit(VirtIODevice *vdev)
+{
+    virtio_cleanup(vdev);
+}
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index ca5f125..316bf92 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -795,6 +795,15 @@ static int virtio_balloon_init_pci(PCIDevice *pci_dev)
     return 0;
 }
 
+static int virtio_balloon_exit_pci(PCIDevice *pci_dev)
+{
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+
+    virtio_pci_stop_ioeventfd(proxy);
+    virtio_balloon_exit(proxy->vdev);
+    return virtio_exit_pci(pci_dev);
+}
+
 static PCIDeviceInfo virtio_info[] = {
     {
         .qdev.name = "virtio-blk-pci",
@@ -869,7 +878,7 @@ static PCIDeviceInfo virtio_info[] = {
         .qdev.alias = "virtio-balloon",
         .qdev.size = sizeof(VirtIOPCIProxy),
         .init      = virtio_balloon_init_pci,
-        .exit      = virtio_exit_pci,
+        .exit      = virtio_balloon_exit_pci,
         .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
         .device_id = PCI_DEVICE_ID_VIRTIO_BALLOON,
         .revision  = VIRTIO_PCI_ABI_VERSION,
diff --git a/hw/virtio.h b/hw/virtio.h
index 0fd0bb0..c129264 100644
--- a/hw/virtio.h
+++ b/hw/virtio.h
@@ -213,6 +213,7 @@ 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);
+void virtio_balloon_exit(VirtIODevice *vdev);
 
 #define DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) \
 	DEFINE_PROP_BIT("indirect_desc", _state, _field, \
commit 514e73ecebc0aeadef218e91e36ee42b3d145c93
Author: Amit Shah <amit.shah at redhat.com>
Date:   Wed Jul 27 16:50:54 2011 +0530

    balloon: Reject negative balloon values
    
    Negative balloon values don't make sense, reject them and throw a qerror
    with QERR_INVALID_PARAMETER_VALUE.
    
    Reported-by: Mike Cao <bcao at redhat.com>
    Signed-off-by: Amit Shah <amit.shah at redhat.com>
    Reviewed-by: Markus Armbruster <armbru at redhat.com>
    Acked-by: Michael S. Tsirkin <mst at redhat.com>

diff --git a/balloon.c b/balloon.c
index 5200565..f56fdc1 100644
--- a/balloon.c
+++ b/balloon.c
@@ -140,6 +140,7 @@ int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque)
 int do_balloon(Monitor *mon, const QDict *params,
 	       MonitorCompletion cb, void *opaque)
 {
+    int64_t target;
     int ret;
 
     if (kvm_enabled() && !kvm_has_sync_mmu()) {
@@ -147,7 +148,12 @@ int do_balloon(Monitor *mon, const QDict *params,
         return -1;
     }
 
-    ret = qemu_balloon(qdict_get_int(params, "value"));
+    target = qdict_get_int(params, "value");
+    if (target <= 0) {
+        qerror_report(QERR_INVALID_PARAMETER_VALUE, "target", "a size");
+        return -1;
+    }
+    ret = qemu_balloon(target);
     if (ret == 0) {
         qerror_report(QERR_DEVICE_NOT_ACTIVE, "balloon");
         return -1;
commit f76f665547f4a954a2c83552a88816fc2a316be0
Author: Amit Shah <amit.shah at redhat.com>
Date:   Wed Jul 27 12:29:33 2011 +0530

    virtio-balloon: Check if balloon registration failed
    
    Multiple balloon registrations are not allowed; check if the
    registration with the qemu balloon api succeeded.  If not, fail the
    device init.
    
    Signed-off-by: Amit Shah <amit.shah at redhat.com>
    Reviewed-by: Markus Armbruster <armbru at redhat.com>
    Acked-by: Michael S. Tsirkin <mst at redhat.com>

diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c
index 2ba7e95..26ee364 100644
--- a/hw/virtio-balloon.c
+++ b/hw/virtio-balloon.c
@@ -269,6 +269,7 @@ static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id)
 VirtIODevice *virtio_balloon_init(DeviceState *dev)
 {
     VirtIOBalloon *s;
+    int ret;
 
     s = (VirtIOBalloon *)virtio_common_init("virtio-balloon",
                                             VIRTIO_ID_BALLOON,
@@ -278,12 +279,18 @@ VirtIODevice *virtio_balloon_init(DeviceState *dev)
     s->vdev.set_config = virtio_balloon_set_config;
     s->vdev.get_features = virtio_balloon_get_features;
 
+    ret = qemu_add_balloon_handler(virtio_balloon_to_target,
+                                   virtio_balloon_stat, s);
+    if (ret < 0) {
+        virtio_cleanup(&s->vdev);
+        return NULL;
+    }
+
     s->ivq = virtio_add_queue(&s->vdev, 128, virtio_balloon_handle_output);
     s->dvq = virtio_add_queue(&s->vdev, 128, virtio_balloon_handle_output);
     s->svq = virtio_add_queue(&s->vdev, 128, virtio_balloon_receive_stats);
 
     reset_stats(s);
-    qemu_add_balloon_handler(virtio_balloon_to_target, virtio_balloon_stat, s);
 
     register_savevm(dev, "virtio-balloon", -1, 1,
                     virtio_balloon_save, virtio_balloon_load, s);
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index d685243..ca5f125 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -788,6 +788,9 @@ static int virtio_balloon_init_pci(PCIDevice *pci_dev)
     VirtIODevice *vdev;
 
     vdev = virtio_balloon_init(&pci_dev->qdev);
+    if (!vdev) {
+        return -1;
+    }
     virtio_init_pci(proxy, vdev);
     return 0;
 }
commit 6c6ec1821a2631b21e680051e2dedaa1be5b83dc
Author: Amit Shah <amit.shah at redhat.com>
Date:   Wed Jul 27 12:28:19 2011 +0530

    balloon: Don't allow multiple balloon handler registrations
    
    Multiple balloon devices don't make sense; disallow more than one
    registration attempt to register handlers.
    
    Signed-off-by: Amit Shah <amit.shah at redhat.com>
    Reviewed-by: Markus Armbruster <armbru at redhat.com>
    Acked-by: Michael S. Tsirkin <mst at redhat.com>

diff --git a/balloon.c b/balloon.c
index a938475..5200565 100644
--- a/balloon.c
+++ b/balloon.c
@@ -36,12 +36,20 @@ static QEMUBalloonEvent *balloon_event_fn;
 static QEMUBalloonStatus *balloon_stat_fn;
 static void *balloon_opaque;
 
-void qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
-                              QEMUBalloonStatus *stat_func, void *opaque)
+int qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
+                             QEMUBalloonStatus *stat_func, void *opaque)
 {
+    if (balloon_event_fn || balloon_stat_fn || balloon_opaque) {
+        /* We're already registered one balloon handler.  How many can
+         * a guest really have?
+         */
+        error_report("Another balloon device already registered");
+        return -1;
+    }
     balloon_event_fn = event_func;
     balloon_stat_fn = stat_func;
     balloon_opaque = opaque;
+    return 0;
 }
 
 static int qemu_balloon(ram_addr_t target)
diff --git a/balloon.h b/balloon.h
index a6c31d5..3df14e6 100644
--- a/balloon.h
+++ b/balloon.h
@@ -20,8 +20,8 @@ typedef void (QEMUBalloonEvent)(void *opaque, ram_addr_t target);
 typedef void (QEMUBalloonStatus)(void *opaque, MonitorCompletion cb,
                                  void *cb_data);
 
-void qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
-                              QEMUBalloonStatus *stat_func, void *opaque);
+int qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
+			     QEMUBalloonStatus *stat_func, void *opaque);
 
 void monitor_print_balloon(Monitor *mon, const QObject *data);
 int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque);
commit d4443cb616a62619b3b133c44094c3b056ecd3b0
Author: Amit Shah <amit.shah at redhat.com>
Date:   Wed Jul 20 13:37:01 2011 +0530

    virtio-balloon: Fix header comment; add Copyright
    
    Signed-off-by: Amit Shah <amit.shah at redhat.com>

diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c
index 40b43b0..2ba7e95 100644
--- a/hw/virtio-balloon.c
+++ b/hw/virtio-balloon.c
@@ -1,7 +1,9 @@
 /*
- * Virtio Block Device
+ * Virtio Balloon Device
  *
  * Copyright IBM, Corp. 2008
+ * Copyright (C) 2011 Red Hat, Inc.
+ * Copyright (C) 2011 Amit Shah <amit.shah at redhat.com>
  *
  * Authors:
  *  Anthony Liguori   <aliguori at us.ibm.com>
commit 73428a8ed53b7c7b1a52141e0ab71c50a42ce931
Author: Amit Shah <amit.shah at redhat.com>
Date:   Wed Jul 20 13:35:30 2011 +0530

    balloon: Fix header comment; add Copyright
    
    Signed-off-by: Amit Shah <amit.shah at redhat.com>

diff --git a/balloon.c b/balloon.c
index 8be3812..a938475 100644
--- a/balloon.c
+++ b/balloon.c
@@ -1,7 +1,9 @@
 /*
- * QEMU System Emulator
+ * Generic Balloon handlers and management
  *
  * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (C) 2011 Red Hat, Inc.
+ * Copyright (C) 2011 Amit Shah <amit.shah at redhat.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -30,7 +32,6 @@
 #include "balloon.h"
 #include "trace.h"
 
-
 static QEMUBalloonEvent *balloon_event_fn;
 static QEMUBalloonStatus *balloon_stat_fn;
 static void *balloon_opaque;
commit 30fb2ca603e8b8d0f02630ef18bc0d0637a88ffa
Author: Amit Shah <amit.shah at redhat.com>
Date:   Wed Jul 20 13:30:56 2011 +0530

    balloon: Separate out stat and balloon handling
    
    Passing on '0' as ballooning target to indicate retrieval of stats is
    bad API.  It also makes 'balloon 0' in the monitor cause a segfault.
    Have two different functions handle the different functionality instead.
    
    Detailed explanation from Markus's review:
    
    1. do_info_balloon() is an info_async() method.  It receives a callback
       with argument, to be called exactly once (callback frees the
       argument).  It passes the callback via qemu_balloon_status() and
       indirectly through qemu_balloon_event to virtio_balloon_to_target().
    
       virtio_balloon_to_target() executes its balloon stats half.  It
       stores the callback in the device state.
    
       If it can't send a stats request, it resets stats and calls the
       callback right away.
    
       Else, it sends a stats request.  The device model runs the callback
       when it receives the answer.
    
       Works.
    
    2. do_balloon() is a cmd_async() method.  It receives a callback with
       argument, to be called when the command completes.  do_balloon()
       calls it right before it succeeds.  Odd, but should work.
    
       Nevertheless, it passes the callback on via qemu_ballon() and
       indirectly through qemu_balloon_event to virtio_balloon_to_target().
    
       a. If the argument is non-zero, virtio_balloon_to_target() executes
          its balloon half, which doesn't use the callback in any way.
    
          Odd, but works.
    
       b. If the argument is zero, virtio_balloon_to_target() executes its
          balloon stats half, just like in 1.  It either calls the callback
          right away, or arranges for it to be called later.
    
          Thus, the callback runs twice: use after free and double free.
    
    Test case: start with -S -device virtio-balloon, execute "balloon 0" in
    human monitor.  Runs the callback first from virtio_balloon_to_target(),
    then again from do_balloon().
    
    Reported-by: Mike Cao <bcao at redhat.com>
    Signed-off-by: Amit Shah <amit.shah at redhat.com>
    Reviewed-by: Markus Armbruster <armbru at redhat.com>

diff --git a/balloon.c b/balloon.c
index d40be39..8be3812 100644
--- a/balloon.c
+++ b/balloon.c
@@ -32,30 +32,33 @@
 
 
 static QEMUBalloonEvent *balloon_event_fn;
+static QEMUBalloonStatus *balloon_stat_fn;
 static void *balloon_opaque;
 
-void qemu_add_balloon_handler(QEMUBalloonEvent *func, void *opaque)
+void qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
+                              QEMUBalloonStatus *stat_func, void *opaque)
 {
-    balloon_event_fn = func;
+    balloon_event_fn = event_func;
+    balloon_stat_fn = stat_func;
     balloon_opaque = opaque;
 }
 
-static int qemu_balloon(ram_addr_t target, MonitorCompletion cb, void *opaque)
+static int qemu_balloon(ram_addr_t target)
 {
     if (!balloon_event_fn) {
         return 0;
     }
     trace_balloon_event(balloon_opaque, target);
-    balloon_event_fn(balloon_opaque, target, cb, opaque);
+    balloon_event_fn(balloon_opaque, target);
     return 1;
 }
 
 static int qemu_balloon_status(MonitorCompletion cb, void *opaque)
 {
-    if (!balloon_event_fn) {
+    if (!balloon_stat_fn) {
         return 0;
     }
-    balloon_event_fn(balloon_opaque, 0, cb, opaque);
+    balloon_stat_fn(balloon_opaque, cb, opaque);
     return 1;
 }
 
@@ -135,7 +138,7 @@ int do_balloon(Monitor *mon, const QDict *params,
         return -1;
     }
 
-    ret = qemu_balloon(qdict_get_int(params, "value"), cb, opaque);
+    ret = qemu_balloon(qdict_get_int(params, "value"));
     if (ret == 0) {
         qerror_report(QERR_DEVICE_NOT_ACTIVE, "balloon");
         return -1;
diff --git a/balloon.h b/balloon.h
index 06a8a46..a6c31d5 100644
--- a/balloon.h
+++ b/balloon.h
@@ -16,10 +16,12 @@
 
 #include "monitor.h"
 
-typedef void (QEMUBalloonEvent)(void *opaque, ram_addr_t target,
-                                MonitorCompletion cb, void *cb_data);
+typedef void (QEMUBalloonEvent)(void *opaque, ram_addr_t target);
+typedef void (QEMUBalloonStatus)(void *opaque, MonitorCompletion cb,
+                                 void *cb_data);
 
-void qemu_add_balloon_handler(QEMUBalloonEvent *func, void *opaque);
+void qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
+                              QEMUBalloonStatus *stat_func, void *opaque);
 
 void monitor_print_balloon(Monitor *mon, const QObject *data);
 int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque);
diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c
index 2f371f2..40b43b0 100644
--- a/hw/virtio-balloon.c
+++ b/hw/virtio-balloon.c
@@ -227,8 +227,7 @@ static void virtio_balloon_stat(void *opaque, MonitorCompletion cb,
     complete_stats_request(dev);
 }
 
-static void virtio_balloon_to_target(void *opaque, ram_addr_t target,
-                                     MonitorCompletion cb, void *cb_data)
+static void virtio_balloon_to_target(void *opaque, ram_addr_t target)
 {
     VirtIOBalloon *dev = opaque;
 
@@ -238,8 +237,6 @@ static void virtio_balloon_to_target(void *opaque, ram_addr_t target,
     if (target) {
         dev->num_pages = (ram_size - target) >> VIRTIO_BALLOON_PFN_SHIFT;
         virtio_notify_config(&dev->vdev);
-    } else {
-        virtio_balloon_stat(opaque, cb, cb_data);
     }
 }
 
@@ -284,7 +281,7 @@ VirtIODevice *virtio_balloon_init(DeviceState *dev)
     s->svq = virtio_add_queue(&s->vdev, 128, virtio_balloon_receive_stats);
 
     reset_stats(s);
-    qemu_add_balloon_handler(virtio_balloon_to_target, s);
+    qemu_add_balloon_handler(virtio_balloon_to_target, virtio_balloon_stat, s);
 
     register_savevm(dev, "virtio-balloon", -1, 1,
                     virtio_balloon_save, virtio_balloon_load, s);
commit dce911c753489609238f91d29bcf945c87a19911
Author: Amit Shah <amit.shah at redhat.com>
Date:   Wed Jul 20 13:19:07 2011 +0530

    virtio-balloon: Separate status handling into separate function
    
    Separate out the code to retrieve balloon info from the code that sets
    balloon values.
    
    This will be used to separate the two callbacks from balloon.c and help
    cope with 'balloon 0' on the monitor.  Currently, 'balloon 0' causes a
    segfault in monitor_resume().
    
    Signed-off-by: Amit Shah <amit.shah at redhat.com>
    Reviewed-by: Markus Armbruster <armbru at redhat.com>

diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c
index 70a8710..2f371f2 100644
--- a/hw/virtio-balloon.c
+++ b/hw/virtio-balloon.c
@@ -199,36 +199,47 @@ static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f)
     return f;
 }
 
+static void virtio_balloon_stat(void *opaque, MonitorCompletion cb,
+                                void *cb_data)
+{
+    VirtIOBalloon *dev = opaque;
+
+    /* For now, only allow one request at a time.  This restriction can be
+     * removed later by queueing callback and data pairs.
+     */
+    if (dev->stats_callback != NULL) {
+        return;
+    }
+    dev->stats_callback = cb;
+    dev->stats_opaque_callback_data = cb_data;
+
+    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);
+        return;
+    }
+
+    /* Stats are not supported.  Clear out any stale values that might
+     * have been set by a more featureful guest kernel.
+     */
+    reset_stats(dev);
+    complete_stats_request(dev);
+}
+
 static void virtio_balloon_to_target(void *opaque, ram_addr_t target,
                                      MonitorCompletion cb, void *cb_data)
 {
     VirtIOBalloon *dev = opaque;
 
-    if (target > ram_size)
+    if (target > ram_size) {
         target = ram_size;
-
+    }
     if (target) {
         dev->num_pages = (ram_size - target) >> VIRTIO_BALLOON_PFN_SHIFT;
         virtio_notify_config(&dev->vdev);
     } else {
-        /* For now, only allow one request at a time.  This restriction can be
-         * removed later by queueing callback and data pairs.
-         */
-        if (dev->stats_callback != NULL) {
-            return;
-        }
-        dev->stats_callback = cb;
-        dev->stats_opaque_callback_data = cb_data; 
-        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 {
-            /* Stats are not supported.  Clear out any stale values that might
-             * have been set by a more featureful guest kernel.
-             */
-            reset_stats(dev);
-            complete_stats_request(dev);
-        }
+        virtio_balloon_stat(opaque, cb, cb_data);
     }
 }
 
commit 182b9203f8f17198b1f818c23d80a2c698f29fa5
Author: Amit Shah <amit.shah at redhat.com>
Date:   Wed Jul 20 13:14:12 2011 +0530

    balloon: Simplify code flow
    
    Replace:
      if (foo) {
        ...
      } else {
        return 0;
      }
    
    by
    
      if (!foo) {
        return 0;
      }
      ...
    
    Signed-off-by: Amit Shah <amit.shah at redhat.com>
    Reviewed-by: Markus Armbruster <armbru at redhat.com>

diff --git a/balloon.c b/balloon.c
index 86f629e..d40be39 100644
--- a/balloon.c
+++ b/balloon.c
@@ -42,23 +42,21 @@ void qemu_add_balloon_handler(QEMUBalloonEvent *func, void *opaque)
 
 static int qemu_balloon(ram_addr_t target, MonitorCompletion cb, void *opaque)
 {
-    if (balloon_event_fn) {
-        trace_balloon_event(balloon_opaque, target);
-        balloon_event_fn(balloon_opaque, target, cb, opaque);
-        return 1;
-    } else {
+    if (!balloon_event_fn) {
         return 0;
     }
+    trace_balloon_event(balloon_opaque, target);
+    balloon_event_fn(balloon_opaque, target, cb, opaque);
+    return 1;
 }
 
 static int qemu_balloon_status(MonitorCompletion cb, void *opaque)
 {
-    if (balloon_event_fn) {
-        balloon_event_fn(balloon_opaque, 0, cb, opaque);
-        return 1;
-    } else {
+    if (!balloon_event_fn) {
         return 0;
     }
+    balloon_event_fn(balloon_opaque, 0, cb, opaque);
+    return 1;
 }
 
 static void print_balloon_stat(const char *key, QObject *obj, void *opaque)
commit b80bc1ddb2e5838f8bc86f7cc8a45d16c8d8dcba
Author: Amit Shah <amit.shah at redhat.com>
Date:   Wed Jul 20 13:12:15 2011 +0530

    balloon: Add braces around if statements
    
    Signed-off-by: Amit Shah <amit.shah at redhat.com>
    Reviewed-by: Markus Armbruster <armbru at redhat.com>

diff --git a/balloon.c b/balloon.c
index f9bcf07..86f629e 100644
--- a/balloon.c
+++ b/balloon.c
@@ -65,9 +65,10 @@ static void print_balloon_stat(const char *key, QObject *obj, void *opaque)
 {
     Monitor *mon = opaque;
 
-    if (strcmp(key, "actual"))
+    if (strcmp(key, "actual")) {
         monitor_printf(mon, ",%s=%" PRId64, key,
                        qint_get_int(qobject_to_qint(obj)));
+    }
 }
 
 void monitor_print_balloon(Monitor *mon, const QObject *data)
@@ -75,9 +76,9 @@ void monitor_print_balloon(Monitor *mon, const QObject *data)
     QDict *qdict;
 
     qdict = qobject_to_qdict(data);
-    if (!qdict_haskey(qdict, "actual"))
+    if (!qdict_haskey(qdict, "actual")) {
         return;
-
+    }
     monitor_printf(mon, "balloon: actual=%" PRId64,
                    qdict_get_int(qdict, "actual") >> 20);
     qdict_iter(qdict, print_balloon_stat, mon);
commit 0a2a30d5add5100d0c6cd4b466b227f7d76d19cf
Author: Amit Shah <amit.shah at redhat.com>
Date:   Wed Jul 20 13:08:46 2011 +0530

    balloon: Make functions, local vars static
    
    balloon.h had function declarations for a couple of functions that are
    local to balloon.c.  Make them static.
    
    Drop the 'qemu_' prefix for balloon.c-local variables, and make them
    static.
    
    Signed-off-by: Amit Shah <amit.shah at redhat.com>
    Reviewed-by: Markus Armbruster <armbru at redhat.com>

diff --git a/balloon.c b/balloon.c
index 248c1b5..f9bcf07 100644
--- a/balloon.c
+++ b/balloon.c
@@ -31,30 +31,30 @@
 #include "trace.h"
 
 
-static QEMUBalloonEvent *qemu_balloon_event;
-void *qemu_balloon_event_opaque;
+static QEMUBalloonEvent *balloon_event_fn;
+static void *balloon_opaque;
 
 void qemu_add_balloon_handler(QEMUBalloonEvent *func, void *opaque)
 {
-    qemu_balloon_event = func;
-    qemu_balloon_event_opaque = opaque;
+    balloon_event_fn = func;
+    balloon_opaque = opaque;
 }
 
-int qemu_balloon(ram_addr_t target, MonitorCompletion cb, void *opaque)
+static int qemu_balloon(ram_addr_t target, MonitorCompletion cb, void *opaque)
 {
-    if (qemu_balloon_event) {
-        trace_balloon_event(qemu_balloon_event_opaque, target);
-        qemu_balloon_event(qemu_balloon_event_opaque, target, cb, opaque);
+    if (balloon_event_fn) {
+        trace_balloon_event(balloon_opaque, target);
+        balloon_event_fn(balloon_opaque, target, cb, opaque);
         return 1;
     } else {
         return 0;
     }
 }
 
-int qemu_balloon_status(MonitorCompletion cb, void *opaque)
+static int qemu_balloon_status(MonitorCompletion cb, void *opaque)
 {
-    if (qemu_balloon_event) {
-        qemu_balloon_event(qemu_balloon_event_opaque, 0, cb, opaque);
+    if (balloon_event_fn) {
+        balloon_event_fn(balloon_opaque, 0, cb, opaque);
         return 1;
     } else {
         return 0;
diff --git a/balloon.h b/balloon.h
index d478e28..06a8a46 100644
--- a/balloon.h
+++ b/balloon.h
@@ -21,10 +21,6 @@ typedef void (QEMUBalloonEvent)(void *opaque, ram_addr_t target,
 
 void qemu_add_balloon_handler(QEMUBalloonEvent *func, void *opaque);
 
-int qemu_balloon(ram_addr_t target, MonitorCompletion cb, void *opaque);
-
-int qemu_balloon_status(MonitorCompletion cb, void *opaque);
-
 void monitor_print_balloon(Monitor *mon, const QObject *data);
 int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque);
 int do_balloon(Monitor *mon, const QDict *params,
commit fb8f4ceeb837a7410e018619daae6bc821060503
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Jul 15 16:14:59 2011 +0200

    bluetooth: kill dummy usb device, use hid code directly.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/bt-hid.c b/hw/bt-hid.c
index a4204f9..5f1afe3 100644
--- a/hw/bt-hid.c
+++ b/hw/bt-hid.c
@@ -19,7 +19,9 @@
  */
 
 #include "qemu-common.h"
-#include "usb.h"
+#include "qemu-timer.h"
+#include "console.h"
+#include "hid.h"
 #include "bt.h"
 
 enum hid_transaction_req {
@@ -86,7 +88,7 @@ struct bt_hid_device_s {
     struct bt_l2cap_device_s btdev;
     struct bt_l2cap_conn_params_s *control;
     struct bt_l2cap_conn_params_s *interrupt;
-    USBDevice *usbdev;
+    HIDState hid;
 
     int proto;
     int connected;
@@ -111,7 +113,7 @@ static void bt_hid_reset(struct bt_hid_device_s *s)
     bt_l2cap_device_done(&s->btdev);
     bt_l2cap_device_init(&s->btdev, net);
 
-    s->usbdev->info->handle_reset(s->usbdev);
+    hid_reset(&s->hid);
     s->proto = BT_HID_PROTO_REPORT;
     s->state = bt_state_ready;
     s->dataother.len = 0;
@@ -124,23 +126,16 @@ static void bt_hid_reset(struct bt_hid_device_s *s)
 
 static int bt_hid_out(struct bt_hid_device_s *s)
 {
-    USBPacket p;
-
     if (s->data_type == BT_DATA_OUTPUT) {
-        usb_packet_init(&p);
-        usb_packet_setup(&p, USB_TOKEN_OUT, 0, 1);
-        usb_packet_addbuf(&p, s->dataout.buffer, s->dataout.len);
-        s->dataout.len = s->usbdev->info->handle_data(s->usbdev, &p);
-        usb_packet_cleanup(&p);
-
-        return s->dataout.len;
+        /* nothing */
+        ;
     }
 
     if (s->data_type == BT_DATA_FEATURE) {
         /* XXX:
          * does this send a USB_REQ_CLEAR_FEATURE/USB_REQ_SET_FEATURE
          * or a SET_REPORT? */
-        p.devep = 0;
+        ;
     }
 
     return -1;
@@ -148,14 +143,8 @@ static int bt_hid_out(struct bt_hid_device_s *s)
 
 static int bt_hid_in(struct bt_hid_device_s *s)
 {
-    USBPacket p;
-
-    usb_packet_init(&p);
-    usb_packet_setup(&p, USB_TOKEN_IN, 0, 1);
-    usb_packet_addbuf(&p, s->dataout.buffer, sizeof(s->datain.buffer));
-    s->datain.len = s->usbdev->info->handle_data(s->usbdev, &p);
-    usb_packet_cleanup(&p);
-
+    s->datain.len = hid_keyboard_poll(&s->hid, s->datain.buffer,
+                                      sizeof(s->datain.buffer));
     return s->datain.len;
 }
 
@@ -323,8 +312,7 @@ static void bt_hid_control_transaction(struct bt_hid_device_s *s,
             break;
         }
         s->proto = parameter;
-        s->usbdev->info->handle_control(s->usbdev, NULL, SET_PROTOCOL, s->proto, 0, 0,
-                                        NULL);
+        s->hid.protocol = parameter;
         ret = BT_HS_SUCCESSFUL;
         break;
 
@@ -333,8 +321,7 @@ static void bt_hid_control_transaction(struct bt_hid_device_s *s,
             ret = BT_HS_ERR_INVALID_PARAMETER;
             break;
         }
-        s->usbdev->info->handle_control(s->usbdev, NULL, GET_IDLE, 0, 0, 1,
-                        s->control->sdu_out(s->control, 1));
+        *s->control->sdu_out(s->control, 1) = s->hid.idle;
         s->control->sdu_submit(s->control);
         break;
 
@@ -344,11 +331,7 @@ static void bt_hid_control_transaction(struct bt_hid_device_s *s,
             break;
         }
 
-        /* We don't need to know about the Idle Rate here really,
-         * so just pass it on to the device.  */
-        ret = s->usbdev->info->handle_control(s->usbdev, NULL,
-                        SET_IDLE, data[1], 0, 0, NULL) ?
-                BT_HS_SUCCESSFUL : BT_HS_ERR_INVALID_PARAMETER;
+        s->hid.idle = data[1];
         /* XXX: Does this generate a handshake? */
         break;
 
@@ -385,9 +368,10 @@ static void bt_hid_control_sdu(void *opaque, const uint8_t *data, int len)
     bt_hid_control_transaction(hid, data, len);
 }
 
-static void bt_hid_datain(void *opaque)
+static void bt_hid_datain(HIDState *hs)
 {
-    struct bt_hid_device_s *hid = opaque;
+    struct bt_hid_device_s *hid =
+        container_of(hs, struct bt_hid_device_s, hid);
 
     /* If suspended, wake-up and send a wake-up event first.  We might
      * want to also inspect the input report and ignore event like
@@ -450,7 +434,7 @@ static void bt_hid_connected_update(struct bt_hid_device_s *hid)
     hid->btdev.device.inquiry_scan = !hid->connected;
 
     if (hid->connected && !prev) {
-        hid->usbdev->info->handle_reset(hid->usbdev);
+        hid_reset(&hid->hid);
         hid->proto = BT_HID_PROTO_REPORT;
     }
 
@@ -518,7 +502,7 @@ static void bt_hid_destroy(struct bt_device_s *dev)
         bt_hid_send_control(hid, BT_HC_VIRTUAL_CABLE_UNPLUG);
     bt_l2cap_device_done(&hid->btdev);
 
-    hid->usbdev->info->handle_destroy(hid->usbdev);
+    hid_free(&hid->hid);
 
     qemu_free(hid);
 }
@@ -531,7 +515,7 @@ enum peripheral_minor_class {
 };
 
 static struct bt_device_s *bt_hid_init(struct bt_scatternet_s *net,
-                USBDevice *dev, enum peripheral_minor_class minor)
+                                       enum peripheral_minor_class minor)
 {
     struct bt_hid_device_s *s = qemu_mallocz(sizeof(*s));
     uint32_t class =
@@ -551,9 +535,8 @@ static struct bt_device_s *bt_hid_init(struct bt_scatternet_s *net,
     bt_l2cap_psm_register(&s->btdev, BT_PSM_HID_INTR,
                     BT_HID_MTU, bt_hid_new_interrupt_ch);
 
-    s->usbdev = dev;
-    s->btdev.device.lmp_name = s->usbdev->product_desc;
-    usb_hid_datain_cb(s->usbdev, s, bt_hid_datain);
+    hid_init(&s->hid, HID_KEYBOARD, bt_hid_datain);
+    s->btdev.device.lmp_name = "BT Keyboard";
 
     s->btdev.device.handle_destroy = bt_hid_destroy;
 
@@ -566,6 +549,5 @@ static struct bt_device_s *bt_hid_init(struct bt_scatternet_s *net,
 
 struct bt_device_s *bt_keyboard_init(struct bt_scatternet_s *net)
 {
-    USBDevice *dev = usb_create_simple(NULL /* FIXME */, "usb-kbd");
-    return bt_hid_init(net, dev, class_keyboard);
+    return bt_hid_init(net, class_keyboard);
 }
commit b069d3488f327da97fb0da1939518a00637f01a3
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Jul 15 15:52:33 2011 +0200

    hid: move idle+protocol from usb-hid to hid too.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/hid.c b/hw/hid.c
index 1893ae5..7b5ef5f 100644
--- a/hw/hid.c
+++ b/hw/hid.c
@@ -24,6 +24,7 @@
  */
 #include "hw.h"
 #include "console.h"
+#include "qemu-timer.h"
 #include "hid.h"
 
 #define HID_USAGE_ERROR_ROLLOVER        0x01
@@ -73,6 +74,11 @@ bool hid_has_events(HIDState *hs)
     return hs->n > 0;
 }
 
+void hid_set_next_idle(HIDState *hs, int64_t curtime)
+{
+    hs->next_idle_clock = curtime + (get_ticks_per_sec() * hs->idle * 4) / 1000;
+}
+
 static void hid_pointer_event_clear(HIDPointerEvent *e, int buttons)
 {
     e->xdx = e->ydy = e->dz = 0;
@@ -365,6 +371,8 @@ void hid_reset(HIDState *hs)
     }
     hs->head = 0;
     hs->n = 0;
+    hs->protocol = 1;
+    hs->idle = 0;
 }
 
 void hid_free(HIDState *hs)
diff --git a/hw/hid.h b/hw/hid.h
index 99910c3..4a8fa5b 100644
--- a/hw/hid.h
+++ b/hw/hid.h
@@ -39,6 +39,9 @@ struct HIDState {
     uint32_t head; /* index into circular queue */
     uint32_t n;
     int kind;
+    int32_t protocol;
+    uint8_t idle;
+    int64_t next_idle_clock;
     HIDEventFunc event;
 };
 
@@ -47,6 +50,7 @@ void hid_reset(HIDState *hs);
 void hid_free(HIDState *hs);
 
 bool hid_has_events(HIDState *hs);
+void hid_set_next_idle(HIDState *hs, int64_t curtime);
 int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len);
 int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len);
 int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len);
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index 48ce743..e5d57de 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -45,9 +45,6 @@
 typedef struct USBHIDState {
     USBDevice dev;
     HIDState hid;
-    int32_t protocol;
-    uint8_t idle;
-    int64_t next_idle_clock;
     void *datain_opaque;
     void (*datain)(void *);
 } USBHIDState;
@@ -377,13 +374,6 @@ static void usb_hid_handle_reset(USBDevice *dev)
     USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
 
     hid_reset(&us->hid);
-    us->protocol = 1;
-    us->idle = 0;
-}
-
-static void usb_hid_set_next_idle(USBHIDState *s, int64_t curtime)
-{
-    s->next_idle_clock = curtime + (get_ticks_per_sec() * s->idle * 4) / 1000;
 }
 
 static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
@@ -448,22 +438,22 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
             goto fail;
         }
         ret = 1;
-        data[0] = us->protocol;
+        data[0] = hs->protocol;
         break;
     case SET_PROTOCOL:
         if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
             goto fail;
         }
         ret = 0;
-        us->protocol = value;
+        hs->protocol = value;
         break;
     case GET_IDLE:
         ret = 1;
-        data[0] = us->idle;
+        data[0] = hs->idle;
         break;
     case SET_IDLE:
-        us->idle = (uint8_t) (value >> 8);
-        usb_hid_set_next_idle(us, qemu_get_clock_ns(vm_clock));
+        hs->idle = (uint8_t) (value >> 8);
+        hid_set_next_idle(hs, qemu_get_clock_ns(vm_clock));
         ret = 0;
         break;
     default:
@@ -486,10 +476,10 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
         if (p->devep == 1) {
             int64_t curtime = qemu_get_clock_ns(vm_clock);
             if (!hid_has_events(hs) &&
-                (!us->idle || us->next_idle_clock - curtime > 0)) {
+                (!hs->idle || hs->next_idle_clock - curtime > 0)) {
                 return USB_RET_NAK;
             }
-            usb_hid_set_next_idle(us, curtime);
+            hid_set_next_idle(hs, curtime);
             if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
                 ret = hid_pointer_poll(hs, buf, p->iov.size);
             } else if (hs->kind == HID_KEYBOARD) {
@@ -552,8 +542,8 @@ static int usb_hid_post_load(void *opaque, int version_id)
 {
     USBHIDState *s = opaque;
 
-    if (s->idle) {
-        usb_hid_set_next_idle(s, qemu_get_clock_ns(vm_clock));
+    if (s->hid.idle) {
+        hid_set_next_idle(&s->hid, qemu_get_clock_ns(vm_clock));
     }
     return 0;
 }
@@ -581,8 +571,8 @@ static const VMStateDescription vmstate_usb_ptr = {
                              vmstate_usb_ptr_queue, HIDPointerEvent),
         VMSTATE_UINT32(hid.head, USBHIDState),
         VMSTATE_UINT32(hid.n, USBHIDState),
-        VMSTATE_INT32(protocol, USBHIDState),
-        VMSTATE_UINT8(idle, USBHIDState),
+        VMSTATE_INT32(hid.protocol, USBHIDState),
+        VMSTATE_UINT8(hid.idle, USBHIDState),
         VMSTATE_END_OF_LIST()
     }
 };
@@ -601,8 +591,8 @@ static const VMStateDescription vmstate_usb_kbd = {
         VMSTATE_UINT8(hid.kbd.leds, USBHIDState),
         VMSTATE_UINT8_ARRAY(hid.kbd.key, USBHIDState, 16),
         VMSTATE_INT32(hid.kbd.keys, USBHIDState),
-        VMSTATE_INT32(protocol, USBHIDState),
-        VMSTATE_UINT8(idle, USBHIDState),
+        VMSTATE_INT32(hid.protocol, USBHIDState),
+        VMSTATE_UINT8(hid.idle, USBHIDState),
         VMSTATE_END_OF_LIST()
     }
 };
commit dcfda673101313472524bfac8c2fe2e1d03c8214
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Jul 15 15:08:01 2011 +0200

    usb-hid: split hid code to hw/hid.[ch]
    
    Almost pure code motion.  Unstatic hid interface functions and add
    them to the header file.  Some renames.  Some code style cleanups.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/Makefile.objs b/Makefile.objs
index 3d1a4de..eb5e1dc 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -89,6 +89,7 @@ common-obj-y += i2c.o smbus.o smbus_eeprom.o
 common-obj-y += eeprom93xx.o
 common-obj-y += scsi-disk.o cdrom.o
 common-obj-y += scsi-generic.o scsi-bus.o
+common-obj-y += hid.o
 common-obj-y += usb.o usb-hub.o usb-$(HOST_USB).o usb-hid.o usb-msd.o usb-wacom.o
 common-obj-y += usb-serial.o usb-net.o usb-bus.o usb-desc.o
 common-obj-$(CONFIG_SSI) += ssi.o
diff --git a/hw/hid.c b/hw/hid.c
new file mode 100644
index 0000000..1893ae5
--- /dev/null
+++ b/hw/hid.c
@@ -0,0 +1,395 @@
+/*
+ * QEMU HID devices
+ *
+ * Copyright (c) 2005 Fabrice Bellard
+ * Copyright (c) 2007 OpenMoko, Inc.  (andrew at openedhand.com)
+ *
+ * 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 "hw.h"
+#include "console.h"
+#include "hid.h"
+
+#define HID_USAGE_ERROR_ROLLOVER        0x01
+#define HID_USAGE_POSTFAIL              0x02
+#define HID_USAGE_ERROR_UNDEFINED       0x03
+
+/* Indices are QEMU keycodes, values are from HID Usage Table.  Indices
+ * above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d.  */
+static const uint8_t hid_usage_keys[0x100] = {
+    0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
+    0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b,
+    0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c,
+    0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16,
+    0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33,
+    0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19,
+    0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55,
+    0xe2, 0x2c, 0x32, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
+    0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f,
+    0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59,
+    0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x00, 0x44,
+    0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
+    0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65,
+
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46,
+    0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a,
+    0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d,
+    0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+bool hid_has_events(HIDState *hs)
+{
+    return hs->n > 0;
+}
+
+static void hid_pointer_event_clear(HIDPointerEvent *e, int buttons)
+{
+    e->xdx = e->ydy = e->dz = 0;
+    e->buttons_state = buttons;
+}
+
+static void hid_pointer_event_combine(HIDPointerEvent *e, int xyrel,
+                                      int x1, int y1, int z1) {
+    if (xyrel) {
+        e->xdx += x1;
+        e->ydy += y1;
+    } else {
+        e->xdx = x1;
+        e->ydy = y1;
+        /* Windows drivers do not like the 0/0 position and ignore such
+         * events. */
+        if (!(x1 | y1)) {
+            x1 = 1;
+        }
+    }
+    e->dz += z1;
+}
+
+static void hid_pointer_event(void *opaque,
+                              int x1, int y1, int z1, int buttons_state)
+{
+    HIDState *hs = opaque;
+    unsigned use_slot = (hs->head + hs->n - 1) & QUEUE_MASK;
+    unsigned previous_slot = (use_slot - 1) & QUEUE_MASK;
+
+    /* We combine events where feasible to keep the queue small.  We shouldn't
+     * combine anything with the first event of a particular button state, as
+     * that would change the location of the button state change.  When the
+     * queue is empty, a second event is needed because we don't know if
+     * the first event changed the button state.  */
+    if (hs->n == QUEUE_LENGTH) {
+        /* Queue full.  Discard old button state, combine motion normally.  */
+        hs->ptr.queue[use_slot].buttons_state = buttons_state;
+    } else if (hs->n < 2 ||
+               hs->ptr.queue[use_slot].buttons_state != buttons_state ||
+               hs->ptr.queue[previous_slot].buttons_state !=
+               hs->ptr.queue[use_slot].buttons_state) {
+        /* Cannot or should not combine, so add an empty item to the queue.  */
+        QUEUE_INCR(use_slot);
+        hs->n++;
+        hid_pointer_event_clear(&hs->ptr.queue[use_slot], buttons_state);
+    }
+    hid_pointer_event_combine(&hs->ptr.queue[use_slot],
+                              hs->kind == HID_MOUSE,
+                              x1, y1, z1);
+    hs->event(hs);
+}
+
+static void hid_keyboard_event(void *opaque, int keycode)
+{
+    HIDState *hs = opaque;
+    int slot;
+
+    if (hs->n == QUEUE_LENGTH) {
+        fprintf(stderr, "usb-kbd: warning: key event queue full\n");
+        return;
+    }
+    slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
+    hs->kbd.keycodes[slot] = keycode;
+    hs->event(hs);
+}
+
+static void hid_keyboard_process_keycode(HIDState *hs)
+{
+    uint8_t hid_code, key;
+    int i, keycode, slot;
+
+    if (hs->n == 0) {
+        return;
+    }
+    slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--;
+    keycode = hs->kbd.keycodes[slot];
+
+    key = keycode & 0x7f;
+    hid_code = hid_usage_keys[key | ((hs->kbd.modifiers >> 1) & (1 << 7))];
+    hs->kbd.modifiers &= ~(1 << 8);
+
+    switch (hid_code) {
+    case 0x00:
+        return;
+
+    case 0xe0:
+        if (hs->kbd.modifiers & (1 << 9)) {
+            hs->kbd.modifiers ^= 3 << 8;
+            return;
+        }
+    case 0xe1 ... 0xe7:
+        if (keycode & (1 << 7)) {
+            hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f));
+            return;
+        }
+    case 0xe8 ... 0xef:
+        hs->kbd.modifiers |= 1 << (hid_code & 0x0f);
+        return;
+    }
+
+    if (keycode & (1 << 7)) {
+        for (i = hs->kbd.keys - 1; i >= 0; i--) {
+            if (hs->kbd.key[i] == hid_code) {
+                hs->kbd.key[i] = hs->kbd.key[-- hs->kbd.keys];
+                hs->kbd.key[hs->kbd.keys] = 0x00;
+                break;
+            }
+        }
+        if (i < 0) {
+            return;
+        }
+    } else {
+        for (i = hs->kbd.keys - 1; i >= 0; i--) {
+            if (hs->kbd.key[i] == hid_code) {
+                break;
+            }
+        }
+        if (i < 0) {
+            if (hs->kbd.keys < sizeof(hs->kbd.key)) {
+                hs->kbd.key[hs->kbd.keys++] = hid_code;
+            }
+        } else {
+            return;
+        }
+    }
+}
+
+static inline int int_clamp(int val, int vmin, int vmax)
+{
+    if (val < vmin) {
+        return vmin;
+    } else if (val > vmax) {
+        return vmax;
+    } else {
+        return val;
+    }
+}
+
+int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
+{
+    int dx, dy, dz, b, l;
+    int index;
+    HIDPointerEvent *e;
+
+    if (!hs->ptr.mouse_grabbed) {
+        qemu_activate_mouse_event_handler(hs->ptr.eh_entry);
+        hs->ptr.mouse_grabbed = 1;
+    }
+
+    /* When the buffer is empty, return the last event.  Relative
+       movements will all be zero.  */
+    index = (hs->n ? hs->head : hs->head - 1);
+    e = &hs->ptr.queue[index & QUEUE_MASK];
+
+    if (hs->kind == HID_MOUSE) {
+        dx = int_clamp(e->xdx, -127, 127);
+        dy = int_clamp(e->ydy, -127, 127);
+        e->xdx -= dx;
+        e->ydy -= dy;
+    } else {
+        dx = e->xdx;
+        dy = e->ydy;
+    }
+    dz = int_clamp(e->dz, -127, 127);
+    e->dz -= dz;
+
+    b = 0;
+    if (e->buttons_state & MOUSE_EVENT_LBUTTON) {
+        b |= 0x01;
+    }
+    if (e->buttons_state & MOUSE_EVENT_RBUTTON) {
+        b |= 0x02;
+    }
+    if (e->buttons_state & MOUSE_EVENT_MBUTTON) {
+        b |= 0x04;
+    }
+
+    if (hs->n &&
+        !e->dz &&
+        (hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) {
+        /* that deals with this event */
+        QUEUE_INCR(hs->head);
+        hs->n--;
+    }
+
+    /* Appears we have to invert the wheel direction */
+    dz = 0 - dz;
+    l = 0;
+    switch (hs->kind) {
+    case HID_MOUSE:
+        if (len > l) {
+            buf[l++] = b;
+        }
+        if (len > l) {
+            buf[l++] = dx;
+        }
+        if (len > l) {
+            buf[l++] = dy;
+        }
+        if (len > l) {
+            buf[l++] = dz;
+        }
+        break;
+
+    case HID_TABLET:
+        if (len > l) {
+            buf[l++] = b;
+        }
+        if (len > l) {
+            buf[l++] = dx & 0xff;
+        }
+        if (len > l) {
+            buf[l++] = dx >> 8;
+        }
+        if (len > l) {
+            buf[l++] = dy & 0xff;
+        }
+        if (len > l) {
+            buf[l++] = dy >> 8;
+        }
+        if (len > l) {
+            buf[l++] = dz;
+        }
+        break;
+
+    default:
+        abort();
+    }
+
+    return l;
+}
+
+int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len)
+{
+    if (len < 2) {
+        return 0;
+    }
+
+    hid_keyboard_process_keycode(hs);
+
+    buf[0] = hs->kbd.modifiers & 0xff;
+    buf[1] = 0;
+    if (hs->kbd.keys > 6) {
+        memset(buf + 2, HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2);
+    } else {
+        memcpy(buf + 2, hs->kbd.key, MIN(8, len) - 2);
+    }
+
+    return MIN(8, len);
+}
+
+int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len)
+{
+    if (len > 0) {
+        int ledstate = 0;
+        /* 0x01: Num Lock LED
+         * 0x02: Caps Lock LED
+         * 0x04: Scroll Lock LED
+         * 0x08: Compose LED
+         * 0x10: Kana LED */
+        hs->kbd.leds = buf[0];
+        if (hs->kbd.leds & 0x04) {
+            ledstate |= QEMU_SCROLL_LOCK_LED;
+        }
+        if (hs->kbd.leds & 0x01) {
+            ledstate |= QEMU_NUM_LOCK_LED;
+        }
+        if (hs->kbd.leds & 0x02) {
+            ledstate |= QEMU_CAPS_LOCK_LED;
+        }
+        kbd_put_ledstate(ledstate);
+    }
+    return 0;
+}
+
+void hid_reset(HIDState *hs)
+{
+    switch (hs->kind) {
+    case HID_KEYBOARD:
+        qemu_add_kbd_event_handler(hid_keyboard_event, hs);
+        memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes));
+        memset(hs->kbd.key, 0, sizeof(hs->kbd.key));
+        hs->kbd.keys = 0;
+        break;
+    case HID_MOUSE:
+    case HID_TABLET:
+        memset(hs->ptr.queue, 0, sizeof(hs->ptr.queue));
+        break;
+    }
+    hs->head = 0;
+    hs->n = 0;
+}
+
+void hid_free(HIDState *hs)
+{
+    switch (hs->kind) {
+    case HID_KEYBOARD:
+        qemu_remove_kbd_event_handler();
+        break;
+    case HID_MOUSE:
+    case HID_TABLET:
+        qemu_remove_mouse_event_handler(hs->ptr.eh_entry);
+        break;
+    }
+}
+
+void hid_init(HIDState *hs, int kind, HIDEventFunc event)
+{
+    hs->kind = kind;
+    hs->event = event;
+
+    if (hs->kind == HID_MOUSE) {
+        hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
+                                                        0, "QEMU HID Mouse");
+    } else if (hs->kind == HID_TABLET) {
+        hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
+                                                        1, "QEMU HID Tablet");
+    }
+}
diff --git a/hw/hid.h b/hw/hid.h
new file mode 100644
index 0000000..99910c3
--- /dev/null
+++ b/hw/hid.h
@@ -0,0 +1,54 @@
+#ifndef QEMU_HID_H
+#define QEMU_HID_H
+
+#define HID_MOUSE     1
+#define HID_TABLET    2
+#define HID_KEYBOARD  3
+
+typedef struct HIDPointerEvent {
+    int32_t xdx, ydy; /* relative iff it's a mouse, otherwise absolute */
+    int32_t dz, buttons_state;
+} HIDPointerEvent;
+
+#define QUEUE_LENGTH    16 /* should be enough for a triple-click */
+#define QUEUE_MASK      (QUEUE_LENGTH-1u)
+#define QUEUE_INCR(v)   ((v)++, (v) &= QUEUE_MASK)
+
+typedef struct HIDState HIDState;
+typedef void (*HIDEventFunc)(HIDState *s);
+
+typedef struct HIDMouseState {
+    HIDPointerEvent queue[QUEUE_LENGTH];
+    int mouse_grabbed;
+    QEMUPutMouseEntry *eh_entry;
+} HIDMouseState;
+
+typedef struct HIDKeyboardState {
+    uint32_t keycodes[QUEUE_LENGTH];
+    uint16_t modifiers;
+    uint8_t leds;
+    uint8_t key[16];
+    int32_t keys;
+} HIDKeyboardState;
+
+struct HIDState {
+    union {
+        HIDMouseState ptr;
+        HIDKeyboardState kbd;
+    };
+    uint32_t head; /* index into circular queue */
+    uint32_t n;
+    int kind;
+    HIDEventFunc event;
+};
+
+void hid_init(HIDState *hs, int kind, HIDEventFunc event);
+void hid_reset(HIDState *hs);
+void hid_free(HIDState *hs);
+
+bool hid_has_events(HIDState *hs);
+int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len);
+int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len);
+int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len);
+
+#endif /* QEMU_HID_H */
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index b730692..48ce743 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -27,6 +27,7 @@
 #include "usb.h"
 #include "usb-desc.h"
 #include "qemu-timer.h"
+#include "hid.h"
 
 /* HID interface requests */
 #define GET_REPORT   0xa101
@@ -41,47 +42,6 @@
 #define USB_DT_REPORT 0x22
 #define USB_DT_PHY    0x23
 
-#define HID_MOUSE     1
-#define HID_TABLET    2
-#define HID_KEYBOARD  3
-
-typedef struct HIDPointerEvent {
-    int32_t xdx, ydy; /* relative iff it's a mouse, otherwise absolute */
-    int32_t dz, buttons_state;
-} HIDPointerEvent;
-
-#define QUEUE_LENGTH    16 /* should be enough for a triple-click */
-#define QUEUE_MASK      (QUEUE_LENGTH-1u)
-#define QUEUE_INCR(v)   ((v)++, (v) &= QUEUE_MASK)
-
-typedef struct HIDState HIDState;
-typedef void (*HIDEventFunc)(HIDState *s);
-
-typedef struct HIDMouseState {
-    HIDPointerEvent queue[QUEUE_LENGTH];
-    int mouse_grabbed;
-    QEMUPutMouseEntry *eh_entry;
-} HIDMouseState;
-
-typedef struct HIDKeyboardState {
-    uint32_t keycodes[QUEUE_LENGTH];
-    uint16_t modifiers;
-    uint8_t leds;
-    uint8_t key[16];
-    int32_t keys;
-} HIDKeyboardState;
-
-struct HIDState {
-    union {
-        HIDMouseState ptr;
-        HIDKeyboardState kbd;
-    };
-    uint32_t head; /* index into circular queue */
-    uint32_t n;
-    int kind;
-    HIDEventFunc event;
-};
-
 typedef struct USBHIDState {
     USBDevice dev;
     HIDState hid;
@@ -401,53 +361,6 @@ static const uint8_t qemu_keyboard_hid_report_descriptor[] = {
     0xc0,		/* End Collection */
 };
 
-#define USB_HID_USAGE_ERROR_ROLLOVER	0x01
-#define USB_HID_USAGE_POSTFAIL		0x02
-#define USB_HID_USAGE_ERROR_UNDEFINED	0x03
-
-/* Indices are QEMU keycodes, values are from HID Usage Table.  Indices
- * above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d.  */
-static const uint8_t usb_hid_usage_keys[0x100] = {
-    0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
-    0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b,
-    0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c,
-    0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16,
-    0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33,
-    0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19,
-    0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55,
-    0xe2, 0x2c, 0x32, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
-    0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f,
-    0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59,
-    0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x00, 0x44,
-    0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
-    0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65,
-
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46,
-    0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a,
-    0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d,
-    0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-static bool hid_has_events(HIDState *hs)
-{
-    return hs->n > 0;
-}
-
 static void usb_hid_changed(HIDState *hs)
 {
     USBHIDState *us = container_of(hs, USBHIDState, hid);
@@ -459,290 +372,11 @@ static void usb_hid_changed(HIDState *hs)
     usb_wakeup(&us->dev);
 }
 
-static void hid_pointer_event_clear(HIDPointerEvent *e, int buttons)
-{
-    e->xdx = e->ydy = e->dz = 0;
-    e->buttons_state = buttons;
-}
-
-static void hid_pointer_event_combine(HIDPointerEvent *e, int xyrel,
-                                      int x1, int y1, int z1) {
-    if (xyrel) {
-        e->xdx += x1;
-        e->ydy += y1;
-    } else {
-        e->xdx = x1;
-        e->ydy = y1;
-        /* Windows drivers do not like the 0/0 position and ignore such
-         * events. */
-        if (!(x1 | y1)) {
-            x1 = 1;
-        }
-    }
-    e->dz += z1;
-}
-
-static void hid_pointer_event(void *opaque,
-                              int x1, int y1, int z1, int buttons_state)
-{
-    HIDState *hs = opaque;
-    unsigned use_slot = (hs->head + hs->n - 1) & QUEUE_MASK;
-    unsigned previous_slot = (use_slot - 1) & QUEUE_MASK;
-
-    /* We combine events where feasible to keep the queue small.  We shouldn't
-     * combine anything with the first event of a particular button state, as
-     * that would change the location of the button state change.  When the
-     * queue is empty, a second event is needed because we don't know if
-     * the first event changed the button state.  */
-    if (hs->n == QUEUE_LENGTH) {
-        /* Queue full.  Discard old button state, combine motion normally.  */
-        hs->ptr.queue[use_slot].buttons_state = buttons_state;
-    } else if (hs->n < 2 ||
-               hs->ptr.queue[use_slot].buttons_state != buttons_state ||
-               hs->ptr.queue[previous_slot].buttons_state !=
-               hs->ptr.queue[use_slot].buttons_state) {
-        /* Cannot or should not combine, so add an empty item to the queue.  */
-        QUEUE_INCR(use_slot);
-        hs->n++;
-        hid_pointer_event_clear(&hs->ptr.queue[use_slot], buttons_state);
-    }
-    hid_pointer_event_combine(&hs->ptr.queue[use_slot],
-                              hs->kind == HID_MOUSE,
-                              x1, y1, z1);
-    hs->event(hs);
-}
-
-static void hid_keyboard_event(void *opaque, int keycode)
-{
-    HIDState *hs = opaque;
-    int slot;
-
-    if (hs->n == QUEUE_LENGTH) {
-        fprintf(stderr, "usb-kbd: warning: key event queue full\n");
-        return;
-    }
-    slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
-    hs->kbd.keycodes[slot] = keycode;
-    hs->event(hs);
-}
-
-static void hid_keyboard_process_keycode(HIDState *hs)
-{
-    uint8_t hid_code, key;
-    int i, keycode, slot;
-
-    if (hs->n == 0) {
-        return;
-    }
-    slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--;
-    keycode = hs->kbd.keycodes[slot];
-
-    key = keycode & 0x7f;
-    hid_code = usb_hid_usage_keys[key | ((hs->kbd.modifiers >> 1) & (1 << 7))];
-    hs->kbd.modifiers &= ~(1 << 8);
-
-    switch (hid_code) {
-    case 0x00:
-        return;
-
-    case 0xe0:
-        if (hs->kbd.modifiers & (1 << 9)) {
-            hs->kbd.modifiers ^= 3 << 8;
-            return;
-        }
-    case 0xe1 ... 0xe7:
-        if (keycode & (1 << 7)) {
-            hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f));
-            return;
-        }
-    case 0xe8 ... 0xef:
-        hs->kbd.modifiers |= 1 << (hid_code & 0x0f);
-        return;
-    }
-
-    if (keycode & (1 << 7)) {
-        for (i = hs->kbd.keys - 1; i >= 0; i--) {
-            if (hs->kbd.key[i] == hid_code) {
-                hs->kbd.key[i] = hs->kbd.key[-- hs->kbd.keys];
-                hs->kbd.key[hs->kbd.keys] = 0x00;
-                break;
-            }
-        }
-        if (i < 0) {
-            return;
-        }
-    } else {
-        for (i = hs->kbd.keys - 1; i >= 0; i--) {
-            if (hs->kbd.key[i] == hid_code) {
-                break;
-            }
-        }
-        if (i < 0) {
-            if (hs->kbd.keys < sizeof(hs->kbd.key)) {
-                hs->kbd.key[hs->kbd.keys++] = hid_code;
-            }
-        } else {
-            return;
-        }
-    }
-}
-
-static inline int int_clamp(int val, int vmin, int vmax)
-{
-    if (val < vmin)
-        return vmin;
-    else if (val > vmax)
-        return vmax;
-    else
-        return val;
-}
-
-static int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
-{
-    int dx, dy, dz, b, l;
-    int index;
-    HIDPointerEvent *e;
-
-    if (!hs->ptr.mouse_grabbed) {
-        qemu_activate_mouse_event_handler(hs->ptr.eh_entry);
-        hs->ptr.mouse_grabbed = 1;
-    }
-
-    /* When the buffer is empty, return the last event.  Relative
-       movements will all be zero.  */
-    index = (hs->n ? hs->head : hs->head - 1);
-    e = &hs->ptr.queue[index & QUEUE_MASK];
-
-    if (hs->kind == HID_MOUSE) {
-        dx = int_clamp(e->xdx, -127, 127);
-        dy = int_clamp(e->ydy, -127, 127);
-        e->xdx -= dx;
-        e->ydy -= dy;
-    } else {
-        dx = e->xdx;
-        dy = e->ydy;
-    }
-    dz = int_clamp(e->dz, -127, 127);
-    e->dz -= dz;
-
-    b = 0;
-    if (e->buttons_state & MOUSE_EVENT_LBUTTON)
-        b |= 0x01;
-    if (e->buttons_state & MOUSE_EVENT_RBUTTON)
-        b |= 0x02;
-    if (e->buttons_state & MOUSE_EVENT_MBUTTON)
-        b |= 0x04;
-
-    if (hs->n &&
-        !e->dz &&
-        (hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) {
-        /* that deals with this event */
-        QUEUE_INCR(hs->head);
-        hs->n--;
-    }
-
-    /* Appears we have to invert the wheel direction */
-    dz = 0 - dz;
-    l = 0;
-    switch (hs->kind) {
-    case HID_MOUSE:
-        if (len > l)
-            buf[l++] = b;
-        if (len > l)
-            buf[l++] = dx;
-        if (len > l)
-            buf[l++] = dy;
-        if (len > l)
-            buf[l++] = dz;
-        break;
-
-    case HID_TABLET:
-        if (len > l)
-            buf[l++] = b;
-        if (len > l)
-            buf[l++] = dx & 0xff;
-        if (len > l)
-            buf[l++] = dx >> 8;
-        if (len > l)
-            buf[l++] = dy & 0xff;
-        if (len > l)
-            buf[l++] = dy >> 8;
-        if (len > l)
-            buf[l++] = dz;
-        break;
-
-    default:
-        abort();
-    }
-
-    return l;
-}
-
-static int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len)
-{
-    if (len < 2)
-        return 0;
-
-    hid_keyboard_process_keycode(hs);
-
-    buf[0] = hs->kbd.modifiers & 0xff;
-    buf[1] = 0;
-    if (hs->kbd.keys > 6) {
-        memset(buf + 2, USB_HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2);
-    } else {
-        memcpy(buf + 2, hs->kbd.key, MIN(8, len) - 2);
-    }
-
-    return MIN(8, len);
-}
-
-static int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len)
-{
-    if (len > 0) {
-        int ledstate = 0;
-        /* 0x01: Num Lock LED
-         * 0x02: Caps Lock LED
-         * 0x04: Scroll Lock LED
-         * 0x08: Compose LED
-         * 0x10: Kana LED */
-        hs->kbd.leds = buf[0];
-        if (hs->kbd.leds & 0x04) {
-            ledstate |= QEMU_SCROLL_LOCK_LED;
-        }
-        if (hs->kbd.leds & 0x01) {
-            ledstate |= QEMU_NUM_LOCK_LED;
-        }
-        if (hs->kbd.leds & 0x02) {
-            ledstate |= QEMU_CAPS_LOCK_LED;
-        }
-        kbd_put_ledstate(ledstate);
-    }
-    return 0;
-}
-
-static void hid_handle_reset(HIDState *hs)
-{
-    switch (hs->kind) {
-    case HID_KEYBOARD:
-        qemu_add_kbd_event_handler(hid_keyboard_event, hs);
-        memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes));
-        memset(hs->kbd.key, 0, sizeof(hs->kbd.key));
-        hs->kbd.keys = 0;
-        break;
-    case HID_MOUSE:
-    case HID_TABLET:
-        memset(hs->ptr.queue, 0, sizeof(hs->ptr.queue));
-        break;
-    }
-    hs->head = 0;
-    hs->n = 0;
-}
-
 static void usb_hid_handle_reset(USBDevice *dev)
 {
     USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
 
-    hid_handle_reset(&us->hid);
+    hid_reset(&us->hid);
     us->protocol = 1;
     us->idle = 0;
 }
@@ -875,19 +509,6 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
     return ret;
 }
 
-static void hid_free(HIDState *hs)
-{
-    switch (hs->kind) {
-    case HID_KEYBOARD:
-        qemu_remove_kbd_event_handler();
-        break;
-    case HID_MOUSE:
-    case HID_TABLET:
-        qemu_remove_mouse_event_handler(hs->ptr.eh_entry);
-        break;
-    }
-}
-
 static void usb_hid_handle_destroy(USBDevice *dev)
 {
     USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
@@ -895,20 +516,6 @@ static void usb_hid_handle_destroy(USBDevice *dev)
     hid_free(&us->hid);
 }
 
-static void hid_init(HIDState *hs, int kind, HIDEventFunc event)
-{
-    hs->kind = kind;
-    hs->event = event;
-
-    if (hs->kind == HID_MOUSE) {
-        hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
-                                                        0, "QEMU HID Mouse");
-    } else if (hs->kind == HID_TABLET) {
-        hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
-                                                        1, "QEMU HID Tablet");
-    }
-}
-
 static int usb_hid_initfn(USBDevice *dev, int kind)
 {
     USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
commit 38931fa8cfb074a08ce65fd1982bd4a5bef9d6fb
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Jul 15 14:46:39 2011 +0200

    usb-hid: add hid_has_events()
    
    Add hid_has_events function, use it to figure whenever there are pending
    events instead of checking and updating USBHIDState->changed.
    
    Setting ->changed to 1 on init is removed, that should have absolutely
    no effect as the initial state of ->idle is 0 so we report hid state
    anyway until the guest configures some idle time.  Also should clear
    ->idle on reset.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index 870cc66..b730692 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -88,7 +88,6 @@ typedef struct USBHIDState {
     int32_t protocol;
     uint8_t idle;
     int64_t next_idle_clock;
-    int changed;
     void *datain_opaque;
     void (*datain)(void *);
 } USBHIDState;
@@ -444,12 +443,15 @@ static const uint8_t usb_hid_usage_keys[0x100] = {
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 };
 
+static bool hid_has_events(HIDState *hs)
+{
+    return hs->n > 0;
+}
+
 static void usb_hid_changed(HIDState *hs)
 {
     USBHIDState *us = container_of(hs, USBHIDState, hid);
 
-    us->changed = 1;
-
     if (us->datain) {
         us->datain(us->datain_opaque);
     }
@@ -742,6 +744,7 @@ static void usb_hid_handle_reset(USBDevice *dev)
 
     hid_handle_reset(&us->hid);
     us->protocol = 1;
+    us->idle = 0;
 }
 
 static void usb_hid_set_next_idle(USBHIDState *s, int64_t curtime)
@@ -798,7 +801,6 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
         } else if (hs->kind == HID_KEYBOARD) {
             ret = hid_keyboard_poll(hs, data, length);
         }
-        us->changed = hs->n > 0;
         break;
     case SET_REPORT:
         if (hs->kind == HID_KEYBOARD) {
@@ -849,7 +851,7 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
     case USB_TOKEN_IN:
         if (p->devep == 1) {
             int64_t curtime = qemu_get_clock_ns(vm_clock);
-            if (!us->changed &&
+            if (!hid_has_events(hs) &&
                 (!us->idle || us->next_idle_clock - curtime > 0)) {
                 return USB_RET_NAK;
             }
@@ -860,7 +862,6 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
                 ret = hid_keyboard_poll(hs, buf, p->iov.size);
             }
             usb_packet_copy(p, buf, ret);
-            us->changed = hs->n > 0;
         } else {
             goto fail;
         }
@@ -914,9 +915,6 @@ static int usb_hid_initfn(USBDevice *dev, int kind)
 
     usb_desc_init(dev);
     hid_init(&us->hid, kind, usb_hid_changed);
-
-    /* Force poll routine to be run and grab input the first time.  */
-    us->changed = 1;
     return 0;
 }
 
commit 8bde6805412a2808009a84f1ce5f47b88b0352d0
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Jul 15 14:37:15 2011 +0200

    usb-hid: add event callback
    
    Add callback for event notification, which allows to un-usbify more
    functions.  Also split separate hid_* functions for reset and release.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index f5d6c61..870cc66 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -54,6 +54,9 @@ typedef struct HIDPointerEvent {
 #define QUEUE_MASK      (QUEUE_LENGTH-1u)
 #define QUEUE_INCR(v)   ((v)++, (v) &= QUEUE_MASK)
 
+typedef struct HIDState HIDState;
+typedef void (*HIDEventFunc)(HIDState *s);
+
 typedef struct HIDMouseState {
     HIDPointerEvent queue[QUEUE_LENGTH];
     int mouse_grabbed;
@@ -68,7 +71,7 @@ typedef struct HIDKeyboardState {
     int32_t keys;
 } HIDKeyboardState;
 
-typedef struct HIDState {
+struct HIDState {
     union {
         HIDMouseState ptr;
         HIDKeyboardState kbd;
@@ -76,7 +79,8 @@ typedef struct HIDState {
     uint32_t head; /* index into circular queue */
     uint32_t n;
     int kind;
-} HIDState;
+    HIDEventFunc event;
+};
 
 typedef struct USBHIDState {
     USBDevice dev;
@@ -440,14 +444,17 @@ static const uint8_t usb_hid_usage_keys[0x100] = {
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 };
 
-static void usb_hid_changed(USBHIDState *hs)
+static void usb_hid_changed(HIDState *hs)
 {
-    hs->changed = 1;
+    USBHIDState *us = container_of(hs, USBHIDState, hid);
 
-    if (hs->datain)
-        hs->datain(hs->datain_opaque);
+    us->changed = 1;
+
+    if (us->datain) {
+        us->datain(us->datain_opaque);
+    }
 
-    usb_wakeup(&hs->dev);
+    usb_wakeup(&us->dev);
 }
 
 static void hid_pointer_event_clear(HIDPointerEvent *e, int buttons)
@@ -473,11 +480,10 @@ static void hid_pointer_event_combine(HIDPointerEvent *e, int xyrel,
     e->dz += z1;
 }
 
-static void usb_pointer_event(void *opaque,
+static void hid_pointer_event(void *opaque,
                               int x1, int y1, int z1, int buttons_state)
 {
-    USBHIDState *us = opaque;
-    HIDState *hs = &us->hid;
+    HIDState *hs = opaque;
     unsigned use_slot = (hs->head + hs->n - 1) & QUEUE_MASK;
     unsigned previous_slot = (use_slot - 1) & QUEUE_MASK;
 
@@ -501,13 +507,12 @@ static void usb_pointer_event(void *opaque,
     hid_pointer_event_combine(&hs->ptr.queue[use_slot],
                               hs->kind == HID_MOUSE,
                               x1, y1, z1);
-    usb_hid_changed(us);
+    hs->event(hs);
 }
 
-static void usb_keyboard_event(void *opaque, int keycode)
+static void hid_keyboard_event(void *opaque, int keycode)
 {
-    USBHIDState *us = opaque;
-    HIDState *hs = &us->hid;
+    HIDState *hs = opaque;
     int slot;
 
     if (hs->n == QUEUE_LENGTH) {
@@ -516,7 +521,7 @@ static void usb_keyboard_event(void *opaque, int keycode)
     }
     slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
     hs->kbd.keycodes[slot] = keycode;
-    usb_hid_changed(us);
+    hs->event(hs);
 }
 
 static void hid_keyboard_process_keycode(HIDState *hs)
@@ -713,26 +718,29 @@ static int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len)
     return 0;
 }
 
-static void usb_mouse_handle_reset(USBDevice *dev)
+static void hid_handle_reset(HIDState *hs)
 {
-    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
-
-    memset(us->hid.ptr.queue, 0, sizeof(us->hid.ptr.queue));
-    us->hid.head = 0;
-    us->hid.n = 0;
-    us->protocol = 1;
+    switch (hs->kind) {
+    case HID_KEYBOARD:
+        qemu_add_kbd_event_handler(hid_keyboard_event, hs);
+        memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes));
+        memset(hs->kbd.key, 0, sizeof(hs->kbd.key));
+        hs->kbd.keys = 0;
+        break;
+    case HID_MOUSE:
+    case HID_TABLET:
+        memset(hs->ptr.queue, 0, sizeof(hs->ptr.queue));
+        break;
+    }
+    hs->head = 0;
+    hs->n = 0;
 }
 
-static void usb_keyboard_handle_reset(USBDevice *dev)
+static void usb_hid_handle_reset(USBDevice *dev)
 {
     USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
 
-    qemu_add_kbd_event_handler(usb_keyboard_event, us);
-    memset(us->hid.kbd.keycodes, 0, sizeof(us->hid.kbd.keycodes));
-    us->hid.head = 0;
-    us->hid.n = 0;
-    memset(us->hid.kbd.key, 0, sizeof(us->hid.kbd.key));
-    us->hid.kbd.keys = 0;
+    hid_handle_reset(&us->hid);
     us->protocol = 1;
 }
 
@@ -866,34 +874,46 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
     return ret;
 }
 
-static void usb_hid_handle_destroy(USBDevice *dev)
+static void hid_free(HIDState *hs)
 {
-    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
-
-    switch (us->hid.kind) {
+    switch (hs->kind) {
     case HID_KEYBOARD:
         qemu_remove_kbd_event_handler();
         break;
-    default:
-        qemu_remove_mouse_event_handler(us->hid.ptr.eh_entry);
+    case HID_MOUSE:
+    case HID_TABLET:
+        qemu_remove_mouse_event_handler(hs->ptr.eh_entry);
+        break;
     }
 }
 
-static int usb_hid_initfn(USBDevice *dev, int kind)
+static void usb_hid_handle_destroy(USBDevice *dev)
 {
     USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
-    HIDState *hs = &us->hid;
 
-    usb_desc_init(dev);
+    hid_free(&us->hid);
+}
+
+static void hid_init(HIDState *hs, int kind, HIDEventFunc event)
+{
     hs->kind = kind;
+    hs->event = event;
 
     if (hs->kind == HID_MOUSE) {
-        hs->ptr.eh_entry = qemu_add_mouse_event_handler(usb_pointer_event, us,
+        hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
                                                         0, "QEMU HID Mouse");
     } else if (hs->kind == HID_TABLET) {
-        hs->ptr.eh_entry = qemu_add_mouse_event_handler(usb_pointer_event, us,
+        hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
                                                         1, "QEMU HID Tablet");
     }
+}
+
+static int usb_hid_initfn(USBDevice *dev, int kind)
+{
+    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
+
+    usb_desc_init(dev);
+    hid_init(&us->hid, kind, usb_hid_changed);
 
     /* Force poll routine to be run and grab input the first time.  */
     us->changed = 1;
@@ -992,7 +1012,7 @@ static struct USBDeviceInfo hid_info[] = {
         .usb_desc       = &desc_tablet,
         .init           = usb_tablet_initfn,
         .handle_packet  = usb_generic_handle_packet,
-        .handle_reset   = usb_mouse_handle_reset,
+        .handle_reset   = usb_hid_handle_reset,
         .handle_control = usb_hid_handle_control,
         .handle_data    = usb_hid_handle_data,
         .handle_destroy = usb_hid_handle_destroy,
@@ -1005,7 +1025,7 @@ static struct USBDeviceInfo hid_info[] = {
         .usb_desc       = &desc_mouse,
         .init           = usb_mouse_initfn,
         .handle_packet  = usb_generic_handle_packet,
-        .handle_reset   = usb_mouse_handle_reset,
+        .handle_reset   = usb_hid_handle_reset,
         .handle_control = usb_hid_handle_control,
         .handle_data    = usb_hid_handle_data,
         .handle_destroy = usb_hid_handle_destroy,
@@ -1018,7 +1038,7 @@ static struct USBDeviceInfo hid_info[] = {
         .usb_desc       = &desc_keyboard,
         .init           = usb_keyboard_initfn,
         .handle_packet  = usb_generic_handle_packet,
-        .handle_reset   = usb_keyboard_handle_reset,
+        .handle_reset   = usb_hid_handle_reset,
         .handle_control = usb_hid_handle_control,
         .handle_data    = usb_hid_handle_data,
         .handle_destroy = usb_hid_handle_destroy,
commit 0d878eec1eddcf01f07c38c6040ea91184139299
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Jul 15 13:12:44 2011 +0200

    usb-hid: create & use HIDState
    
    First step in separating out the HID emulation code from usb-hid, so it
    can be reused without creating a dummy usb device like bluetooth does.
    
    This creates a HIDState struct, moves the non-usbish fields from
    USBHIDStruct there.  Renames non-usbish structs, defines and functions
    from usb* to hid*.  Adapts the code to that.
    
    Also cleans up a bunch of code style issues along the way.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index 541644a..f5d6c61 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -41,42 +41,46 @@
 #define USB_DT_REPORT 0x22
 #define USB_DT_PHY    0x23
 
-#define USB_MOUSE     1
-#define USB_TABLET    2
-#define USB_KEYBOARD  3
+#define HID_MOUSE     1
+#define HID_TABLET    2
+#define HID_KEYBOARD  3
 
-typedef struct USBPointerEvent {
+typedef struct HIDPointerEvent {
     int32_t xdx, ydy; /* relative iff it's a mouse, otherwise absolute */
     int32_t dz, buttons_state;
-} USBPointerEvent;
+} HIDPointerEvent;
 
 #define QUEUE_LENGTH    16 /* should be enough for a triple-click */
 #define QUEUE_MASK      (QUEUE_LENGTH-1u)
 #define QUEUE_INCR(v)   ((v)++, (v) &= QUEUE_MASK)
 
-typedef struct USBMouseState {
-    USBPointerEvent queue[QUEUE_LENGTH];
+typedef struct HIDMouseState {
+    HIDPointerEvent queue[QUEUE_LENGTH];
     int mouse_grabbed;
     QEMUPutMouseEntry *eh_entry;
-} USBMouseState;
+} HIDMouseState;
 
-typedef struct USBKeyboardState {
+typedef struct HIDKeyboardState {
     uint32_t keycodes[QUEUE_LENGTH];
     uint16_t modifiers;
     uint8_t leds;
     uint8_t key[16];
     int32_t keys;
-} USBKeyboardState;
+} HIDKeyboardState;
 
-typedef struct USBHIDState {
-    USBDevice dev;
+typedef struct HIDState {
     union {
-        USBMouseState ptr;
-        USBKeyboardState kbd;
+        HIDMouseState ptr;
+        HIDKeyboardState kbd;
     };
     uint32_t head; /* index into circular queue */
     uint32_t n;
     int kind;
+} HIDState;
+
+typedef struct USBHIDState {
+    USBDevice dev;
+    HIDState hid;
     int32_t protocol;
     uint8_t idle;
     int64_t next_idle_clock;
@@ -446,12 +450,13 @@ static void usb_hid_changed(USBHIDState *hs)
     usb_wakeup(&hs->dev);
 }
 
-static void usb_pointer_event_clear(USBPointerEvent *e, int buttons) {
+static void hid_pointer_event_clear(HIDPointerEvent *e, int buttons)
+{
     e->xdx = e->ydy = e->dz = 0;
     e->buttons_state = buttons;
 }
 
-static void usb_pointer_event_combine(USBPointerEvent *e, int xyrel,
+static void hid_pointer_event_combine(HIDPointerEvent *e, int xyrel,
                                       int x1, int y1, int z1) {
     if (xyrel) {
         e->xdx += x1;
@@ -471,8 +476,8 @@ static void usb_pointer_event_combine(USBPointerEvent *e, int xyrel,
 static void usb_pointer_event(void *opaque,
                               int x1, int y1, int z1, int buttons_state)
 {
-    USBHIDState *hs = opaque;
-    USBMouseState *s = &hs->ptr;
+    USBHIDState *us = opaque;
+    HIDState *hs = &us->hid;
     unsigned use_slot = (hs->head + hs->n - 1) & QUEUE_MASK;
     unsigned previous_slot = (use_slot - 1) & QUEUE_MASK;
 
@@ -483,25 +488,26 @@ static void usb_pointer_event(void *opaque,
      * the first event changed the button state.  */
     if (hs->n == QUEUE_LENGTH) {
         /* Queue full.  Discard old button state, combine motion normally.  */
-        s->queue[use_slot].buttons_state = buttons_state;
+        hs->ptr.queue[use_slot].buttons_state = buttons_state;
     } else if (hs->n < 2 ||
-               s->queue[use_slot].buttons_state != buttons_state ||
-               s->queue[previous_slot].buttons_state != s->queue[use_slot].buttons_state) {
+               hs->ptr.queue[use_slot].buttons_state != buttons_state ||
+               hs->ptr.queue[previous_slot].buttons_state !=
+               hs->ptr.queue[use_slot].buttons_state) {
         /* Cannot or should not combine, so add an empty item to the queue.  */
         QUEUE_INCR(use_slot);
         hs->n++;
-        usb_pointer_event_clear(&s->queue[use_slot], buttons_state);
+        hid_pointer_event_clear(&hs->ptr.queue[use_slot], buttons_state);
     }
-    usb_pointer_event_combine(&s->queue[use_slot],
-                              hs->kind == USB_MOUSE,
+    hid_pointer_event_combine(&hs->ptr.queue[use_slot],
+                              hs->kind == HID_MOUSE,
                               x1, y1, z1);
-    usb_hid_changed(hs);
+    usb_hid_changed(us);
 }
 
 static void usb_keyboard_event(void *opaque, int keycode)
 {
-    USBHIDState *hs = opaque;
-    USBKeyboardState *s = &hs->kbd;
+    USBHIDState *us = opaque;
+    HIDState *hs = &us->hid;
     int slot;
 
     if (hs->n == QUEUE_LENGTH) {
@@ -509,13 +515,12 @@ static void usb_keyboard_event(void *opaque, int keycode)
         return;
     }
     slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
-    s->keycodes[slot] = keycode;
-    usb_hid_changed(hs);
+    hs->kbd.keycodes[slot] = keycode;
+    usb_hid_changed(us);
 }
 
-static void usb_keyboard_process_keycode(USBHIDState *hs)
+static void hid_keyboard_process_keycode(HIDState *hs)
 {
-    USBKeyboardState *s = &hs->kbd;
     uint8_t hid_code, key;
     int i, keycode, slot;
 
@@ -523,49 +528,55 @@ static void usb_keyboard_process_keycode(USBHIDState *hs)
         return;
     }
     slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--;
-    keycode = s->keycodes[slot];
+    keycode = hs->kbd.keycodes[slot];
 
     key = keycode & 0x7f;
-    hid_code = usb_hid_usage_keys[key | ((s->modifiers >> 1) & (1 << 7))];
-    s->modifiers &= ~(1 << 8);
+    hid_code = usb_hid_usage_keys[key | ((hs->kbd.modifiers >> 1) & (1 << 7))];
+    hs->kbd.modifiers &= ~(1 << 8);
 
     switch (hid_code) {
     case 0x00:
         return;
 
     case 0xe0:
-        if (s->modifiers & (1 << 9)) {
-            s->modifiers ^= 3 << 8;
+        if (hs->kbd.modifiers & (1 << 9)) {
+            hs->kbd.modifiers ^= 3 << 8;
             return;
         }
     case 0xe1 ... 0xe7:
         if (keycode & (1 << 7)) {
-            s->modifiers &= ~(1 << (hid_code & 0x0f));
+            hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f));
             return;
         }
     case 0xe8 ... 0xef:
-        s->modifiers |= 1 << (hid_code & 0x0f);
+        hs->kbd.modifiers |= 1 << (hid_code & 0x0f);
         return;
     }
 
     if (keycode & (1 << 7)) {
-        for (i = s->keys - 1; i >= 0; i --)
-            if (s->key[i] == hid_code) {
-                s->key[i] = s->key[-- s->keys];
-                s->key[s->keys] = 0x00;
+        for (i = hs->kbd.keys - 1; i >= 0; i--) {
+            if (hs->kbd.key[i] == hid_code) {
+                hs->kbd.key[i] = hs->kbd.key[-- hs->kbd.keys];
+                hs->kbd.key[hs->kbd.keys] = 0x00;
                 break;
             }
-        if (i < 0)
+        }
+        if (i < 0) {
             return;
+        }
     } else {
-        for (i = s->keys - 1; i >= 0; i --)
-            if (s->key[i] == hid_code)
+        for (i = hs->kbd.keys - 1; i >= 0; i--) {
+            if (hs->kbd.key[i] == hid_code) {
                 break;
+            }
+        }
         if (i < 0) {
-            if (s->keys < sizeof(s->key))
-                s->key[s->keys ++] = hid_code;
-        } else
+            if (hs->kbd.keys < sizeof(hs->kbd.key)) {
+                hs->kbd.key[hs->kbd.keys++] = hid_code;
+            }
+        } else {
             return;
+        }
     }
 }
 
@@ -579,24 +590,23 @@ static inline int int_clamp(int val, int vmin, int vmax)
         return val;
 }
 
-static int usb_pointer_poll(USBHIDState *hs, uint8_t *buf, int len)
+static int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
 {
     int dx, dy, dz, b, l;
     int index;
-    USBMouseState *s = &hs->ptr;
-    USBPointerEvent *e;
+    HIDPointerEvent *e;
 
-    if (!s->mouse_grabbed) {
-        qemu_activate_mouse_event_handler(s->eh_entry);
-        s->mouse_grabbed = 1;
+    if (!hs->ptr.mouse_grabbed) {
+        qemu_activate_mouse_event_handler(hs->ptr.eh_entry);
+        hs->ptr.mouse_grabbed = 1;
     }
 
     /* When the buffer is empty, return the last event.  Relative
        movements will all be zero.  */
     index = (hs->n ? hs->head : hs->head - 1);
-    e = &s->queue[index & QUEUE_MASK];
+    e = &hs->ptr.queue[index & QUEUE_MASK];
 
-    if (hs->kind == USB_MOUSE) {
+    if (hs->kind == HID_MOUSE) {
         dx = int_clamp(e->xdx, -127, 127);
         dy = int_clamp(e->ydy, -127, 127);
         e->xdx -= dx;
@@ -618,7 +628,7 @@ static int usb_pointer_poll(USBHIDState *hs, uint8_t *buf, int len)
 
     if (hs->n &&
         !e->dz &&
-        (hs->kind == USB_TABLET || (!e->xdx && !e->ydy))) {
+        (hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) {
         /* that deals with this event */
         QUEUE_INCR(hs->head);
         hs->n--;
@@ -628,7 +638,7 @@ static int usb_pointer_poll(USBHIDState *hs, uint8_t *buf, int len)
     dz = 0 - dz;
     l = 0;
     switch (hs->kind) {
-    case USB_MOUSE:
+    case HID_MOUSE:
         if (len > l)
             buf[l++] = b;
         if (len > l)
@@ -639,7 +649,7 @@ static int usb_pointer_poll(USBHIDState *hs, uint8_t *buf, int len)
             buf[l++] = dz;
         break;
 
-    case USB_TABLET:
+    case HID_TABLET:
         if (len > l)
             buf[l++] = b;
         if (len > l)
@@ -661,25 +671,25 @@ static int usb_pointer_poll(USBHIDState *hs, uint8_t *buf, int len)
     return l;
 }
 
-static int usb_keyboard_poll(USBHIDState *hs, uint8_t *buf, int len)
+static int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len)
 {
-    USBKeyboardState *s = &hs->kbd;
     if (len < 2)
         return 0;
 
-    usb_keyboard_process_keycode(hs);
+    hid_keyboard_process_keycode(hs);
 
-    buf[0] = s->modifiers & 0xff;
+    buf[0] = hs->kbd.modifiers & 0xff;
     buf[1] = 0;
-    if (s->keys > 6)
+    if (hs->kbd.keys > 6) {
         memset(buf + 2, USB_HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2);
-    else
-        memcpy(buf + 2, s->key, MIN(8, len) - 2);
+    } else {
+        memcpy(buf + 2, hs->kbd.key, MIN(8, len) - 2);
+    }
 
     return MIN(8, len);
 }
 
-static int usb_keyboard_write(USBKeyboardState *s, uint8_t *buf, int len)
+static int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len)
 {
     if (len > 0) {
         int ledstate = 0;
@@ -688,13 +698,16 @@ static int usb_keyboard_write(USBKeyboardState *s, uint8_t *buf, int len)
          * 0x04: Scroll Lock LED
          * 0x08: Compose LED
          * 0x10: Kana LED */
-        s->leds = buf[0];
-        if (s->leds & 0x04)
+        hs->kbd.leds = buf[0];
+        if (hs->kbd.leds & 0x04) {
             ledstate |= QEMU_SCROLL_LOCK_LED;
-        if (s->leds & 0x01)
+        }
+        if (hs->kbd.leds & 0x01) {
             ledstate |= QEMU_NUM_LOCK_LED;
-        if (s->leds & 0x02)
+        }
+        if (hs->kbd.leds & 0x02) {
             ledstate |= QEMU_CAPS_LOCK_LED;
+        }
         kbd_put_ledstate(ledstate);
     }
     return 0;
@@ -702,25 +715,25 @@ static int usb_keyboard_write(USBKeyboardState *s, uint8_t *buf, int len)
 
 static void usb_mouse_handle_reset(USBDevice *dev)
 {
-    USBHIDState *s = (USBHIDState *)dev;
+    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
 
-    memset(s->ptr.queue, 0, sizeof (s->ptr.queue));
-    s->head = 0;
-    s->n = 0;
-    s->protocol = 1;
+    memset(us->hid.ptr.queue, 0, sizeof(us->hid.ptr.queue));
+    us->hid.head = 0;
+    us->hid.n = 0;
+    us->protocol = 1;
 }
 
 static void usb_keyboard_handle_reset(USBDevice *dev)
 {
-    USBHIDState *s = (USBHIDState *)dev;
-
-    qemu_add_kbd_event_handler(usb_keyboard_event, s);
-    memset(s->kbd.keycodes, 0, sizeof (s->kbd.keycodes));
-    s->head = 0;
-    s->n = 0;
-    memset(s->kbd.key, 0, sizeof (s->kbd.key));
-    s->kbd.keys = 0;
-    s->protocol = 1;
+    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
+
+    qemu_add_kbd_event_handler(usb_keyboard_event, us);
+    memset(us->hid.kbd.keycodes, 0, sizeof(us->hid.kbd.keycodes));
+    us->hid.head = 0;
+    us->hid.n = 0;
+    memset(us->hid.kbd.key, 0, sizeof(us->hid.kbd.key));
+    us->hid.kbd.keys = 0;
+    us->protocol = 1;
 }
 
 static void usb_hid_set_next_idle(USBHIDState *s, int64_t curtime)
@@ -731,7 +744,8 @@ static void usb_hid_set_next_idle(USBHIDState *s, int64_t curtime)
 static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
                int request, int value, int index, int length, uint8_t *data)
 {
-    USBHIDState *s = (USBHIDState *)dev;
+    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
+    HIDState *hs = &us->hid;
     int ret;
 
     ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
@@ -740,7 +754,7 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
     }
 
     ret = 0;
-    switch(request) {
+    switch (request) {
     case DeviceRequest | USB_REQ_GET_INTERFACE:
         data[0] = 0;
         ret = 1;
@@ -750,17 +764,17 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
         break;
         /* hid specific requests */
     case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
-        switch(value >> 8) {
+        switch (value >> 8) {
         case 0x22:
-	    if (s->kind == USB_MOUSE) {
+            if (hs->kind == HID_MOUSE) {
 		memcpy(data, qemu_mouse_hid_report_descriptor,
 		       sizeof(qemu_mouse_hid_report_descriptor));
 		ret = sizeof(qemu_mouse_hid_report_descriptor);
-	    } else if (s->kind == USB_TABLET) {
-		memcpy(data, qemu_tablet_hid_report_descriptor,
+            } else if (hs->kind == HID_TABLET) {
+                memcpy(data, qemu_tablet_hid_report_descriptor,
 		       sizeof(qemu_tablet_hid_report_descriptor));
 		ret = sizeof(qemu_tablet_hid_report_descriptor);
-            } else if (s->kind == USB_KEYBOARD) {
+            } else if (hs->kind == HID_KEYBOARD) {
                 memcpy(data, qemu_keyboard_hid_report_descriptor,
                        sizeof(qemu_keyboard_hid_report_descriptor));
                 ret = sizeof(qemu_keyboard_hid_report_descriptor);
@@ -771,38 +785,41 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
         }
         break;
     case GET_REPORT:
-        if (s->kind == USB_MOUSE || s->kind == USB_TABLET) {
-            ret = usb_pointer_poll(s, data, length);
-        } else if (s->kind == USB_KEYBOARD) {
-            ret = usb_keyboard_poll(s, data, length);
+        if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
+            ret = hid_pointer_poll(hs, data, length);
+        } else if (hs->kind == HID_KEYBOARD) {
+            ret = hid_keyboard_poll(hs, data, length);
         }
-        s->changed = s->n > 0;
+        us->changed = hs->n > 0;
         break;
     case SET_REPORT:
-        if (s->kind == USB_KEYBOARD)
-            ret = usb_keyboard_write(&s->kbd, data, length);
-        else
+        if (hs->kind == HID_KEYBOARD) {
+            ret = hid_keyboard_write(hs, data, length);
+        } else {
             goto fail;
+        }
         break;
     case GET_PROTOCOL:
-        if (s->kind != USB_KEYBOARD && s->kind != USB_MOUSE)
+        if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
             goto fail;
+        }
         ret = 1;
-        data[0] = s->protocol;
+        data[0] = us->protocol;
         break;
     case SET_PROTOCOL:
-        if (s->kind != USB_KEYBOARD && s->kind != USB_MOUSE)
+        if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
             goto fail;
+        }
         ret = 0;
-        s->protocol = value;
+        us->protocol = value;
         break;
     case GET_IDLE:
         ret = 1;
-        data[0] = s->idle;
+        data[0] = us->idle;
         break;
     case SET_IDLE:
-        s->idle = (uint8_t) (value >> 8);
-        usb_hid_set_next_idle(s, qemu_get_clock_ns(vm_clock));
+        us->idle = (uint8_t) (value >> 8);
+        usb_hid_set_next_idle(us, qemu_get_clock_ns(vm_clock));
         ret = 0;
         break;
     default:
@@ -815,25 +832,27 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
 
 static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
 {
-    USBHIDState *s = (USBHIDState *)dev;
+    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
+    HIDState *hs = &us->hid;
     uint8_t buf[p->iov.size];
     int ret = 0;
 
-    switch(p->pid) {
+    switch (p->pid) {
     case USB_TOKEN_IN:
         if (p->devep == 1) {
             int64_t curtime = qemu_get_clock_ns(vm_clock);
-            if (!s->changed && (!s->idle || s->next_idle_clock - curtime > 0))
+            if (!us->changed &&
+                (!us->idle || us->next_idle_clock - curtime > 0)) {
                 return USB_RET_NAK;
-            usb_hid_set_next_idle(s, curtime);
-            if (s->kind == USB_MOUSE || s->kind == USB_TABLET) {
-                ret = usb_pointer_poll(s, buf, p->iov.size);
             }
-            else if (s->kind == USB_KEYBOARD) {
-                ret = usb_keyboard_poll(s, buf, p->iov.size);
+            usb_hid_set_next_idle(us, curtime);
+            if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
+                ret = hid_pointer_poll(hs, buf, p->iov.size);
+            } else if (hs->kind == HID_KEYBOARD) {
+                ret = hid_keyboard_poll(hs, buf, p->iov.size);
             }
             usb_packet_copy(p, buf, ret);
-            s->changed = s->n > 0;
+            us->changed = hs->n > 0;
         } else {
             goto fail;
         }
@@ -849,50 +868,51 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
 
 static void usb_hid_handle_destroy(USBDevice *dev)
 {
-    USBHIDState *s = (USBHIDState *)dev;
+    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
 
-    switch(s->kind) {
-    case USB_KEYBOARD:
+    switch (us->hid.kind) {
+    case HID_KEYBOARD:
         qemu_remove_kbd_event_handler();
         break;
     default:
-        qemu_remove_mouse_event_handler(s->ptr.eh_entry);
+        qemu_remove_mouse_event_handler(us->hid.ptr.eh_entry);
     }
 }
 
 static int usb_hid_initfn(USBDevice *dev, int kind)
 {
-    USBHIDState *s = DO_UPCAST(USBHIDState, dev, dev);
+    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
+    HIDState *hs = &us->hid;
 
     usb_desc_init(dev);
-    s->kind = kind;
-
-    if (s->kind == USB_MOUSE) {
-        s->ptr.eh_entry = qemu_add_mouse_event_handler(usb_pointer_event, s,
-                                                       0, "QEMU USB Mouse");
-    } else if (s->kind == USB_TABLET) {
-        s->ptr.eh_entry = qemu_add_mouse_event_handler(usb_pointer_event, s,
-                                                       1, "QEMU USB Tablet");
+    hs->kind = kind;
+
+    if (hs->kind == HID_MOUSE) {
+        hs->ptr.eh_entry = qemu_add_mouse_event_handler(usb_pointer_event, us,
+                                                        0, "QEMU HID Mouse");
+    } else if (hs->kind == HID_TABLET) {
+        hs->ptr.eh_entry = qemu_add_mouse_event_handler(usb_pointer_event, us,
+                                                        1, "QEMU HID Tablet");
     }
 
     /* Force poll routine to be run and grab input the first time.  */
-    s->changed = 1;
+    us->changed = 1;
     return 0;
 }
 
 static int usb_tablet_initfn(USBDevice *dev)
 {
-    return usb_hid_initfn(dev, USB_TABLET);
+    return usb_hid_initfn(dev, HID_TABLET);
 }
 
 static int usb_mouse_initfn(USBDevice *dev)
 {
-    return usb_hid_initfn(dev, USB_MOUSE);
+    return usb_hid_initfn(dev, HID_MOUSE);
 }
 
 static int usb_keyboard_initfn(USBDevice *dev)
 {
-    return usb_hid_initfn(dev, USB_KEYBOARD);
+    return usb_hid_initfn(dev, HID_KEYBOARD);
 }
 
 void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *))
@@ -918,10 +938,10 @@ static const VMStateDescription vmstate_usb_ptr_queue = {
     .version_id = 1,
     .minimum_version_id = 1,
     .fields = (VMStateField []) {
-        VMSTATE_INT32(xdx, USBPointerEvent),
-        VMSTATE_INT32(ydy, USBPointerEvent),
-        VMSTATE_INT32(dz, USBPointerEvent),
-        VMSTATE_INT32(buttons_state, USBPointerEvent),
+        VMSTATE_INT32(xdx, HIDPointerEvent),
+        VMSTATE_INT32(ydy, HIDPointerEvent),
+        VMSTATE_INT32(dz, HIDPointerEvent),
+        VMSTATE_INT32(buttons_state, HIDPointerEvent),
         VMSTATE_END_OF_LIST()
     }
 };
@@ -932,10 +952,10 @@ static const VMStateDescription vmstate_usb_ptr = {
     .post_load = usb_hid_post_load,
     .fields = (VMStateField []) {
         VMSTATE_USB_DEVICE(dev, USBHIDState),
-        VMSTATE_STRUCT_ARRAY(ptr.queue, USBHIDState, QUEUE_LENGTH, 0,
-                             vmstate_usb_ptr_queue, USBPointerEvent),
-        VMSTATE_UINT32(head, USBHIDState),
-        VMSTATE_UINT32(n, USBHIDState),
+        VMSTATE_STRUCT_ARRAY(hid.ptr.queue, USBHIDState, QUEUE_LENGTH, 0,
+                             vmstate_usb_ptr_queue, HIDPointerEvent),
+        VMSTATE_UINT32(hid.head, USBHIDState),
+        VMSTATE_UINT32(hid.n, USBHIDState),
         VMSTATE_INT32(protocol, USBHIDState),
         VMSTATE_UINT8(idle, USBHIDState),
         VMSTATE_END_OF_LIST()
@@ -949,13 +969,13 @@ static const VMStateDescription vmstate_usb_kbd = {
     .post_load = usb_hid_post_load,
     .fields = (VMStateField []) {
         VMSTATE_USB_DEVICE(dev, USBHIDState),
-        VMSTATE_UINT32_ARRAY(kbd.keycodes, USBHIDState, QUEUE_LENGTH),
-        VMSTATE_UINT32(head, USBHIDState),
-        VMSTATE_UINT32(n, USBHIDState),
-        VMSTATE_UINT16(kbd.modifiers, USBHIDState),
-        VMSTATE_UINT8(kbd.leds, USBHIDState),
-        VMSTATE_UINT8_ARRAY(kbd.key, USBHIDState, 16),
-        VMSTATE_INT32(kbd.keys, USBHIDState),
+        VMSTATE_UINT32_ARRAY(hid.kbd.keycodes, USBHIDState, QUEUE_LENGTH),
+        VMSTATE_UINT32(hid.head, USBHIDState),
+        VMSTATE_UINT32(hid.n, USBHIDState),
+        VMSTATE_UINT16(hid.kbd.modifiers, USBHIDState),
+        VMSTATE_UINT8(hid.kbd.leds, USBHIDState),
+        VMSTATE_UINT8_ARRAY(hid.kbd.key, USBHIDState, 16),
+        VMSTATE_INT32(hid.kbd.keys, USBHIDState),
         VMSTATE_INT32(protocol, USBHIDState),
         VMSTATE_UINT8(idle, USBHIDState),
         VMSTATE_END_OF_LIST()
commit 0ce668bc5284ffebd2d0b269ae141f9a696dbd01
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Jul 13 17:36:46 2011 +0200

    ehci: iovec support, remove buffer
    
    Map guest memory and pass on a direct pointer instead of copying
    the bits to a indirect buffer.  EHCI transfer descriptors can
    reference multiple (physical guest) pages so we'll actually start
    seeing usb packets wich carry iovec with more than one element.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 799e31a..2b43895 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -28,6 +28,7 @@
 #include "pci.h"
 #include "monitor.h"
 #include "trace.h"
+#include "dma.h"
 
 #define EHCI_DEBUG   0
 
@@ -269,6 +270,7 @@ typedef struct EHCIqtd {
 
     uint32_t bufptr[5];               // Standard buffer pointer
 #define QTD_BUFPTR_MASK               0xfffff000
+#define QTD_BUFPTR_SH                 12
 } EHCIqtd;
 
 /*  EHCI spec version 1.0 Section 3.6
@@ -357,7 +359,7 @@ struct EHCIQueue {
     uint32_t qtdaddr;      // address QTD read from
 
     USBPacket packet;
-    uint8_t buffer[BUFF_SIZE];
+    QEMUSGList sgl;
     int pid;
     uint32_t tbytes;
     enum async_state async;
@@ -414,7 +416,7 @@ struct EHCIState {
     uint32_t p_fetch_addr;   // which address to look at next
 
     USBPacket ipacket;
-    uint8_t ibuffer[BUFF_SIZE];
+    QEMUSGList isgl;
     int isoch_pause;
 
     uint64_t last_run_ns;
@@ -1165,58 +1167,56 @@ static int ehci_qh_do_overlay(EHCIQueue *q)
     return 0;
 }
 
-static int ehci_buffer_rw(EHCIQueue *q, int bytes, int rw)
+static int ehci_init_transfer(EHCIQueue *q)
 {
-    int bufpos = 0;
-    int cpage, offset;
-    uint32_t head;
-    uint32_t tail;
-
-
-    if (!bytes) {
-        return 0;
-    }
-
-    cpage = get_field(q->qh.token, QTD_TOKEN_CPAGE);
-    if (cpage > 4) {
-        fprintf(stderr, "cpage out of range (%d)\n", cpage);
-        return USB_RET_PROCERR;
-    }
+    uint32_t cpage, offset, bytes, plen;
+    target_phys_addr_t page;
 
+    cpage  = get_field(q->qh.token, QTD_TOKEN_CPAGE);
+    bytes  = get_field(q->qh.token, QTD_TOKEN_TBYTES);
     offset = q->qh.bufptr[0] & ~QTD_BUFPTR_MASK;
+    qemu_sglist_init(&q->sgl, 5);
 
-    do {
-        /* start and end of this page */
-        head = q->qh.bufptr[cpage] & QTD_BUFPTR_MASK;
-        tail = head + ~QTD_BUFPTR_MASK + 1;
-        /* add offset into page */
-        head |= offset;
-
-        if (bytes <= (tail - head)) {
-            tail = head + bytes;
+    while (bytes > 0) {
+        if (cpage > 4) {
+            fprintf(stderr, "cpage out of range (%d)\n", cpage);
+            return USB_RET_PROCERR;
         }
 
-        trace_usb_ehci_data(rw, cpage, offset, head, tail-head, bufpos);
-        cpu_physical_memory_rw(head, q->buffer + bufpos, tail - head, rw);
-
-        bufpos += (tail - head);
-        offset += (tail - head);
-        bytes -= (tail - head);
-
-        if (bytes > 0) {
-            cpage++;
+        page  = q->qh.bufptr[cpage] & QTD_BUFPTR_MASK;
+        page += offset;
+        plen  = bytes;
+        if (plen > 4096 - offset) {
+            plen = 4096 - offset;
             offset = 0;
+            cpage++;
         }
-    } while (bytes > 0);
 
-    /* save cpage */
-    set_field(&q->qh.token, cpage, QTD_TOKEN_CPAGE);
+        qemu_sglist_add(&q->sgl, page, plen);
+        bytes -= plen;
+    }
+    return 0;
+}
 
-    /* save offset into cpage */
-    q->qh.bufptr[0] &= QTD_BUFPTR_MASK;
-    q->qh.bufptr[0] |= offset;
+static void ehci_finish_transfer(EHCIQueue *q, int status)
+{
+    uint32_t cpage, offset;
 
-    return 0;
+    qemu_sglist_destroy(&q->sgl);
+
+    if (status > 0) {
+        /* update cpage & offset */
+        cpage  = get_field(q->qh.token, QTD_TOKEN_CPAGE);
+        offset = q->qh.bufptr[0] & ~QTD_BUFPTR_MASK;
+
+        offset += status;
+        cpage  += offset >> QTD_BUFPTR_SH;
+        offset &= ~QTD_BUFPTR_MASK;
+
+        set_field(&q->qh.token, cpage, QTD_TOKEN_CPAGE);
+        q->qh.bufptr[0] &= QTD_BUFPTR_MASK;
+        q->qh.bufptr[0] |= offset;
+    }
 }
 
 static void ehci_async_complete_packet(USBPort *port, USBPacket *packet)
@@ -1295,10 +1295,6 @@ err:
         }
 
         if (q->tbytes && q->pid == USB_TOKEN_IN) {
-            if (ehci_buffer_rw(q, q->usb_status, 1) != 0) {
-                q->usb_status = USB_RET_PROCERR;
-                return;
-            }
             q->tbytes -= q->usb_status;
         } else {
             q->tbytes = 0;
@@ -1307,6 +1303,8 @@ err:
         DPRINTF("updating tbytes to %d\n", q->tbytes);
         set_field(&q->qh.token, q->tbytes, QTD_TOKEN_TBYTES);
     }
+    ehci_finish_transfer(q, q->usb_status);
+    usb_packet_unmap(&q->packet);
 
     q->qh.token ^= QTD_TOKEN_DTOGGLE;
     q->qh.token &= ~QTD_TOKEN_ACTIVE;
@@ -1346,8 +1344,7 @@ static int ehci_execute(EHCIQueue *q)
         default: fprintf(stderr, "bad token\n"); break;
     }
 
-    if ((q->tbytes && q->pid != USB_TOKEN_IN) &&
-        (ehci_buffer_rw(q, q->tbytes, 0) != 0)) {
+    if (ehci_init_transfer(q) != 0) {
         return USB_RET_PROCERR;
     }
 
@@ -1356,6 +1353,9 @@ static int ehci_execute(EHCIQueue *q)
 
     ret = USB_RET_NODEV;
 
+    usb_packet_setup(&q->packet, q->pid, devadr, endp);
+    usb_packet_map(&q->packet, &q->sgl);
+
     // TO-DO: associating device with ehci port
     for(i = 0; i < NB_PORTS; i++) {
         port = &q->ehci->ports[i];
@@ -1367,9 +1367,6 @@ static int ehci_execute(EHCIQueue *q)
             continue;
         }
 
-        usb_packet_setup(&q->packet, q->pid, devadr, endp);
-        usb_packet_addbuf(&q->packet, q->buffer, q->tbytes);
-
         ret = usb_handle_packet(dev, &q->packet);
 
         DPRINTF("submit: qh %x next %x qtd %x pid %x len %zd "
@@ -1399,7 +1396,7 @@ static int ehci_process_itd(EHCIState *ehci,
     USBPort *port;
     USBDevice *dev;
     int ret;
-    uint32_t i, j, len, len1, len2, pid, dir, devaddr, endp;
+    uint32_t i, j, len, pid, dir, devaddr, endp;
     uint32_t pg, off, ptr1, ptr2, max, mult;
 
     dir =(itd->bufptr[1] & ITD_BUFPTR_DIRECTION);
@@ -1424,29 +1421,23 @@ static int ehci_process_itd(EHCIState *ehci,
                 return USB_RET_PROCERR;
             }
 
+            qemu_sglist_init(&ehci->isgl, 2);
             if (off + len > 4096) {
                 /* transfer crosses page border */
-                len2 = off + len - 4096;
-                len1 = len - len2;
+                uint32_t len2 = off + len - 4096;
+                uint32_t len1 = len - len2;
+                qemu_sglist_add(&ehci->isgl, ptr1 + off, len1);
+                qemu_sglist_add(&ehci->isgl, ptr2, len2);
             } else {
-                len1 = len;
-                len2 = 0;
+                qemu_sglist_add(&ehci->isgl, ptr1 + off, len);
             }
 
-            if (!dir) {
-                pid = USB_TOKEN_OUT;
-                trace_usb_ehci_data(0, pg, off, ptr1 + off, len1, 0);
-                cpu_physical_memory_rw(ptr1 + off, &ehci->ibuffer[0], len1, 0);
-                if (len2) {
-                    trace_usb_ehci_data(0, pg+1, 0, ptr2, len2, len1);
-                    cpu_physical_memory_rw(ptr2, &ehci->ibuffer[len1], len2, 0);
-                }
-            } else {
-                pid = USB_TOKEN_IN;
-            }
+            pid = dir ? USB_TOKEN_IN : USB_TOKEN_OUT;
 
-            ret = USB_RET_NODEV;
+            usb_packet_setup(&ehci->ipacket, pid, devaddr, endp);
+            usb_packet_map(&ehci->ipacket, &ehci->isgl);
 
+            ret = USB_RET_NODEV;
             for (j = 0; j < NB_PORTS; j++) {
                 port = &ehci->ports[j];
                 dev = port->dev;
@@ -1455,9 +1446,6 @@ static int ehci_process_itd(EHCIState *ehci,
                     continue;
                 }
 
-                usb_packet_setup(&ehci->ipacket, pid, devaddr, endp);
-                usb_packet_addbuf(&ehci->ipacket, ehci->ibuffer, len);
-
                 ret = usb_handle_packet(dev, &ehci->ipacket);
 
                 if (ret != USB_RET_NODEV) {
@@ -1465,6 +1453,9 @@ static int ehci_process_itd(EHCIState *ehci,
                 }
             }
 
+            usb_packet_unmap(&ehci->ipacket);
+            qemu_sglist_destroy(&ehci->isgl);
+
 #if 0
             /*  In isoch, there is no facility to indicate a NAK so let's
              *  instead just complete a zero-byte transaction.  Setting
@@ -1502,20 +1493,6 @@ static int ehci_process_itd(EHCIState *ehci,
                     set_field(&itd->transact[i], len - ret, ITD_XACT_LENGTH);
                 } else {
                     /* IN */
-                    if (len1 > ret) {
-                        len1 = ret;
-                    }
-                    if (len2 > ret - len1) {
-                        len2 = ret - len1;
-                    }
-                    if (len1) {
-                        trace_usb_ehci_data(1, pg, off, ptr1 + off, len1, 0);
-                        cpu_physical_memory_rw(ptr1 + off, &ehci->ibuffer[0], len1, 1);
-                    }
-                    if (len2) {
-                        trace_usb_ehci_data(1, pg+1, 0, ptr2, len2, len1);
-                        cpu_physical_memory_rw(ptr2, &ehci->ibuffer[len1], len2, 1);
-                    }
                     set_field(&itd->transact[i], ret, ITD_XACT_LENGTH);
                 }
 
commit df5e66eefb8fb05891c49d0be88e3ed9656993c5
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Jul 13 15:37:29 2011 +0200

    uhci: remove buffer
    
    Map guest memory and pass on a direct pointer instead of copying
    the bits to a indirect buffer.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index 20b829b..824e3a5 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -31,6 +31,7 @@
 #include "qemu-timer.h"
 #include "usb-uhci.h"
 #include "iov.h"
+#include "dma.h"
 
 //#define DEBUG
 //#define DEBUG_DUMP_DATA
@@ -111,6 +112,7 @@ typedef struct UHCIState UHCIState;
  */
 typedef struct UHCIAsync {
     USBPacket packet;
+    QEMUSGList sgl;
     UHCIState *uhci;
     QTAILQ_ENTRY(UHCIAsync) next;
     uint32_t  td;
@@ -118,7 +120,6 @@ typedef struct UHCIAsync {
     int8_t    valid;
     uint8_t   isoc;
     uint8_t   done;
-    uint8_t   buffer[2048];
 } UHCIAsync;
 
 typedef struct UHCIPort {
@@ -176,6 +177,7 @@ static UHCIAsync *uhci_async_alloc(UHCIState *s)
     async->done  = 0;
     async->isoc  = 0;
     usb_packet_init(&async->packet);
+    qemu_sglist_init(&async->sgl, 1);
 
     return async;
 }
@@ -183,6 +185,7 @@ static UHCIAsync *uhci_async_alloc(UHCIState *s)
 static void uhci_async_free(UHCIState *s, UHCIAsync *async)
 {
     usb_packet_cleanup(&async->packet);
+    qemu_sglist_destroy(&async->sgl);
     qemu_free(async);
 }
 
@@ -706,11 +709,6 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_
             goto out;
         }
 
-        if (len > 0) {
-            /* write the data back */
-            cpu_physical_memory_write(td->buffer, async->buffer, len);
-        }
-
         if ((td->ctrl & TD_CTRL_SPD) && len < max_len) {
             *int_mask |= 0x02;
             /* short packet: do not update QH */
@@ -827,12 +825,12 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *in
 
     usb_packet_setup(&async->packet, pid, (td->token >> 8) & 0x7f,
                      (td->token >> 15) & 0xf);
-    usb_packet_addbuf(&async->packet, async->buffer, max_len);
+    qemu_sglist_add(&async->sgl, td->buffer, max_len);
+    usb_packet_map(&async->packet, &async->sgl);
 
     switch(pid) {
     case USB_TOKEN_OUT:
     case USB_TOKEN_SETUP:
-        cpu_physical_memory_read(td->buffer, async->buffer, max_len);
         len = uhci_broadcast_packet(s, &async->packet);
         if (len >= 0)
             len = max_len;
@@ -859,6 +857,7 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *in
 
 done:
     len = uhci_complete_td(s, td, async, int_mask);
+    usb_packet_unmap(&async->packet);
     uhci_async_free(s, async);
     return len;
 }
commit 29c74f762bc65d1f38da8624ee4182822db369bf
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Jul 13 12:32:06 2011 +0200

    usb-storage: iovec support
    
    Add full iovec support to usb-storage.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index 48e0b34..90e57fb 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -43,8 +43,6 @@ typedef struct {
     enum USBMSDMode mode;
     uint32_t scsi_len;
     uint8_t *scsi_buf;
-    uint32_t usb_len;
-    uint8_t *usb_buf;
     uint32_t data_len;
     uint32_t residue;
     uint32_t tag;
@@ -176,20 +174,14 @@ static const USBDesc desc = {
     .str  = desc_strings,
 };
 
-static void usb_msd_copy_data(MSDState *s)
+static void usb_msd_copy_data(MSDState *s, USBPacket *p)
 {
     uint32_t len;
-    len = s->usb_len;
+    len = p->iov.size - p->result;
     if (len > s->scsi_len)
         len = s->scsi_len;
-    if (s->mode == USB_MSDM_DATAIN) {
-        memcpy(s->usb_buf, s->scsi_buf, len);
-    } else {
-        memcpy(s->scsi_buf, s->usb_buf, len);
-    }
-    s->usb_len -= len;
+    usb_packet_copy(p, s->scsi_buf, len);
     s->scsi_len -= len;
-    s->usb_buf += len;
     s->scsi_buf += len;
     s->data_len -= len;
     if (s->scsi_len == 0 || s->data_len == 0) {
@@ -221,9 +213,9 @@ static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
     s->scsi_len = len;
     s->scsi_buf = scsi_req_get_buf(req);
     if (p) {
-        usb_msd_copy_data(s);
-        if (s->packet && s->usb_len == 0) {
-            p->result = p->iov.size;
+        usb_msd_copy_data(s, p);
+        p = s->packet;
+        if (p && p->result == p->iov.size) {
             /* Set s->packet to NULL before calling usb_packet_complete
                because another request may be issued before
                usb_packet_complete returns.  */
@@ -250,16 +242,13 @@ static void usb_msd_command_complete(SCSIRequest *req, uint32_t status)
             s->mode = USB_MSDM_CBW;
         } else {
             if (s->data_len) {
-                s->data_len -= s->usb_len;
-                if (s->mode == USB_MSDM_DATAIN) {
-                    memset(s->usb_buf, 0, s->usb_len);
-                }
-                s->usb_len = 0;
+                int len = (p->iov.size - p->result);
+                usb_packet_skip(p, len);
+                s->data_len -= len;
             }
             if (s->data_len == 0) {
                 s->mode = USB_MSDM_CSW;
             }
-            p->result = p->iov.size;
         }
         s->packet = NULL;
         usb_packet_complete(&s->dev, p);
@@ -345,10 +334,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
     int ret = 0;
     struct usb_msd_cbw cbw;
     uint8_t devep = p->devep;
-    uint8_t *data = p->iov.iov[0].iov_base;
-    int len = p->iov.iov[0].iov_len;
 
-    assert(p->iov.niov == 1); /* temporary */
     switch (p->pid) {
     case USB_TOKEN_OUT:
         if (devep != 2)
@@ -356,11 +342,11 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
 
         switch (s->mode) {
         case USB_MSDM_CBW:
-            if (len != 31) {
+            if (p->iov.size != 31) {
                 fprintf(stderr, "usb-msd: Bad CBW size");
                 goto fail;
             }
-            memcpy(&cbw, data, 31);
+            usb_packet_copy(p, &cbw, 31);
             if (le32_to_cpu(cbw.sig) != 0x43425355) {
                 fprintf(stderr, "usb-msd: Bad signature %08x\n",
                         le32_to_cpu(cbw.sig));
@@ -391,36 +377,39 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
             if (s->mode != USB_MSDM_CSW && s->residue == 0) {
                 scsi_req_continue(s->req);
             }
-            ret = len;
+            ret = p->result;
             break;
 
         case USB_MSDM_DATAOUT:
-            DPRINTF("Data out %d/%d\n", len, s->data_len);
-            if (len > s->data_len)
+            DPRINTF("Data out %zd/%d\n", p->iov.size, s->data_len);
+            if (p->iov.size > s->data_len) {
                 goto fail;
+            }
 
-            s->usb_buf = data;
-            s->usb_len = len;
             if (s->scsi_len) {
-                usb_msd_copy_data(s);
+                usb_msd_copy_data(s, p);
             }
-            if (s->residue && s->usb_len) {
-                s->data_len -= s->usb_len;
-                if (s->data_len == 0)
-                    s->mode = USB_MSDM_CSW;
-                s->usb_len = 0;
+            if (s->residue) {
+                int len = p->iov.size - p->result;
+                if (len) {
+                    usb_packet_skip(p, len);
+                    s->data_len -= len;
+                    if (s->data_len == 0) {
+                        s->mode = USB_MSDM_CSW;
+                    }
+                }
             }
-            if (s->usb_len) {
+            if (p->result < p->iov.size) {
                 DPRINTF("Deferring packet %p\n", p);
                 s->packet = p;
                 ret = USB_RET_ASYNC;
             } else {
-                ret = len;
+                ret = p->result;
             }
             break;
 
         default:
-            DPRINTF("Unexpected write (len %d)\n", len);
+            DPRINTF("Unexpected write (len %zd)\n", p->iov.size);
             goto fail;
         }
         break;
@@ -431,18 +420,20 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
 
         switch (s->mode) {
         case USB_MSDM_DATAOUT:
-            if (s->data_len != 0 || len < 13)
+            if (s->data_len != 0 || p->iov.size < 13) {
                 goto fail;
+            }
             /* Waiting for SCSI write to complete.  */
             s->packet = p;
             ret = USB_RET_ASYNC;
             break;
 
         case USB_MSDM_CSW:
-            DPRINTF("Command status %d tag 0x%x, len %d\n",
-                    s->result, s->tag, len);
-            if (len < 13)
+            DPRINTF("Command status %d tag 0x%x, len %zd\n",
+                    s->result, s->tag, p->iov.size);
+            if (p->iov.size < 13) {
                 goto fail;
+            }
 
             usb_msd_send_status(s, p);
             s->mode = USB_MSDM_CBW;
@@ -450,32 +441,32 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
             break;
 
         case USB_MSDM_DATAIN:
-            DPRINTF("Data in %d/%d, scsi_len %d\n", len, s->data_len, s->scsi_len);
-            if (len > s->data_len)
-                len = s->data_len;
-            s->usb_buf = data;
-            s->usb_len = len;
+            DPRINTF("Data in %zd/%d, scsi_len %d\n",
+                    p->iov.size, s->data_len, s->scsi_len);
             if (s->scsi_len) {
-                usb_msd_copy_data(s);
+                usb_msd_copy_data(s, p);
             }
-            if (s->residue && s->usb_len) {
-                s->data_len -= s->usb_len;
-                memset(s->usb_buf, 0, s->usb_len);
-                if (s->data_len == 0)
-                    s->mode = USB_MSDM_CSW;
-                s->usb_len = 0;
+            if (s->residue) {
+                int len = p->iov.size - p->result;
+                if (len) {
+                    usb_packet_skip(p, len);
+                    s->data_len -= len;
+                    if (s->data_len == 0) {
+                        s->mode = USB_MSDM_CSW;
+                    }
+                }
             }
-            if (s->usb_len) {
+            if (p->result < p->iov.size) {
                 DPRINTF("Deferring packet %p\n", p);
                 s->packet = p;
                 ret = USB_RET_ASYNC;
             } else {
-                ret = len;
+                ret = p->result;
             }
             break;
 
         default:
-            DPRINTF("Unexpected read (len %d)\n", len);
+            DPRINTF("Unexpected read (len %zd)\n", p->iov.size);
             goto fail;
         }
         break;
commit b621bab436b1260b1c6f3841f3bb7d76236289dc
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Jul 13 11:28:17 2011 +0200

    usb-host: iovec support
    
    Add full support for iovecs to usb-host.  The code can split large
    transfers into smaller ones already, we are using this to also split
    requests at iovec borders.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/usb-linux.c b/usb-linux.c
index 184f56f..5562187 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -707,7 +707,7 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
     USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
     struct usbdevfs_urb *urb;
     AsyncURB *aurb;
-    int ret, rem;
+    int ret, rem, prem, v;
     uint8_t *pbuf;
     uint8_t ep;
 
@@ -735,10 +735,18 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
         return usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN);
     }
 
-    assert(p->iov.niov == 1); /* temporary */
-    rem = p->iov.iov[0].iov_len;
-    pbuf = p->iov.iov[0].iov_base;
+    v = 0;
+    prem = p->iov.iov[v].iov_len;
+    pbuf = p->iov.iov[v].iov_base;
+    rem = p->iov.size;
     while (rem) {
+        if (prem == 0) {
+            v++;
+            assert(v < p->iov.niov);
+            prem = p->iov.iov[v].iov_len;
+            pbuf = p->iov.iov[v].iov_base;
+            assert(prem <= rem);
+        }
         aurb = async_alloc(s);
         aurb->packet = p;
 
@@ -747,16 +755,17 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
         urb->type          = USBDEVFS_URB_TYPE_BULK;
         urb->usercontext   = s;
         urb->buffer        = pbuf;
+        urb->buffer_length = prem;
 
-        if (rem > MAX_USBFS_BUFFER_SIZE) {
+        if (urb->buffer_length > MAX_USBFS_BUFFER_SIZE) {
             urb->buffer_length = MAX_USBFS_BUFFER_SIZE;
-            aurb->more         = 1;
-        } else {
-            urb->buffer_length = rem;
-            aurb->more         = 0;
         }
         pbuf += urb->buffer_length;
+        prem -= urb->buffer_length;
         rem  -= urb->buffer_length;
+        if (rem) {
+            aurb->more         = 1;
+        }
 
         ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
 
commit 9440b7e5553f1fbceb9afe81a08f4e56975dea6d
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Jul 13 10:53:23 2011 +0200

    usb-serial: iovec support
    
    Add full support for iovecs to usb-serial.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-serial.c b/hw/usb-serial.c
index 09731da..bf2b775 100644
--- a/hw/usb-serial.c
+++ b/hw/usb-serial.c
@@ -359,38 +359,42 @@ static int usb_serial_handle_control(USBDevice *dev, USBPacket *p,
 static int usb_serial_handle_data(USBDevice *dev, USBPacket *p)
 {
     USBSerialState *s = (USBSerialState *)dev;
-    int ret = 0;
+    int i, ret = 0;
     uint8_t devep = p->devep;
-    uint8_t *data = p->iov.iov[0].iov_base;
-    int len = p->iov.iov[0].iov_len;
-    int first_len;
+    struct iovec *iov;
+    uint8_t header[2];
+    int first_len, len;
 
-    assert(p->iov.niov == 1); /* temporary */
     switch (p->pid) {
     case USB_TOKEN_OUT:
         if (devep != 2)
             goto fail;
-        qemu_chr_write(s->cs, data, len);
+        for (i = 0; i < p->iov.niov; i++) {
+            iov = p->iov.iov + i;
+            qemu_chr_write(s->cs, iov->iov_base, iov->iov_len);
+        }
         break;
 
     case USB_TOKEN_IN:
         if (devep != 1)
             goto fail;
         first_len = RECV_BUF - s->recv_ptr;
+        len = p->iov.size;
         if (len <= 2) {
             ret = USB_RET_NAK;
             break;
         }
-        *data++ = usb_get_modem_lines(s) | 1;
+        header[0] = usb_get_modem_lines(s) | 1;
         /* We do not have the uart details */
         /* handle serial break */
         if (s->event_trigger && s->event_trigger & FTDI_BI) {
             s->event_trigger &= ~FTDI_BI;
-            *data = FTDI_BI;
+            header[1] = FTDI_BI;
+            usb_packet_copy(p, header, 2);
             ret = 2;
             break;
         } else {
-            *data++ = 0;
+            header[1] = 0;
         }
         len -= 2;
         if (len > s->recv_used)
@@ -401,9 +405,10 @@ static int usb_serial_handle_data(USBDevice *dev, USBPacket *p)
         }
         if (first_len > len)
             first_len = len;
-        memcpy(data, s->recv_buf + s->recv_ptr, first_len);
+        usb_packet_copy(p, header, 2);
+        usb_packet_copy(p, s->recv_buf + s->recv_ptr, first_len);
         if (len > first_len)
-            memcpy(data + first_len, s->recv_buf, len - first_len);
+            usb_packet_copy(p, s->recv_buf, len - first_len);
         s->recv_used -= len;
         s->recv_ptr = (s->recv_ptr + len) % RECV_BUF;
         ret = len + 2;
commit 4f4321c11ff6e98583846bfd6f0e81954924b003
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Jul 12 15:22:25 2011 +0200

    usb: use iovecs in USBPacket
    
    Zap data pointer from USBPacket, add a QEMUIOVector instead.
    Add a bunch of helper functions to manage USBPacket data.
    Switch over users to the new interface.
    
    Note that USBPacket->len was used for two purposes:  First to
    pass in the buffer size and second to return the number of
    transfered bytes or the status code on async transfers.  There
    is a new result variable for the latter.  A new status code
    was added to catch uninitialized result.
    
    Nobody creates iovecs with more than one element (yet).
    Some users are (temporarely) limited to iovecs with a single
    element to keep the patch size as small as possible.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/Makefile.objs b/Makefile.objs
index 6991a9f..3d1a4de 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -172,6 +172,7 @@ user-obj-y += cutils.o cache-utils.o
 hw-obj-y =
 hw-obj-y += vl.o loader.o
 hw-obj-$(CONFIG_VIRTIO) += virtio-console.o
+hw-obj-y += usb-libhw.o
 hw-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
 hw-obj-y += fw_cfg.o
 hw-obj-$(CONFIG_PCI) += pci.o pci_bridge.o
diff --git a/hw/bt-hid.c b/hw/bt-hid.c
index 09120af..a4204f9 100644
--- a/hw/bt-hid.c
+++ b/hw/bt-hid.c
@@ -127,11 +127,11 @@ static int bt_hid_out(struct bt_hid_device_s *s)
     USBPacket p;
 
     if (s->data_type == BT_DATA_OUTPUT) {
-        p.pid = USB_TOKEN_OUT;
-        p.devep = 1;
-        p.data = s->dataout.buffer;
-        p.len = s->dataout.len;
+        usb_packet_init(&p);
+        usb_packet_setup(&p, USB_TOKEN_OUT, 0, 1);
+        usb_packet_addbuf(&p, s->dataout.buffer, s->dataout.len);
         s->dataout.len = s->usbdev->info->handle_data(s->usbdev, &p);
+        usb_packet_cleanup(&p);
 
         return s->dataout.len;
     }
@@ -150,11 +150,11 @@ static int bt_hid_in(struct bt_hid_device_s *s)
 {
     USBPacket p;
 
-    p.pid = USB_TOKEN_IN;
-    p.devep = 1;
-    p.data = s->datain.buffer;
-    p.len = sizeof(s->datain.buffer);
+    usb_packet_init(&p);
+    usb_packet_setup(&p, USB_TOKEN_IN, 0, 1);
+    usb_packet_addbuf(&p, s->dataout.buffer, sizeof(s->datain.buffer));
     s->datain.len = s->usbdev->info->handle_data(s->usbdev, &p);
+    usb_packet_cleanup(&p);
 
     return s->datain.len;
 }
diff --git a/hw/milkymist-softusb.c b/hw/milkymist-softusb.c
index abf7b59..75c85ae 100644
--- a/hw/milkymist-softusb.c
+++ b/hw/milkymist-softusb.c
@@ -234,11 +234,11 @@ static void softusb_usbdev_datain(void *opaque)
 
     USBPacket p;
 
-    p.pid = USB_TOKEN_IN;
-    p.devep = 1;
-    p.data = s->kbd_usb_buffer;
-    p.len = sizeof(s->kbd_usb_buffer);
+    usb_packet_init(&p);
+    usb_packet_setup(&p, USB_TOKEN_IN, 0, 1);
+    usb_packet_addbuf(&p, s->kbd_usb_buffer, sizeof(s->kbd_usb_buffer));
     s->usbdev->info->handle_data(s->usbdev, &p);
+    usb_packet_cleanup(&p);
 
     softusb_kbd_changed(s);
 }
diff --git a/hw/usb-bt.c b/hw/usb-bt.c
index 4557802..529fa33 100644
--- a/hw/usb-bt.c
+++ b/hw/usb-bt.c
@@ -294,9 +294,9 @@ static inline int usb_bt_fifo_dequeue(struct usb_hci_in_fifo_s *fifo,
     if (likely(!fifo->len))
         return USB_RET_STALL;
 
-    len = MIN(p->len, fifo->fifo[fifo->start].len);
-    memcpy(p->data, fifo->fifo[fifo->start].data, len);
-    if (len == p->len) {
+    len = MIN(p->iov.size, fifo->fifo[fifo->start].len);
+    usb_packet_copy(p, fifo->fifo[fifo->start].data, len);
+    if (len == p->iov.size) {
         fifo->fifo[fifo->start].len -= len;
         fifo->fifo[fifo->start].data += len;
     } else {
@@ -319,20 +319,13 @@ static inline void usb_bt_fifo_out_enqueue(struct USBBtState *s,
                 struct usb_hci_out_fifo_s *fifo,
                 void (*send)(struct HCIInfo *, const uint8_t *, int),
                 int (*complete)(const uint8_t *, int),
-                const uint8_t *data, int len)
+                USBPacket *p)
 {
-    if (fifo->len) {
-        memcpy(fifo->data + fifo->len, data, len);
-        fifo->len += len;
-        if (complete(fifo->data, fifo->len)) {
-            send(s->hci, fifo->data, fifo->len);
-            fifo->len = 0;
-        }
-    } else if (complete(data, len))
-        send(s->hci, data, len);
-    else {
-        memcpy(fifo->data, data, len);
-        fifo->len = len;
+    usb_packet_copy(p, fifo->data + fifo->len, p->iov.size);
+    fifo->len += p->iov.size;
+    if (complete(fifo->data, fifo->len)) {
+        send(s->hci, fifo->data, fifo->len);
+        fifo->len = 0;
     }
 
     /* TODO: do we need to loop? */
@@ -432,7 +425,7 @@ static int usb_bt_handle_control(USBDevice *dev, USBPacket *p,
     case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_DEVICE) << 8):
         if (s->config)
             usb_bt_fifo_out_enqueue(s, &s->outcmd, s->hci->cmd_send,
-                            usb_bt_hci_cmd_complete, data, length);
+                            usb_bt_hci_cmd_complete, p);
         break;
     default:
     fail:
@@ -474,12 +467,12 @@ static int usb_bt_handle_data(USBDevice *dev, USBPacket *p)
         switch (p->devep & 0xf) {
         case USB_ACL_EP:
             usb_bt_fifo_out_enqueue(s, &s->outacl, s->hci->acl_send,
-                            usb_bt_hci_acl_complete, p->data, p->len);
+                            usb_bt_hci_acl_complete, p);
             break;
 
         case USB_SCO_EP:
             usb_bt_fifo_out_enqueue(s, &s->outsco, s->hci->sco_send,
-                            usb_bt_hci_sco_complete, p->data, p->len);
+                            usb_bt_hci_sco_complete, p);
             break;
 
         default:
diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c
index 4dda2c4..66aeb21 100644
--- a/hw/usb-ccid.c
+++ b/hw/usb-ccid.c
@@ -934,16 +934,16 @@ static int ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p)
 {
     CCID_Header *ccid_header;
 
-    if (p->len + s->bulk_out_pos > BULK_OUT_DATA_SIZE) {
+    if (p->iov.size + s->bulk_out_pos > BULK_OUT_DATA_SIZE) {
         return USB_RET_STALL;
     }
     ccid_header = (CCID_Header *)s->bulk_out_data;
-    memcpy(s->bulk_out_data + s->bulk_out_pos, p->data, p->len);
-    s->bulk_out_pos += p->len;
-    if (p->len == CCID_MAX_PACKET_SIZE) {
+    usb_packet_copy(p, s->bulk_out_data + s->bulk_out_pos, p->iov.size);
+    s->bulk_out_pos += p->iov.size;
+    if (p->iov.size == CCID_MAX_PACKET_SIZE) {
         DPRINTF(s, D_VERBOSE,
-            "usb-ccid: bulk_in: expecting more packets (%d/%d)\n",
-            p->len, ccid_header->dwLength);
+            "usb-ccid: bulk_in: expecting more packets (%zd/%d)\n",
+            p->iov.size, ccid_header->dwLength);
         return 0;
     }
     if (s->bulk_out_pos < 10) {
@@ -1006,15 +1006,17 @@ static int ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p)
     return 0;
 }
 
-static int ccid_bulk_in_copy_to_guest(USBCCIDState *s, uint8_t *data, int len)
+static int ccid_bulk_in_copy_to_guest(USBCCIDState *s, USBPacket *p)
 {
     int ret = 0;
 
-    assert(len > 0);
+    assert(p->iov.size > 0);
     ccid_bulk_in_get(s);
     if (s->current_bulk_in != NULL) {
-        ret = MIN(s->current_bulk_in->len - s->current_bulk_in->pos, len);
-        memcpy(data, s->current_bulk_in->data + s->current_bulk_in->pos, ret);
+        ret = MIN(s->current_bulk_in->len - s->current_bulk_in->pos,
+                  p->iov.size);
+        usb_packet_copy(p, s->current_bulk_in->data +
+                        s->current_bulk_in->pos, ret);
         s->current_bulk_in->pos += ret;
         if (s->current_bulk_in->pos == s->current_bulk_in->len) {
             ccid_bulk_in_release(s);
@@ -1025,11 +1027,13 @@ static int ccid_bulk_in_copy_to_guest(USBCCIDState *s, uint8_t *data, int len)
     }
     if (ret > 0) {
         DPRINTF(s, D_MORE_INFO,
-                "%s: %d/%d req/act to guest (BULK_IN)\n", __func__, len, ret);
+                "%s: %zd/%d req/act to guest (BULK_IN)\n",
+                __func__, p->iov.size, ret);
     }
-    if (ret != USB_RET_NAK && ret < len) {
+    if (ret != USB_RET_NAK && ret < p->iov.size) {
         DPRINTF(s, 1,
-            "%s: returning short (EREMOTEIO) %d < %d\n", __func__, ret, len);
+                "%s: returning short (EREMOTEIO) %d < %zd\n",
+                __func__, ret, p->iov.size);
     }
     return ret;
 }
@@ -1038,8 +1042,7 @@ static int ccid_handle_data(USBDevice *dev, USBPacket *p)
 {
     USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
     int ret = 0;
-    uint8_t *data = p->data;
-    int len = p->len;
+    uint8_t buf[2];
 
     switch (p->pid) {
     case USB_TOKEN_OUT:
@@ -1049,24 +1052,25 @@ static int ccid_handle_data(USBDevice *dev, USBPacket *p)
     case USB_TOKEN_IN:
         switch (p->devep & 0xf) {
         case CCID_BULK_IN_EP:
-            if (!len) {
+            if (!p->iov.size) {
                 ret = USB_RET_NAK;
             } else {
-                ret = ccid_bulk_in_copy_to_guest(s, data, len);
+                ret = ccid_bulk_in_copy_to_guest(s, p);
             }
             break;
         case CCID_INT_IN_EP:
             if (s->notify_slot_change) {
                 /* page 56, RDR_to_PC_NotifySlotChange */
-                data[0] = CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange;
-                data[1] = s->bmSlotICCState;
+                buf[0] = CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange;
+                buf[1] = s->bmSlotICCState;
+                usb_packet_copy(p, buf, 2);
                 ret = 2;
                 s->notify_slot_change = false;
                 s->bmSlotICCState &= ~SLOT_0_CHANGED_MASK;
                 DPRINTF(s, D_INFO,
                         "handle_data: int_in: notify_slot_change %X, "
-                        "requested len %d\n",
-                        s->bmSlotICCState, len);
+                        "requested len %zd\n",
+                        s->bmSlotICCState, p->iov.size);
             }
             break;
         default:
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 8b0dcc3..799e31a 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -1235,7 +1235,7 @@ static void ehci_async_complete_packet(USBPort *port, USBPacket *packet)
     trace_usb_ehci_queue_action(q, "wakeup");
     assert(q->async == EHCI_ASYNC_INFLIGHT);
     q->async = EHCI_ASYNC_FINISHED;
-    q->usb_status = packet->len;
+    q->usb_status = packet->result;
 }
 
 static void ehci_execute_complete(EHCIQueue *q)
@@ -1367,17 +1367,15 @@ static int ehci_execute(EHCIQueue *q)
             continue;
         }
 
-        q->packet.pid = q->pid;
-        q->packet.devaddr = devadr;
-        q->packet.devep = endp;
-        q->packet.data = q->buffer;
-        q->packet.len = q->tbytes;
+        usb_packet_setup(&q->packet, q->pid, devadr, endp);
+        usb_packet_addbuf(&q->packet, q->buffer, q->tbytes);
 
         ret = usb_handle_packet(dev, &q->packet);
 
-        DPRINTF("submit: qh %x next %x qtd %x pid %x len %d (total %d) endp %x ret %d\n",
+        DPRINTF("submit: qh %x next %x qtd %x pid %x len %zd "
+                "(total %d) endp %x ret %d\n",
                 q->qhaddr, q->qh.next, q->qtdaddr, q->pid,
-                q->packet.len, q->tbytes, endp, ret);
+                q->packet.iov.size, q->tbytes, endp, ret);
 
         if (ret != USB_RET_NODEV) {
             break;
@@ -1457,11 +1455,8 @@ static int ehci_process_itd(EHCIState *ehci,
                     continue;
                 }
 
-                ehci->ipacket.pid = pid;
-                ehci->ipacket.devaddr = devaddr;
-                ehci->ipacket.devep = endp;
-                ehci->ipacket.data = ehci->ibuffer;
-                ehci->ipacket.len = len;
+                usb_packet_setup(&ehci->ipacket, pid, devaddr, endp);
+                usb_packet_addbuf(&ehci->ipacket, ehci->ibuffer, len);
 
                 ret = usb_handle_packet(dev, &ehci->ipacket);
 
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index 9008320..541644a 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -816,6 +816,7 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
 static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
 {
     USBHIDState *s = (USBHIDState *)dev;
+    uint8_t buf[p->iov.size];
     int ret = 0;
 
     switch(p->pid) {
@@ -826,11 +827,12 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
                 return USB_RET_NAK;
             usb_hid_set_next_idle(s, curtime);
             if (s->kind == USB_MOUSE || s->kind == USB_TABLET) {
-                ret = usb_pointer_poll(s, p->data, p->len);
+                ret = usb_pointer_poll(s, buf, p->iov.size);
             }
             else if (s->kind == USB_KEYBOARD) {
-                ret = usb_keyboard_poll(s, p->data, p->len);
+                ret = usb_keyboard_poll(s, buf, p->iov.size);
             }
+            usb_packet_copy(p, buf, ret);
             s->changed = s->n > 0;
         } else {
             goto fail;
diff --git a/hw/usb-hub.c b/hw/usb-hub.c
index b49a2fe..c49c547 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -394,11 +394,12 @@ static int usb_hub_handle_data(USBDevice *dev, USBPacket *p)
         if (p->devep == 1) {
             USBHubPort *port;
             unsigned int status;
+            uint8_t buf[4];
             int i, n;
             n = (NUM_PORTS + 1 + 7) / 8;
-            if (p->len == 1) { /* FreeBSD workaround */
+            if (p->iov.size == 1) { /* FreeBSD workaround */
                 n = 1;
-            } else if (n > p->len) {
+            } else if (n > p->iov.size) {
                 return USB_RET_BABBLE;
             }
             status = 0;
@@ -409,8 +410,9 @@ static int usb_hub_handle_data(USBDevice *dev, USBPacket *p)
             }
             if (status != 0) {
                 for(i = 0; i < n; i++) {
-                    p->data[i] = status >> (8 * i);
+                    buf[i] = status >> (8 * i);
                 }
+                usb_packet_copy(p, buf, n);
                 ret = n;
             } else {
                 ret = USB_RET_NAK; /* usb11 11.13.1 */
diff --git a/hw/usb-libhw.c b/hw/usb-libhw.c
new file mode 100644
index 0000000..162b42b
--- /dev/null
+++ b/hw/usb-libhw.c
@@ -0,0 +1,63 @@
+/*
+ * QEMU USB emulation, libhw bits.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "qemu-common.h"
+#include "cpu-common.h"
+#include "usb.h"
+#include "dma.h"
+
+int usb_packet_map(USBPacket *p, QEMUSGList *sgl)
+{
+    int is_write = (p->pid == USB_TOKEN_IN);
+    target_phys_addr_t len;
+    void *mem;
+    int i;
+
+    for (i = 0; i < sgl->nsg; i++) {
+        len = sgl->sg[i].len;
+        mem = cpu_physical_memory_map(sgl->sg[i].base, &len,
+                                      is_write);
+        if (!mem) {
+            goto err;
+        }
+        qemu_iovec_add(&p->iov, mem, len);
+        if (len != sgl->sg[i].len) {
+            goto err;
+        }
+    }
+    return 0;
+
+err:
+    usb_packet_unmap(p);
+    return -1;
+}
+
+void usb_packet_unmap(USBPacket *p)
+{
+    int is_write = (p->pid == USB_TOKEN_IN);
+    int i;
+
+    for (i = 0; i < p->iov.niov; i++) {
+        cpu_physical_memory_unmap(p->iov.iov[i].iov_base,
+                                  p->iov.iov[i].iov_len, is_write,
+                                  p->iov.iov[i].iov_len);
+    }
+}
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index cdeac58..48e0b34 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -207,8 +207,9 @@ static void usb_msd_send_status(MSDState *s, USBPacket *p)
     csw.residue = s->residue;
     csw.status = s->result;
 
-    len = MIN(sizeof(csw), p->len);
-    memcpy(p->data, &csw, len);
+    len = MIN(sizeof(csw), p->iov.size);
+    usb_packet_copy(p, &csw, len);
+    p->result = len;
 }
 
 static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
@@ -222,6 +223,7 @@ static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
     if (p) {
         usb_msd_copy_data(s);
         if (s->packet && s->usb_len == 0) {
+            p->result = p->iov.size;
             /* Set s->packet to NULL before calling usb_packet_complete
                because another request may be issued before
                usb_packet_complete returns.  */
@@ -257,6 +259,7 @@ static void usb_msd_command_complete(SCSIRequest *req, uint32_t status)
             if (s->data_len == 0) {
                 s->mode = USB_MSDM_CSW;
             }
+            p->result = p->iov.size;
         }
         s->packet = NULL;
         usb_packet_complete(&s->dev, p);
@@ -342,9 +345,10 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
     int ret = 0;
     struct usb_msd_cbw cbw;
     uint8_t devep = p->devep;
-    uint8_t *data = p->data;
-    int len = p->len;
+    uint8_t *data = p->iov.iov[0].iov_base;
+    int len = p->iov.iov[0].iov_len;
 
+    assert(p->iov.niov == 1); /* temporary */
     switch (p->pid) {
     case USB_TOKEN_OUT:
         if (devep != 2)
diff --git a/hw/usb-musb.c b/hw/usb-musb.c
index 035dda8..d3ccde9 100644
--- a/hw/usb-musb.c
+++ b/hw/usb-musb.c
@@ -365,6 +365,8 @@ struct MUSBState *musb_init(qemu_irq *irqs)
         s->ep[i].maxp[1] = 0x40;
         s->ep[i].musb = s;
         s->ep[i].epnum = i;
+        usb_packet_init(&s->ep[i].packey[0].p);
+        usb_packet_init(&s->ep[i].packey[1].p);
     }
 
     usb_bus_new(&s->bus, &musb_bus_ops, NULL /* FIXME */);
@@ -605,12 +607,10 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
     ep->interrupt[dir] = ttype == USB_ENDPOINT_XFER_INT;
     ep->delayed_cb[dir] = cb;
 
-    ep->packey[dir].p.pid = pid;
     /* A wild guess on the FADDR semantics... */
-    ep->packey[dir].p.devaddr = ep->faddr[idx];
-    ep->packey[dir].p.devep = ep->type[idx] & 0xf;
-    ep->packey[dir].p.data = (void *) ep->buf[idx];
-    ep->packey[dir].p.len = len;
+    usb_packet_setup(&ep->packey[dir].p, pid, ep->faddr[idx],
+                     ep->type[idx] & 0xf);
+    usb_packet_addbuf(&ep->packey[dir].p, ep->buf[idx], len);
     ep->packey[dir].ep = ep;
     ep->packey[dir].dir = dir;
 
@@ -738,7 +738,7 @@ static void musb_rx_packet_complete(USBPacket *packey, void *opaque)
 
     if (ep->status[1] == USB_RET_STALL) {
         ep->status[1] = 0;
-        packey->len = 0;
+        packey->result = 0;
 
         ep->csr[1] |= MGC_M_RXCSR_H_RXSTALL;
         if (!epnum)
@@ -752,7 +752,7 @@ static void musb_rx_packet_complete(USBPacket *packey, void *opaque)
          * Data-errors in Isochronous.  */
         if (ep->interrupt[1])
             return musb_packet(s, ep, epnum, USB_TOKEN_IN,
-                            packey->len, musb_rx_packet_complete, 1);
+                            packey->iov.size, musb_rx_packet_complete, 1);
 
         ep->csr[1] |= MGC_M_RXCSR_DATAERROR;
         if (!epnum)
@@ -777,14 +777,14 @@ static void musb_rx_packet_complete(USBPacket *packey, void *opaque)
     /* TODO: check len for over/underruns of an OUT packet?  */
     /* TODO: perhaps make use of e->ext_size[1] here.  */
 
-    packey->len = ep->status[1];
+    packey->result = ep->status[1];
 
     if (!(ep->csr[1] & (MGC_M_RXCSR_H_RXSTALL | MGC_M_RXCSR_DATAERROR))) {
         ep->csr[1] |= MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY;
         if (!epnum)
             ep->csr[0] |= MGC_M_CSR0_RXPKTRDY;
 
-        ep->rxcount = packey->len; /* XXX: MIN(packey->len, ep->maxp[1]); */
+        ep->rxcount = packey->result; /* XXX: MIN(packey->len, ep->maxp[1]); */
         /* In DMA mode: assert DMA request for this EP */
     }
 
@@ -856,12 +856,12 @@ static void musb_rx_req(MUSBState *s, int epnum)
      * 64 bytes of the FIFO, only move the FIFO start and return. (Obsolete) */
     if (ep->packey[1].p.pid == USB_TOKEN_IN && ep->status[1] >= 0 &&
                     (ep->fifostart[1]) + ep->rxcount <
-                    ep->packey[1].p.len) {
+                    ep->packey[1].p.iov.size) {
         TRACE("0x%08x, %d",  ep->fifostart[1], ep->rxcount );
         ep->fifostart[1] += ep->rxcount;
         ep->fifolen[1] = 0;
 
-        ep->rxcount = MIN(ep->packey[0].p.len - (ep->fifostart[1]),
+        ep->rxcount = MIN(ep->packey[0].p.iov.size - (ep->fifostart[1]),
                         ep->maxp[1]);
 
         ep->csr[1] &= ~MGC_M_RXCSR_H_REQPKT;
diff --git a/hw/usb-net.c b/hw/usb-net.c
index 4212e5b..0cb47d6 100644
--- a/hw/usb-net.c
+++ b/hw/usb-net.c
@@ -29,6 +29,7 @@
 #include "net.h"
 #include "qemu-queue.h"
 #include "sysemu.h"
+#include "iov.h"
 
 /*#define TRAFFIC_DEBUG*/
 /* Thanks to NetChip Technologies for donating this product ID.
@@ -1121,28 +1122,23 @@ static int usb_net_handle_control(USBDevice *dev, USBPacket *p,
 
 static int usb_net_handle_statusin(USBNetState *s, USBPacket *p)
 {
+    le32 buf[2];
     int ret = 8;
 
-    if (p->len < 8)
+    if (p->iov.size < 8) {
         return USB_RET_STALL;
+    }
 
-    ((le32 *) p->data)[0] = cpu_to_le32(1);
-    ((le32 *) p->data)[1] = cpu_to_le32(0);
+    buf[0] = cpu_to_le32(1);
+    buf[1] = cpu_to_le32(0);
+    usb_packet_copy(p, buf, 8);
     if (!s->rndis_resp.tqh_first)
         ret = USB_RET_NAK;
 
 #ifdef TRAFFIC_DEBUG
-    fprintf(stderr, "usbnet: interrupt poll len %u return %d", p->len, ret);
-    {
-        int i;
-        fprintf(stderr, ":");
-        for (i = 0; i < ret; i++) {
-            if (!(i & 15))
-                fprintf(stderr, "\n%04x:", i);
-            fprintf(stderr, " %02x", p->data[i]);
-        }
-        fprintf(stderr, "\n\n");
-    }
+    fprintf(stderr, "usbnet: interrupt poll len %zu return %d",
+            p->iov.size, ret);
+    iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", ret);
 #endif
 
     return ret;
@@ -1162,9 +1158,10 @@ static int usb_net_handle_datain(USBNetState *s, USBPacket *p)
         return ret;
     }
     ret = s->in_len - s->in_ptr;
-    if (ret > p->len)
-        ret = p->len;
-    memcpy(p->data, &s->in_buf[s->in_ptr], ret);
+    if (ret > p->iov.size) {
+        ret = p->iov.size;
+    }
+    usb_packet_copy(p, &s->in_buf[s->in_ptr], ret);
     s->in_ptr += ret;
     if (s->in_ptr >= s->in_len &&
                     (is_rndis(s) || (s->in_len & (64 - 1)) || !ret)) {
@@ -1173,17 +1170,8 @@ static int usb_net_handle_datain(USBNetState *s, USBPacket *p)
     }
 
 #ifdef TRAFFIC_DEBUG
-    fprintf(stderr, "usbnet: data in len %u return %d", p->len, ret);
-    {
-        int i;
-        fprintf(stderr, ":");
-        for (i = 0; i < ret; i++) {
-            if (!(i & 15))
-                fprintf(stderr, "\n%04x:", i);
-            fprintf(stderr, " %02x", p->data[i]);
-        }
-        fprintf(stderr, "\n\n");
-    }
+    fprintf(stderr, "usbnet: data in len %zu return %d", p->iov.size, ret);
+    iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", ret);
 #endif
 
     return ret;
@@ -1191,29 +1179,20 @@ static int usb_net_handle_datain(USBNetState *s, USBPacket *p)
 
 static int usb_net_handle_dataout(USBNetState *s, USBPacket *p)
 {
-    int ret = p->len;
+    int ret = p->iov.size;
     int sz = sizeof(s->out_buf) - s->out_ptr;
     struct rndis_packet_msg_type *msg =
             (struct rndis_packet_msg_type *) s->out_buf;
     uint32_t len;
 
 #ifdef TRAFFIC_DEBUG
-    fprintf(stderr, "usbnet: data out len %u\n", p->len);
-    {
-        int i;
-        fprintf(stderr, ":");
-        for (i = 0; i < p->len; i++) {
-            if (!(i & 15))
-                fprintf(stderr, "\n%04x:", i);
-            fprintf(stderr, " %02x", p->data[i]);
-        }
-        fprintf(stderr, "\n\n");
-    }
+    fprintf(stderr, "usbnet: data out len %zu\n", p->iov.size);
+    iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", p->iov.size);
 #endif
 
     if (sz > ret)
         sz = ret;
-    memcpy(&s->out_buf[s->out_ptr], p->data, sz);
+    usb_packet_copy(p, &s->out_buf[s->out_ptr], sz);
     s->out_ptr += sz;
 
     if (!is_rndis(s)) {
@@ -1277,8 +1256,8 @@ static int usb_net_handle_data(USBDevice *dev, USBPacket *p)
     }
     if (ret == USB_RET_STALL)
         fprintf(stderr, "usbnet: failed data transaction: "
-                        "pid 0x%x ep 0x%x len 0x%x\n",
-                        p->pid, p->devep, p->len);
+                        "pid 0x%x ep 0x%x len 0x%zx\n",
+                        p->pid, p->devep, p->iov.size);
     return ret;
 }
 
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index 337b250..d39bcb0 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -777,18 +777,17 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
     }
 
     if (completion) {
-        ret = ohci->usb_packet.len;
+        ret = ohci->usb_packet.result;
     } else {
         ret = USB_RET_NODEV;
         for (i = 0; i < ohci->num_ports; i++) {
             dev = ohci->rhport[i].port.dev;
             if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0)
                 continue;
-            ohci->usb_packet.pid = pid;
-            ohci->usb_packet.devaddr = OHCI_BM(ed->flags, ED_FA);
-            ohci->usb_packet.devep = OHCI_BM(ed->flags, ED_EN);
-            ohci->usb_packet.data = ohci->usb_buf;
-            ohci->usb_packet.len = len;
+            usb_packet_setup(&ohci->usb_packet, pid,
+                             OHCI_BM(ed->flags, ED_FA),
+                             OHCI_BM(ed->flags, ED_EN));
+            usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);
             ret = usb_handle_packet(dev, &ohci->usb_packet);
             if (ret != USB_RET_NODEV)
                 break;
@@ -959,7 +958,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
     }
 #endif
     if (completion) {
-        ret = ohci->usb_packet.len;
+        ret = ohci->usb_packet.result;
         ohci->async_td = 0;
         ohci->async_complete = 0;
     } else {
@@ -980,11 +979,10 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
 #endif
                 return 1;
             }
-            ohci->usb_packet.pid = pid;
-            ohci->usb_packet.devaddr = OHCI_BM(ed->flags, ED_FA);
-            ohci->usb_packet.devep = OHCI_BM(ed->flags, ED_EN);
-            ohci->usb_packet.data = ohci->usb_buf;
-            ohci->usb_packet.len = len;
+            usb_packet_setup(&ohci->usb_packet, pid,
+                             OHCI_BM(ed->flags, ED_FA),
+                             OHCI_BM(ed->flags, ED_EN));
+            usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);
             ret = usb_handle_packet(dev, &ohci->usb_packet);
             if (ret != USB_RET_NODEV)
                 break;
@@ -1761,6 +1759,7 @@ static int usb_ohci_init(OHCIState *ohci, DeviceState *dev,
     ohci->localmem_base = localmem_base;
 
     ohci->name = dev->info->name;
+    usb_packet_init(&ohci->usb_packet);
 
     ohci->async_td = 0;
     qemu_register_reset(ohci_reset, ohci);
diff --git a/hw/usb-serial.c b/hw/usb-serial.c
index 298c1e9..09731da 100644
--- a/hw/usb-serial.c
+++ b/hw/usb-serial.c
@@ -361,10 +361,11 @@ static int usb_serial_handle_data(USBDevice *dev, USBPacket *p)
     USBSerialState *s = (USBSerialState *)dev;
     int ret = 0;
     uint8_t devep = p->devep;
-    uint8_t *data = p->data;
-    int len = p->len;
+    uint8_t *data = p->iov.iov[0].iov_base;
+    int len = p->iov.iov[0].iov_len;
     int first_len;
 
+    assert(p->iov.niov == 1); /* temporary */
     switch (p->pid) {
     case USB_TOKEN_OUT:
         if (devep != 2)
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index da74c57..20b829b 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -30,6 +30,7 @@
 #include "pci.h"
 #include "qemu-timer.h"
 #include "usb-uhci.h"
+#include "iov.h"
 
 //#define DEBUG
 //#define DEBUG_DUMP_DATA
@@ -93,17 +94,12 @@ static const char *pid2str(int pid)
 #endif
 
 #ifdef DEBUG_DUMP_DATA
-static void dump_data(const uint8_t *data, int len)
+static void dump_data(USBPacket *p, int ret)
 {
-    int i;
-
-    printf("uhci: data: ");
-    for(i = 0; i < len; i++)
-        printf(" %02x", data[i]);
-    printf("\n");
+    iov_hexdump(p->iov.iov, p->iov.niov, stderr, "uhci", ret);
 }
 #else
-static void dump_data(const uint8_t *data, int len) {}
+static void dump_data(USBPacket *p, int ret) {}
 #endif
 
 typedef struct UHCIState UHCIState;
@@ -179,12 +175,14 @@ static UHCIAsync *uhci_async_alloc(UHCIState *s)
     async->token = 0;
     async->done  = 0;
     async->isoc  = 0;
+    usb_packet_init(&async->packet);
 
     return async;
 }
 
 static void uhci_async_free(UHCIState *s, UHCIAsync *async)
 {
+    usb_packet_cleanup(&async->packet);
     qemu_free(async);
 }
 
@@ -648,10 +646,10 @@ static int uhci_broadcast_packet(UHCIState *s, USBPacket *p)
 {
     int i, ret;
 
-    DPRINTF("uhci: packet enter. pid %s addr 0x%02x ep %d len %d\n",
-           pid2str(p->pid), p->devaddr, p->devep, p->len);
+    DPRINTF("uhci: packet enter. pid %s addr 0x%02x ep %d len %zd\n",
+           pid2str(p->pid), p->devaddr, p->devep, p->iov.size);
     if (p->pid == USB_TOKEN_OUT || p->pid == USB_TOKEN_SETUP)
-        dump_data(p->data, p->len);
+        dump_data(p, 0);
 
     ret = USB_RET_NODEV;
     for (i = 0; i < NB_PORTS && ret == USB_RET_NODEV; i++) {
@@ -662,9 +660,9 @@ static int uhci_broadcast_packet(UHCIState *s, USBPacket *p)
             ret = usb_handle_packet(dev, p);
     }
 
-    DPRINTF("uhci: packet exit. ret %d len %d\n", ret, p->len);
+    DPRINTF("uhci: packet exit. ret %d len %zd\n", ret, p->iov.size);
     if (p->pid == USB_TOKEN_IN && ret > 0)
-        dump_data(p->data, ret);
+        dump_data(p, ret);
 
     return ret;
 }
@@ -684,7 +682,7 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_
     max_len = ((td->token >> 21) + 1) & 0x7ff;
     pid = td->token & 0xff;
 
-    ret = async->packet.len;
+    ret = async->packet.result;
 
     if (td->ctrl & TD_CTRL_IOS)
         td->ctrl &= ~TD_CTRL_ACTIVE;
@@ -692,7 +690,7 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_
     if (ret < 0)
         goto out;
 
-    len = async->packet.len;
+    len = async->packet.result;
     td->ctrl = (td->ctrl & ~0x7ff) | ((len - 1) & 0x7ff);
 
     /* The NAK bit may have been set by a previous frame, so clear it
@@ -827,11 +825,9 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *in
     max_len = ((td->token >> 21) + 1) & 0x7ff;
     pid = td->token & 0xff;
 
-    async->packet.pid     = pid;
-    async->packet.devaddr = (td->token >> 8) & 0x7f;
-    async->packet.devep   = (td->token >> 15) & 0xf;
-    async->packet.data    = async->buffer;
-    async->packet.len     = max_len;
+    usb_packet_setup(&async->packet, pid, (td->token >> 8) & 0x7f,
+                     (td->token >> 15) & 0xf);
+    usb_packet_addbuf(&async->packet, async->buffer, max_len);
 
     switch(pid) {
     case USB_TOKEN_OUT:
@@ -859,7 +855,7 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *in
         return 2;
     }
 
-    async->packet.len = len;
+    async->packet.result = len;
 
 done:
     len = uhci_complete_td(s, td, async, int_mask);
diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c
index d76ee97..2558006 100644
--- a/hw/usb-wacom.c
+++ b/hw/usb-wacom.c
@@ -308,6 +308,7 @@ static int usb_wacom_handle_control(USBDevice *dev, USBPacket *p,
 static int usb_wacom_handle_data(USBDevice *dev, USBPacket *p)
 {
     USBWacomState *s = (USBWacomState *) dev;
+    uint8_t buf[p->iov.size];
     int ret = 0;
 
     switch (p->pid) {
@@ -317,9 +318,10 @@ static int usb_wacom_handle_data(USBDevice *dev, USBPacket *p)
                 return USB_RET_NAK;
             s->changed = 0;
             if (s->mode == WACOM_MODE_HID)
-                ret = usb_mouse_poll(s, p->data, p->len);
+                ret = usb_mouse_poll(s, buf, p->iov.size);
             else if (s->mode == WACOM_MODE_WACOM)
-                ret = usb_wacom_poll(s, p->data, p->len);
+                ret = usb_wacom_poll(s, buf, p->iov.size);
+            usb_packet_copy(p, buf, ret);
             break;
         }
         /* Fall through.  */
diff --git a/hw/usb.c b/hw/usb.c
index 27a983c..685e775 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -25,6 +25,7 @@
  */
 #include "qemu-common.h"
 #include "usb.h"
+#include "iov.h"
 
 void usb_attach(USBPort *port, USBDevice *dev)
 {
@@ -72,10 +73,11 @@ static int do_token_setup(USBDevice *s, USBPacket *p)
     int request, value, index;
     int ret = 0;
 
-    if (p->len != 8)
+    if (p->iov.size != 8) {
         return USB_RET_STALL;
- 
-    memcpy(s->setup_buf, p->data, 8);
+    }
+
+    usb_packet_copy(p, s->setup_buf, p->iov.size);
     s->setup_len   = (s->setup_buf[7] << 8) | s->setup_buf[6];
     s->setup_index = 0;
 
@@ -144,9 +146,10 @@ static int do_token_in(USBDevice *s, USBPacket *p)
     case SETUP_STATE_DATA:
         if (s->setup_buf[0] & USB_DIR_IN) {
             int len = s->setup_len - s->setup_index;
-            if (len > p->len)
-                len = p->len;
-            memcpy(p->data, s->data_buf + s->setup_index, len);
+            if (len > p->iov.size) {
+                len = p->iov.size;
+            }
+            usb_packet_copy(p, s->data_buf + s->setup_index, len);
             s->setup_index += len;
             if (s->setup_index >= s->setup_len)
                 s->setup_state = SETUP_STATE_ACK;
@@ -179,9 +182,10 @@ static int do_token_out(USBDevice *s, USBPacket *p)
     case SETUP_STATE_DATA:
         if (!(s->setup_buf[0] & USB_DIR_IN)) {
             int len = s->setup_len - s->setup_index;
-            if (len > p->len)
-                len = p->len;
-            memcpy(s->data_buf + s->setup_index, p->data, len);
+            if (len > p->iov.size) {
+                len = p->iov.size;
+            }
+            usb_packet_copy(p, s->data_buf + s->setup_index, len);
             s->setup_index += len;
             if (s->setup_index >= s->setup_len)
                 s->setup_state = SETUP_STATE_ACK;
@@ -251,22 +255,22 @@ int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
    usb_packet_complete to complete their async control packets. */
 void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p)
 {
-    if (p->len < 0) {
+    if (p->result < 0) {
         s->setup_state = SETUP_STATE_IDLE;
     }
 
     switch (s->setup_state) {
     case SETUP_STATE_SETUP:
-        if (p->len < s->setup_len) {
-            s->setup_len = p->len;
+        if (p->result < s->setup_len) {
+            s->setup_len = p->result;
         }
         s->setup_state = SETUP_STATE_DATA;
-        p->len = 8;
+        p->result = 8;
         break;
 
     case SETUP_STATE_ACK:
         s->setup_state = SETUP_STATE_IDLE;
-        p->len = 0;
+        p->result = 0;
         break;
 
     default:
@@ -347,3 +351,57 @@ void usb_cancel_packet(USBPacket * p)
     p->owner->info->cancel_packet(p->owner, p);
     p->owner = NULL;
 }
+
+
+void usb_packet_init(USBPacket *p)
+{
+    qemu_iovec_init(&p->iov, 1);
+}
+
+void usb_packet_setup(USBPacket *p, int pid, uint8_t addr, uint8_t ep)
+{
+    p->pid = pid;
+    p->devaddr = addr;
+    p->devep = ep;
+    p->result = 0;
+    qemu_iovec_reset(&p->iov);
+}
+
+void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len)
+{
+    qemu_iovec_add(&p->iov, ptr, len);
+}
+
+void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes)
+{
+    assert(p->result >= 0);
+    assert(p->result + bytes <= p->iov.size);
+    switch (p->pid) {
+    case USB_TOKEN_SETUP:
+    case USB_TOKEN_OUT:
+        iov_to_buf(p->iov.iov, p->iov.niov, ptr, p->result, bytes);
+        break;
+    case USB_TOKEN_IN:
+        iov_from_buf(p->iov.iov, p->iov.niov, ptr, p->result, bytes);
+        break;
+    default:
+        fprintf(stderr, "%s: invalid pid: %x\n", __func__, p->pid);
+        abort();
+    }
+    p->result += bytes;
+}
+
+void usb_packet_skip(USBPacket *p, size_t bytes)
+{
+    assert(p->result >= 0);
+    assert(p->result + bytes <= p->iov.size);
+    if (p->pid == USB_TOKEN_IN) {
+        iov_clear(p->iov.iov, p->iov.niov, p->result, bytes);
+    }
+    p->result += bytes;
+}
+
+void usb_packet_cleanup(USBPacket *p)
+{
+    qemu_iovec_destroy(&p->iov);
+}
diff --git a/hw/usb.h b/hw/usb.h
index ded2de2..84d04df 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -285,12 +285,21 @@ struct USBPacket {
     int pid;
     uint8_t devaddr;
     uint8_t devep;
-    uint8_t *data;
-    int len;
+    QEMUIOVector iov;
+    int result; /* transfer length or USB_RET_* status code */
     /* Internal use by the USB layer.  */
     USBDevice *owner;
 };
 
+void usb_packet_init(USBPacket *p);
+void usb_packet_setup(USBPacket *p, int pid, uint8_t addr, uint8_t ep);
+void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len);
+int usb_packet_map(USBPacket *p, QEMUSGList *sgl);
+void usb_packet_unmap(USBPacket *p);
+void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes);
+void usb_packet_skip(USBPacket *p, size_t bytes);
+void usb_packet_cleanup(USBPacket *p);
+
 int usb_handle_packet(USBDevice *dev, USBPacket *p);
 void usb_packet_complete(USBDevice *dev, USBPacket *p);
 void usb_cancel_packet(USBPacket * p);
diff --git a/usb-bsd.c b/usb-bsd.c
index ab8e3b7..ab84d93 100644
--- a/usb-bsd.c
+++ b/usb-bsd.c
@@ -253,9 +253,9 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
     }
 
     if (p->pid == USB_TOKEN_IN)
-        ret = read(fd, p->data, p->len);
+        ret = readv(fd, p->iov.iov, p->iov.niov);
     else
-        ret = write(fd, p->data, p->len);
+        ret = writev(fd, p->iov.iov, p->iov.niov);
 
     sigprocmask(SIG_SETMASK, &old_mask, NULL);
 
diff --git a/usb-linux.c b/usb-linux.c
index 53cc5fc..184f56f 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -341,16 +341,16 @@ static void async_complete(void *opaque)
         if (p) {
             switch (aurb->urb.status) {
             case 0:
-                p->len += aurb->urb.actual_length;
+                p->result += aurb->urb.actual_length;
                 break;
 
             case -EPIPE:
                 set_halt(s, p->devep);
-                p->len = USB_RET_STALL;
+                p->result = USB_RET_STALL;
                 break;
 
             default:
-                p->len = USB_RET_NAK;
+                p->result = USB_RET_NAK;
                 break;
             }
 
@@ -604,6 +604,7 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
 {
     AsyncURB *aurb;
     int i, j, ret, max_packet_size, offset, len = 0;
+    uint8_t *buf;
 
     max_packet_size = get_max_packet_size(s, p->devep);
     if (max_packet_size == 0)
@@ -628,19 +629,19 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
                 len = urb_status_to_usb_ret(
                                         aurb[i].urb.iso_frame_desc[j].status);
             /* Check the frame fits */
-            } else if (aurb[i].urb.iso_frame_desc[j].actual_length > p->len) {
+            } else if (aurb[i].urb.iso_frame_desc[j].actual_length
+                       > p->iov.size) {
                 printf("husb: received iso data is larger then packet\n");
                 len = USB_RET_NAK;
             /* All good copy data over */
             } else {
                 len = aurb[i].urb.iso_frame_desc[j].actual_length;
-                memcpy(p->data,
-                       aurb[i].urb.buffer +
-                           j * aurb[i].urb.iso_frame_desc[0].length,
-                       len);
+                buf  = aurb[i].urb.buffer +
+                    j * aurb[i].urb.iso_frame_desc[0].length;
+                usb_packet_copy(p, buf, len);
             }
         } else {
-            len = p->len;
+            len = p->iov.size;
             offset = (j == 0) ? 0 : get_iso_buffer_used(s, p->devep);
 
             /* Check the frame fits */
@@ -650,7 +651,7 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
             }
 
             /* All good copy data over */
-            memcpy(aurb[i].urb.buffer + offset, p->data, len);
+            usb_packet_copy(p, aurb[i].urb.buffer + offset, len);
             aurb[i].urb.iso_frame_desc[j].length = len;
             offset += len;
             set_iso_buffer_used(s, p->devep, offset);
@@ -734,9 +735,9 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
         return usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN);
     }
 
-    rem = p->len;
-    pbuf = p->data;
-    p->len = 0;
+    assert(p->iov.niov == 1); /* temporary */
+    rem = p->iov.iov[0].iov_len;
+    pbuf = p->iov.iov[0].iov_base;
     while (rem) {
         aurb = async_alloc(s);
         aurb->packet = p;
diff --git a/usb-redir.c b/usb-redir.c
index e212993..9e5fce2 100644
--- a/usb-redir.c
+++ b/usb-redir.c
@@ -365,12 +365,12 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
         }
 
         len = isop->len;
-        if (len > p->len) {
+        if (len > p->iov.size) {
             ERROR("received iso data is larger then packet ep %02X\n", ep);
             bufp_free(dev, isop, ep);
             return USB_RET_NAK;
         }
-        memcpy(p->data, isop->data, len);
+        usb_packet_copy(p, isop->data, len);
         bufp_free(dev, isop, ep);
         return len;
     } else {
@@ -379,18 +379,20 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
         if (dev->endpoint[EP2I(ep)].iso_started) {
             struct usb_redir_iso_packet_header iso_packet = {
                 .endpoint = ep,
-                .length = p->len
+                .length = p->iov.size
             };
+            uint8_t buf[p->iov.size];
             /* No id, we look at the ep when receiving a status back */
+            usb_packet_copy(p, buf, p->iov.size);
             usbredirparser_send_iso_packet(dev->parser, 0, &iso_packet,
-                                           p->data, p->len);
+                                           buf, p->iov.size);
             usbredirparser_do_write(dev->parser);
         }
         status = dev->endpoint[EP2I(ep)].iso_error;
         dev->endpoint[EP2I(ep)].iso_error = 0;
-        DPRINTF2("iso-token-out ep %02X status %d len %d\n", ep, status,
-                 p->len);
-        return usbredir_handle_status(dev, status, p->len);
+        DPRINTF2("iso-token-out ep %02X status %d len %zd\n", ep, status,
+                 p->iov.size);
+        return usbredir_handle_status(dev, status, p->iov.size);
     }
 }
 
@@ -413,10 +415,11 @@ static int usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p,
     AsyncURB *aurb = async_alloc(dev, p);
     struct usb_redir_bulk_packet_header bulk_packet;
 
-    DPRINTF("bulk-out ep %02X len %d id %u\n", ep, p->len, aurb->packet_id);
+    DPRINTF("bulk-out ep %02X len %zd id %u\n", ep,
+            p->iov.size, aurb->packet_id);
 
     bulk_packet.endpoint  = ep;
-    bulk_packet.length    = p->len;
+    bulk_packet.length    = p->iov.size;
     bulk_packet.stream_id = 0;
     aurb->bulk_packet = bulk_packet;
 
@@ -424,9 +427,11 @@ static int usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p,
         usbredirparser_send_bulk_packet(dev->parser, aurb->packet_id,
                                         &bulk_packet, NULL, 0);
     } else {
-        usbredir_log_data(dev, "bulk data out:", p->data, p->len);
+        uint8_t buf[p->iov.size];
+        usb_packet_copy(p, buf, p->iov.size);
+        usbredir_log_data(dev, "bulk data out:", buf, p->iov.size);
         usbredirparser_send_bulk_packet(dev->parser, aurb->packet_id,
-                                        &bulk_packet, p->data, p->len);
+                                        &bulk_packet, buf, p->iov.size);
     }
     usbredirparser_do_write(dev->parser);
     return USB_RET_ASYNC;
@@ -471,29 +476,31 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev,
         }
 
         len = intp->len;
-        if (len > p->len) {
+        if (len > p->iov.size) {
             ERROR("received int data is larger then packet ep %02X\n", ep);
             bufp_free(dev, intp, ep);
             return USB_RET_NAK;
         }
-        memcpy(p->data, intp->data, len);
+        usb_packet_copy(p, intp->data, len);
         bufp_free(dev, intp, ep);
         return len;
     } else {
         /* Output interrupt endpoint, normal async operation */
         AsyncURB *aurb = async_alloc(dev, p);
         struct usb_redir_interrupt_packet_header interrupt_packet;
+        uint8_t buf[p->iov.size];
 
-        DPRINTF("interrupt-out ep %02X len %d id %u\n", ep, p->len,
+        DPRINTF("interrupt-out ep %02X len %zd id %u\n", ep, p->iov.size,
                 aurb->packet_id);
 
         interrupt_packet.endpoint  = ep;
-        interrupt_packet.length    = p->len;
+        interrupt_packet.length    = p->iov.size;
         aurb->interrupt_packet     = interrupt_packet;
 
-        usbredir_log_data(dev, "interrupt data out:", p->data, p->len);
+        usb_packet_copy(p, buf, p->iov.size);
+        usbredir_log_data(dev, "interrupt data out:", buf, p->iov.size);
         usbredirparser_send_interrupt_packet(dev->parser, aurb->packet_id,
-                                        &interrupt_packet, p->data, p->len);
+                                        &interrupt_packet, buf, p->iov.size);
         usbredirparser_do_write(dev->parser);
         return USB_RET_ASYNC;
     }
@@ -959,7 +966,7 @@ static void usbredir_configuration_status(void *priv, uint32_t id,
             dev->dev.data_buf[0] = config_status->configuration;
             len = 1;
         }
-        aurb->packet->len =
+        aurb->packet->result =
             usbredir_handle_status(dev, config_status->status, len);
         usb_generic_async_ctrl_complete(&dev->dev, aurb->packet);
     }
@@ -987,7 +994,7 @@ static void usbredir_alt_setting_status(void *priv, uint32_t id,
             dev->dev.data_buf[0] = alt_setting_status->alt;
             len = 1;
         }
-        aurb->packet->len =
+        aurb->packet->result =
             usbredir_handle_status(dev, alt_setting_status->status, len);
         usb_generic_async_ctrl_complete(&dev->dev, aurb->packet);
     }
@@ -1070,7 +1077,7 @@ static void usbredir_control_packet(void *priv, uint32_t id,
                 len = USB_RET_STALL;
             }
         }
-        aurb->packet->len = len;
+        aurb->packet->result = len;
         usb_generic_async_ctrl_complete(&dev->dev, aurb->packet);
     }
     async_free(dev, aurb);
@@ -1105,15 +1112,15 @@ static void usbredir_bulk_packet(void *priv, uint32_t id,
         len = usbredir_handle_status(dev, bulk_packet->status, len);
         if (len > 0) {
             usbredir_log_data(dev, "bulk data in:", data, data_len);
-            if (data_len <= aurb->packet->len) {
-                memcpy(aurb->packet->data, data, data_len);
+            if (data_len <= aurb->packet->iov.size) {
+                usb_packet_copy(aurb->packet, data, data_len);
             } else {
-                ERROR("bulk buffer too small (%d > %d)\n", data_len,
-                      aurb->packet->len);
+                ERROR("bulk buffer too small (%d > %zd)\n", data_len,
+                      aurb->packet->iov.size);
                 len = USB_RET_STALL;
             }
         }
-        aurb->packet->len = len;
+        aurb->packet->result = len;
         usb_packet_complete(&dev->dev, aurb->packet);
     }
     async_free(dev, aurb);
@@ -1185,7 +1192,7 @@ static void usbredir_interrupt_packet(void *priv, uint32_t id,
         }
 
         if (aurb->packet) {
-            aurb->packet->len = usbredir_handle_status(dev,
+            aurb->packet->result = usbredir_handle_status(dev,
                                                interrupt_packet->status, len);
             usb_packet_complete(&dev->dev, aurb->packet);
         }
commit d35bf9ade5293171f13bc5fd1460920a258e3e39
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Jul 12 13:36:23 2011 +0200

    move QEMUSGList typedef
    
    Move the QEMUSGList typedef to qemu-common so it can easily be used.
    The actual struct definition stays in dma.h.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/dma.h b/dma.h
index 3d8324b..a6db5ba 100644
--- a/dma.h
+++ b/dma.h
@@ -20,12 +20,12 @@ typedef struct {
     target_phys_addr_t len;
 } ScatterGatherEntry;
 
-typedef struct {
+struct QEMUSGList {
     ScatterGatherEntry *sg;
     int nsg;
     int nalloc;
     target_phys_addr_t size;
-} QEMUSGList;
+};
 
 void qemu_sglist_init(QEMUSGList *qsg, int alloc_hint);
 void qemu_sglist_add(QEMUSGList *qsg, target_phys_addr_t base,
diff --git a/qemu-common.h b/qemu-common.h
index 1e3c665..c7064d3 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -270,6 +270,7 @@ typedef struct I2SCodec I2SCodec;
 typedef struct SSIBus SSIBus;
 typedef struct EventNotifier EventNotifier;
 typedef struct VirtIODevice VirtIODevice;
+typedef struct QEMUSGList QEMUSGList;
 
 typedef uint64_t pcibus_t;
 
commit 8d15028ec03999fa6eca8dba7ef7cd4eb575486b
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Jul 13 15:16:08 2011 +0200

    Add iov_clear()
    
    Fill the spefified area with zeros.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/iov.c b/iov.c
index 60553c7..e7385c4 100644
--- a/iov.c
+++ b/iov.c
@@ -62,6 +62,29 @@ size_t iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt,
     return buf_off;
 }
 
+size_t iov_clear(const struct iovec *iov, const unsigned int iov_cnt,
+                 size_t iov_off, size_t size)
+{
+    size_t iovec_off, buf_off;
+    unsigned int i;
+
+    iovec_off = 0;
+    buf_off = 0;
+    for (i = 0; i < iov_cnt && size; i++) {
+        if (iov_off < (iovec_off + iov[i].iov_len)) {
+            size_t len = MIN((iovec_off + iov[i].iov_len) - iov_off , size);
+
+            memset(iov[i].iov_base + (iov_off - iovec_off), 0, len);
+
+            buf_off += len;
+            iov_off += len;
+            size -= len;
+        }
+        iovec_off += iov[i].iov_len;
+    }
+    return buf_off;
+}
+
 size_t iov_size(const struct iovec *iov, const unsigned int iov_cnt)
 {
     size_t len;
diff --git a/iov.h b/iov.h
index c2c5b39..94d2f78 100644
--- a/iov.h
+++ b/iov.h
@@ -17,5 +17,7 @@ size_t iov_from_buf(struct iovec *iov, unsigned int iov_cnt,
 size_t iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt,
                   void *buf, size_t iov_off, size_t size);
 size_t iov_size(const struct iovec *iov, const unsigned int iov_cnt);
+size_t iov_clear(const struct iovec *iov, const unsigned int iov_cnt,
+                 size_t iov_off, size_t size);
 void iov_hexdump(const struct iovec *iov, const unsigned int iov_cnt,
                  FILE *fp, const char *prefix, size_t limit);
commit 3a1dca94d6dba00fe0fd4c4a28449f57e01b9b6c
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Jul 12 13:35:10 2011 +0200

    Add iov_hexdump()
    
    Useful for debugging purposes.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/iov.c b/iov.c
index 1e02791..60553c7 100644
--- a/iov.c
+++ b/iov.c
@@ -73,3 +73,34 @@ size_t iov_size(const struct iovec *iov, const unsigned int iov_cnt)
     }
     return len;
 }
+
+void iov_hexdump(const struct iovec *iov, const unsigned int iov_cnt,
+                 FILE *fp, const char *prefix, size_t limit)
+{
+    unsigned int i, v, b;
+    uint8_t *c;
+
+    c = iov[0].iov_base;
+    for (i = 0, v = 0, b = 0; b < limit; i++, b++) {
+        if (i == iov[v].iov_len) {
+            i = 0; v++;
+            if (v == iov_cnt) {
+                break;
+            }
+            c = iov[v].iov_base;
+        }
+        if ((b % 16) == 0) {
+            fprintf(fp, "%s: %04x:", prefix, b);
+        }
+        if ((b % 4) == 0) {
+            fprintf(fp, " ");
+        }
+        fprintf(fp, " %02x", c[i]);
+        if ((b % 16) == 15) {
+            fprintf(fp, "\n");
+        }
+    }
+    if ((b % 16) != 0) {
+        fprintf(fp, "\n");
+    }
+}
diff --git a/iov.h b/iov.h
index 110f67a..c2c5b39 100644
--- a/iov.h
+++ b/iov.h
@@ -17,3 +17,5 @@ size_t iov_from_buf(struct iovec *iov, unsigned int iov_cnt,
 size_t iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt,
                   void *buf, size_t iov_off, size_t size);
 size_t iov_size(const struct iovec *iov, const unsigned int iov_cnt);
+void iov_hexdump(const struct iovec *iov, const unsigned int iov_cnt,
+                 FILE *fp, const char *prefix, size_t limit);
commit fa57ee8ed246cfea53acd09663203deda64b4f33
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Aug 4 14:54:19 2011 +0200

    re-activate usb-host for bsd
    
    A bunch of code was disabled via #if 0, for a quite long time (since
    Sept 2009).  Surprisingly the code builds just fine when they are
    removed (tested on OpenBSD).  /me wonders nevertheless whenever there
    are any users of those bits when this went unnoticed for almost two
    years ...
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/usb-bsd.c b/usb-bsd.c
index 3b97eb4..ab8e3b7 100644
--- a/usb-bsd.c
+++ b/usb-bsd.c
@@ -62,7 +62,6 @@ typedef struct USBHostDevice {
 } USBHostDevice;
 
 
-#if 0
 static int ensure_ep_open(USBHostDevice *dev, int ep, int mode)
 {
     char buf[32];
@@ -110,7 +109,6 @@ static void ensure_eps_closed(USBHostDevice *dev)
         epnum++;
     }
 }
-#endif
 
 static void usb_host_handle_reset(USBDevice *dev)
 {
@@ -119,7 +117,6 @@ static void usb_host_handle_reset(USBDevice *dev)
 #endif
 }
 
-#if 0
 /* XXX:
  * -check device states against transfer requests
  *  and return appropriate response
@@ -278,7 +275,6 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
         return ret;
     }
 }
-#endif
 
 static void usb_host_handle_destroy(USBDevice *opaque)
 {
@@ -305,8 +301,8 @@ static int usb_host_initfn(USBDevice *dev)
 USBDevice *usb_host_device_open(const char *devname)
 {
     struct usb_device_info bus_info, dev_info;
-    USBDevice *d = NULL;
-    USBHostDevice *dev, *ret = NULL;
+    USBDevice *d = NULL, *ret = NULL;
+    USBHostDevice *dev;
     char ctlpath[PATH_MAX + 1];
     char buspath[PATH_MAX + 1];
     int bfd, dfd, bus, address, i;
@@ -408,10 +404,8 @@ static struct USBDeviceInfo usb_host_dev_info = {
     .init           = usb_host_initfn,
     .handle_packet  = usb_generic_handle_packet,
     .handle_reset   = usb_host_handle_reset,
-#if 0
     .handle_control = usb_host_handle_control,
     .handle_data    = usb_host_handle_data,
-#endif
     .handle_destroy = usb_host_handle_destroy,
 };
 
commit e7a8a7837a964e0fe327e6ef8dde02c6a53dd14a
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Fri Jul 15 16:05:00 2011 +0200

    block: Use bdrv_co_* instead of synchronous versions in coroutines
    
    If we're already in a coroutine, there is no reason to use the synchronous
    version of block layer functions when a coroutine one exists. This makes
    bdrv_read/write/flush use bdrv_co_* when used inside a coroutine.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index 0d05b4b..26910ca 100644
--- a/block.c
+++ b/block.c
@@ -70,6 +70,7 @@ static int coroutine_fn bdrv_co_readv_em(BlockDriverState *bs,
 static int coroutine_fn bdrv_co_writev_em(BlockDriverState *bs,
                                          int64_t sector_num, int nb_sectors,
                                          QEMUIOVector *iov);
+static int coroutine_fn bdrv_co_flush_em(BlockDriverState *bs);
 
 static QTAILQ_HEAD(, BlockDriverState) bdrv_states =
     QTAILQ_HEAD_INITIALIZER(bdrv_states);
@@ -946,6 +947,17 @@ static int bdrv_check_request(BlockDriverState *bs, int64_t sector_num,
                                    nb_sectors * BDRV_SECTOR_SIZE);
 }
 
+static inline bool bdrv_has_async_rw(BlockDriver *drv)
+{
+    return drv->bdrv_co_readv != bdrv_co_readv_em
+        || drv->bdrv_aio_readv != bdrv_aio_readv_em;
+}
+
+static inline bool bdrv_has_async_flush(BlockDriver *drv)
+{
+    return drv->bdrv_aio_flush != bdrv_aio_flush_em;
+}
+
 /* return < 0 if error. See bdrv_write() for the return codes */
 int bdrv_read(BlockDriverState *bs, int64_t sector_num,
               uint8_t *buf, int nb_sectors)
@@ -954,6 +966,18 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num,
 
     if (!drv)
         return -ENOMEDIUM;
+
+    if (bdrv_has_async_rw(drv) && qemu_in_coroutine()) {
+        QEMUIOVector qiov;
+        struct iovec iov = {
+            .iov_base = (void *)buf,
+            .iov_len = nb_sectors * BDRV_SECTOR_SIZE,
+        };
+
+        qemu_iovec_init_external(&qiov, &iov, 1);
+        return bdrv_co_readv(bs, sector_num, nb_sectors, &qiov);
+    }
+
     if (bdrv_check_request(bs, sector_num, nb_sectors))
         return -EIO;
 
@@ -998,8 +1022,21 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num,
                const uint8_t *buf, int nb_sectors)
 {
     BlockDriver *drv = bs->drv;
+
     if (!bs->drv)
         return -ENOMEDIUM;
+
+    if (bdrv_has_async_rw(drv) && qemu_in_coroutine()) {
+        QEMUIOVector qiov;
+        struct iovec iov = {
+            .iov_base = (void *)buf,
+            .iov_len = nb_sectors * BDRV_SECTOR_SIZE,
+        };
+
+        qemu_iovec_init_external(&qiov, &iov, 1);
+        return bdrv_co_writev(bs, sector_num, nb_sectors, &qiov);
+    }
+
     if (bs->read_only)
         return -EACCES;
     if (bdrv_check_request(bs, sector_num, nb_sectors))
@@ -1649,6 +1686,10 @@ int bdrv_flush(BlockDriverState *bs)
         return 0;
     }
 
+    if (bs->drv && bdrv_has_async_flush(bs->drv) && qemu_in_coroutine()) {
+        return bdrv_co_flush_em(bs);
+    }
+
     if (bs->drv && bs->drv->bdrv_flush) {
         return bs->drv->bdrv_flush(bs);
     }
@@ -2916,6 +2957,21 @@ static int coroutine_fn bdrv_co_writev_em(BlockDriverState *bs,
     return bdrv_co_io_em(bs, sector_num, nb_sectors, iov, true);
 }
 
+static int coroutine_fn bdrv_co_flush_em(BlockDriverState *bs)
+{
+    CoroutineIOCompletion co = {
+        .coroutine = qemu_coroutine_self(),
+    };
+    BlockDriverAIOCB *acb;
+
+    acb = bdrv_aio_flush(bs, bdrv_co_io_em_complete, &co);
+    if (!acb) {
+        return -EIO;
+    }
+    qemu_coroutine_yield();
+    return co.ret;
+}
+
 /**************************************************************/
 /* removable device support */
 
commit a6f4e09d90cef88be07cd597c2f2a9f0b3ed0763
Author: Michael Walle <michael at walle.cc>
Date:   Thu Jul 21 20:52:24 2011 +0200

    lm32: softusb: claim to support full speed
    
    The QEMU keyboard and mouse reports themselves as full speed devices,
    though they are actually low speed devices. Until this is fixed, claim that
    we are supporting full speed devices.
    
    Acked-by: Gerd Hoffmann <kraxel at redhat.com>
    Signed-off-by: Michael Walle <michael at walle.cc>
    Signed-off-by: Edgar E. Iglesias <edgar.iglesias at gmail.com>

diff --git a/hw/milkymist-softusb.c b/hw/milkymist-softusb.c
index ce2bfc6..abf7b59 100644
--- a/hw/milkymist-softusb.c
+++ b/hw/milkymist-softusb.c
@@ -310,10 +310,12 @@ static int milkymist_softusb_init(SysBusDevice *dev)
     usb_bus_new(&s->usbbus, &softusb_bus_ops, NULL);
 
     /* our two ports */
+    /* FIXME: claim to support full speed devices. qemu mouse and keyboard
+     * report themselves as full speed devices. */
     usb_register_port(&s->usbbus, &s->usbport[0], NULL, 0, &softusb_ops,
-            USB_SPEED_MASK_LOW);
+            USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
     usb_register_port(&s->usbbus, &s->usbport[1], NULL, 1, &softusb_ops,
-            USB_SPEED_MASK_LOW);
+            USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
 
     /* and finally create an usb keyboard */
     s->usbdev = usb_create_simple(&s->usbbus, "usb-kbd");
commit cb4b4fde82b064472c13fb9d983ca36a70e560aa
Author: Michael S. Tsirkin <mst at redhat.com>
Date:   Wed Aug 3 15:24:41 2011 +0300

    vhost: remove an incorrect assert
    
    The 'to' can go negative when the first region gets removed
    (it gets incremented by to 0 immediately afterward), which
    makes the assertion fail. Nothing breaks if
    to < 0 here so just remove the assert.
    
    Tested-by: David Ahern <daahern at cisco.com>
    Signed-off-by: Michael S. Tsirkin <mst at redhat.com>

diff --git a/hw/vhost.c b/hw/vhost.c
index c3d8821..19e7255 100644
--- a/hw/vhost.c
+++ b/hw/vhost.c
@@ -120,7 +120,6 @@ static void vhost_dev_unassign_memory(struct vhost_dev *dev,
         if (start_addr <= reg->guest_phys_addr && memlast >= reglast) {
             --dev->mem->nregions;
             --to;
-            assert(to >= 0);
             ++overlap_middle;
             continue;
         }
commit 1ab74cea060d776b19857c3babc64d729bbdba5c
Author: Fabien Chouteau <chouteau at adacore.com>
Date:   Mon Aug 1 18:18:37 2011 +0200

    Delayed IP packets
    
    In the current implementation, if Slirp tries to send an IP packet to a client
    with an unknown hardware address, the packet is simply dropped and an ARP
    request is sent (if_encap in slirp/slirp.c).
    
    With this patch, Slirp will send the ARP request, re-queue the packet and try
    to send it later. The packet is dropped after one second if the ARP reply is
    not received.
    
    Signed-off-by: Fabien Chouteau <chouteau at adacore.com>
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>

diff --git a/slirp/if.c b/slirp/if.c
index 0f04e13..2d79e45 100644
--- a/slirp/if.c
+++ b/slirp/if.c
@@ -6,6 +6,7 @@
  */
 
 #include <slirp.h>
+#include "qemu-timer.h"
 
 #define ifs_init(ifm) ((ifm)->ifs_next = (ifm)->ifs_prev = (ifm))
 
@@ -105,6 +106,9 @@ if_output(struct socket *so, struct mbuf *ifm)
 	ifs_init(ifm);
 	insque(ifm, ifq);
 
+        /* Expiration date = Now + 1 second */
+        ifm->expiration_date = qemu_get_clock_ns(rt_clock) + 1000000000ULL;
+
 diddit:
 	slirp->if_queued++;
 
@@ -153,6 +157,9 @@ diddit:
 void
 if_start(Slirp *slirp)
 {
+    int requeued = 0;
+    uint64_t now;
+
 	struct mbuf *ifm, *ifqt;
 
 	DEBUG_CALL("if_start");
@@ -165,6 +172,8 @@ if_start(Slirp *slirp)
         if (!slirp_can_output(slirp->opaque))
             return;
 
+        now = qemu_get_clock_ns(rt_clock);
+
 	/*
 	 * See which queue to get next packet from
 	 * If there's something in the fastq, select it immediately
@@ -199,11 +208,22 @@ if_start(Slirp *slirp)
 		   ifm->ifq_so->so_nqueued = 0;
 	}
 
-	/* Encapsulate the packet for sending */
-        if_encap(slirp, (uint8_t *)ifm->m_data, ifm->m_len);
-
-        m_free(ifm);
+        if (ifm->expiration_date < now) {
+            /* Expired */
+            m_free(ifm);
+        } else {
+            /* Encapsulate the packet for sending */
+            if (if_encap(slirp, ifm)) {
+                m_free(ifm);
+            } else {
+                /* re-queue */
+                insque(ifm, ifqt);
+                requeued++;
+            }
+        }
 
 	if (slirp->if_queued)
 	   goto again;
+
+        slirp->if_queued = requeued;
 }
diff --git a/slirp/main.h b/slirp/main.h
index 0dd8d81..028df4b 100644
--- a/slirp/main.h
+++ b/slirp/main.h
@@ -42,5 +42,5 @@ extern int tcp_keepintvl;
 #define PROTO_PPP 0x2
 #endif
 
-void if_encap(Slirp *slirp, const uint8_t *ip_data, int ip_data_len);
+int if_encap(Slirp *slirp, struct mbuf *ifm);
 ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags);
diff --git a/slirp/mbuf.c b/slirp/mbuf.c
index ce2eb84..c699c75 100644
--- a/slirp/mbuf.c
+++ b/slirp/mbuf.c
@@ -70,6 +70,8 @@ m_get(Slirp *slirp)
 	m->m_len = 0;
         m->m_nextpkt = NULL;
         m->m_prevpkt = NULL;
+        m->arp_requested = false;
+        m->expiration_date = (uint64_t)-1;
 end_error:
 	DEBUG_ARG("m = %lx", (long )m);
 	return m;
diff --git a/slirp/mbuf.h b/slirp/mbuf.h
index b74544b..55170e5 100644
--- a/slirp/mbuf.h
+++ b/slirp/mbuf.h
@@ -86,6 +86,8 @@ struct mbuf {
 		char	m_dat_[1]; /* ANSI don't like 0 sized arrays */
 		char	*m_ext_;
 	} M_dat;
+    bool     arp_requested;
+    uint64_t expiration_date;
 };
 
 #define m_next		m_hdr.mh_next
diff --git a/slirp/slirp.c b/slirp/slirp.c
index 4a9a4d5..a86cc6e 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -692,55 +692,63 @@ void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
     }
 }
 
-/* output the IP packet to the ethernet device */
-void if_encap(Slirp *slirp, const uint8_t *ip_data, int ip_data_len)
+/* Output the IP packet to the ethernet device. Returns 0 if the packet must be
+ * re-queued.
+ */
+int if_encap(Slirp *slirp, struct mbuf *ifm)
 {
     uint8_t buf[1600];
     struct ethhdr *eh = (struct ethhdr *)buf;
     uint8_t ethaddr[ETH_ALEN];
-    const struct ip *iph = (const struct ip *)ip_data;
+    const struct ip *iph = (const struct ip *)ifm->m_data;
 
-    if (ip_data_len + ETH_HLEN > sizeof(buf))
-        return;
+    if (ifm->m_len + ETH_HLEN > sizeof(buf)) {
+        return 1;
+    }
 
     if (!arp_table_search(slirp, iph->ip_dst.s_addr, ethaddr)) {
         uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)];
         struct ethhdr *reh = (struct ethhdr *)arp_req;
         struct arphdr *rah = (struct arphdr *)(arp_req + ETH_HLEN);
 
-        /* If the client addr is not known, there is no point in
-           sending the packet to it. Normally the sender should have
-           done an ARP request to get its MAC address. Here we do it
-           in place of sending the packet and we hope that the sender
-           will retry sending its packet. */
-        memset(reh->h_dest, 0xff, ETH_ALEN);
-        memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
-        memcpy(&reh->h_source[2], &slirp->vhost_addr, 4);
-        reh->h_proto = htons(ETH_P_ARP);
-        rah->ar_hrd = htons(1);
-        rah->ar_pro = htons(ETH_P_IP);
-        rah->ar_hln = ETH_ALEN;
-        rah->ar_pln = 4;
-        rah->ar_op = htons(ARPOP_REQUEST);
-        /* source hw addr */
-        memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 4);
-        memcpy(&rah->ar_sha[2], &slirp->vhost_addr, 4);
-        /* source IP */
-        rah->ar_sip = slirp->vhost_addr.s_addr;
-        /* target hw addr (none) */
-        memset(rah->ar_tha, 0, ETH_ALEN);
-        /* target IP */
-        rah->ar_tip = iph->ip_dst.s_addr;
-        slirp->client_ipaddr = iph->ip_dst;
-        slirp_output(slirp->opaque, arp_req, sizeof(arp_req));
+        if (!ifm->arp_requested) {
+            /* If the client addr is not known, send an ARP request */
+            memset(reh->h_dest, 0xff, ETH_ALEN);
+            memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
+            memcpy(&reh->h_source[2], &slirp->vhost_addr, 4);
+            reh->h_proto = htons(ETH_P_ARP);
+            rah->ar_hrd = htons(1);
+            rah->ar_pro = htons(ETH_P_IP);
+            rah->ar_hln = ETH_ALEN;
+            rah->ar_pln = 4;
+            rah->ar_op = htons(ARPOP_REQUEST);
+
+            /* source hw addr */
+            memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 4);
+            memcpy(&rah->ar_sha[2], &slirp->vhost_addr, 4);
+
+            /* source IP */
+            rah->ar_sip = slirp->vhost_addr.s_addr;
+
+            /* target hw addr (none) */
+            memset(rah->ar_tha, 0, ETH_ALEN);
+
+            /* target IP */
+            rah->ar_tip = iph->ip_dst.s_addr;
+            slirp->client_ipaddr = iph->ip_dst;
+            slirp_output(slirp->opaque, arp_req, sizeof(arp_req));
+            ifm->arp_requested = true;
+        }
+        return 0;
     } else {
         memcpy(eh->h_dest, ethaddr, ETH_ALEN);
         memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4);
         /* XXX: not correct */
         memcpy(&eh->h_source[2], &slirp->vhost_addr, 4);
         eh->h_proto = htons(ETH_P_IP);
-        memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len);
-        slirp_output(slirp->opaque, buf, ip_data_len + ETH_HLEN);
+        memcpy(buf + sizeof(struct ethhdr), ifm->m_data, ifm->m_len);
+        slirp_output(slirp->opaque, buf, ifm->m_len + ETH_HLEN);
+        return 1;
     }
 }
 
commit 1a0ca1e1f6011a8623ec0653a1b35bbfc3f576c9
Author: Fabien Chouteau <chouteau at adacore.com>
Date:   Wed Aug 3 12:52:54 2011 +0200

    Simple ARP table
    
    This patch adds a simple ARP table in Slirp and also adds handling of
    gratuitous ARP requests.
    
    Signed-off-by: Fabien Chouteau <chouteau at adacore.com>
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>

diff --git a/Makefile.objs b/Makefile.objs
index 6991a9f..0c10557 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -151,7 +151,7 @@ common-obj-y += qemu-timer.o qemu-timer-common.o
 
 slirp-obj-y = cksum.o if.o ip_icmp.o ip_input.o ip_output.o
 slirp-obj-y += slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tcp_output.o
-slirp-obj-y += tcp_subr.o tcp_timer.o udp.o bootp.o tftp.o
+slirp-obj-y += tcp_subr.o tcp_timer.o udp.o bootp.o tftp.o arp_table.o
 common-obj-$(CONFIG_SLIRP) += $(addprefix slirp/, $(slirp-obj-y))
 
 # xen backend driver support
diff --git a/slirp/arp_table.c b/slirp/arp_table.c
new file mode 100644
index 0000000..820dee2
--- /dev/null
+++ b/slirp/arp_table.c
@@ -0,0 +1,95 @@
+/*
+ * ARP table
+ *
+ * Copyright (c) 2011 AdaCore
+ *
+ * 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 "slirp.h"
+
+void arp_table_add(Slirp *slirp, int ip_addr, uint8_t ethaddr[ETH_ALEN])
+{
+    const in_addr_t broadcast_addr =
+        ~slirp->vnetwork_mask.s_addr | slirp->vnetwork_addr.s_addr;
+    ArpTable *arptbl = &slirp->arp_table;
+    int i;
+
+    DEBUG_CALL("arp_table_add");
+    DEBUG_ARG("ip = 0x%x", ip_addr);
+    DEBUG_ARGS((dfd, " hw addr = %02x:%02x:%02x:%02x:%02x:%02x\n",
+                ethaddr[0], ethaddr[1], ethaddr[2],
+                ethaddr[3], ethaddr[4], ethaddr[5]));
+
+    /* Check 0.0.0.0/8 invalid source-only addresses */
+    assert((ip_addr & htonl(~(0xf << 28))) != 0);
+
+    if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
+        /* Do not register broadcast addresses */
+        return;
+    }
+
+    /* Search for an entry */
+    for (i = 0; i < ARP_TABLE_SIZE; i++) {
+        if (arptbl->table[i].ar_sip == ip_addr) {
+            /* Update the entry */
+            memcpy(arptbl->table[i].ar_sha, ethaddr, ETH_ALEN);
+            return;
+        }
+    }
+
+    /* No entry found, create a new one */
+    arptbl->table[arptbl->next_victim].ar_sip = ip_addr;
+    memcpy(arptbl->table[arptbl->next_victim].ar_sha,  ethaddr, ETH_ALEN);
+    arptbl->next_victim = (arptbl->next_victim + 1) % ARP_TABLE_SIZE;
+}
+
+bool arp_table_search(Slirp *slirp, int in_ip_addr,
+                      uint8_t out_ethaddr[ETH_ALEN])
+{
+    const in_addr_t broadcast_addr =
+        ~slirp->vnetwork_mask.s_addr | slirp->vnetwork_addr.s_addr;
+    ArpTable *arptbl = &slirp->arp_table;
+    int i;
+
+    DEBUG_CALL("arp_table_search");
+    DEBUG_ARG("ip = 0x%x", in_ip_addr);
+
+    /* Check 0.0.0.0/8 invalid source-only addresses */
+    assert((in_ip_addr & htonl(~(0xf << 28))) != 0);
+
+    /* If broadcast address */
+    if (in_ip_addr == 0xffffffff || in_ip_addr == broadcast_addr) {
+        /* return Ethernet broadcast address */
+        memset(out_ethaddr, 0xff, ETH_ALEN);
+        return 1;
+    }
+
+    for (i = 0; i < ARP_TABLE_SIZE; i++) {
+        if (arptbl->table[i].ar_sip == in_ip_addr) {
+            memcpy(out_ethaddr, arptbl->table[i].ar_sha,  ETH_ALEN);
+            DEBUG_ARGS((dfd, " found hw addr = %02x:%02x:%02x:%02x:%02x:%02x\n",
+                        out_ethaddr[0], out_ethaddr[1], out_ethaddr[2],
+                        out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]));
+            return 1;
+        }
+    }
+
+    return 0;
+}
diff --git a/slirp/bootp.c b/slirp/bootp.c
index 1eb2ed1..efd1fe7 100644
--- a/slirp/bootp.c
+++ b/slirp/bootp.c
@@ -149,6 +149,7 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
     struct in_addr preq_addr;
     int dhcp_msg_type, val;
     uint8_t *q;
+    uint8_t client_ethaddr[ETH_ALEN];
 
     /* extract exact DHCP msg type */
     dhcp_decode(bp, &dhcp_msg_type, &preq_addr);
@@ -164,8 +165,9 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
     if (dhcp_msg_type != DHCPDISCOVER &&
         dhcp_msg_type != DHCPREQUEST)
         return;
-    /* XXX: this is a hack to get the client mac address */
-    memcpy(slirp->client_ethaddr, bp->bp_hwaddr, 6);
+
+    /* Get client's hardware address from bootp request */
+    memcpy(client_ethaddr, bp->bp_hwaddr, ETH_ALEN);
 
     m = m_get(slirp);
     if (!m) {
@@ -178,25 +180,25 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
 
     if (dhcp_msg_type == DHCPDISCOVER) {
         if (preq_addr.s_addr != htonl(0L)) {
-            bc = request_addr(slirp, &preq_addr, slirp->client_ethaddr);
+            bc = request_addr(slirp, &preq_addr, client_ethaddr);
             if (bc) {
                 daddr.sin_addr = preq_addr;
             }
         }
         if (!bc) {
          new_addr:
-            bc = get_new_addr(slirp, &daddr.sin_addr, slirp->client_ethaddr);
+            bc = get_new_addr(slirp, &daddr.sin_addr, client_ethaddr);
             if (!bc) {
                 DPRINTF("no address left\n");
                 return;
             }
         }
-        memcpy(bc->macaddr, slirp->client_ethaddr, 6);
+        memcpy(bc->macaddr, client_ethaddr, ETH_ALEN);
     } else if (preq_addr.s_addr != htonl(0L)) {
-        bc = request_addr(slirp, &preq_addr, slirp->client_ethaddr);
+        bc = request_addr(slirp, &preq_addr, client_ethaddr);
         if (bc) {
             daddr.sin_addr = preq_addr;
-            memcpy(bc->macaddr, slirp->client_ethaddr, 6);
+            memcpy(bc->macaddr, client_ethaddr, ETH_ALEN);
         } else {
             daddr.sin_addr.s_addr = 0;
         }
@@ -209,6 +211,9 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
         }
     }
 
+    /* Update ARP table for this IP address */
+    arp_table_add(slirp, daddr.sin_addr.s_addr, client_ethaddr);
+
     saddr.sin_addr = slirp->vhost_addr;
     saddr.sin_port = htons(BOOTP_SERVER);
 
@@ -218,7 +223,7 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
     rbp->bp_xid = bp->bp_xid;
     rbp->bp_htype = 1;
     rbp->bp_hlen = 6;
-    memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, 6);
+    memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, ETH_ALEN);
 
     rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */
     rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */
diff --git a/slirp/slirp.c b/slirp/slirp.c
index df787ea..4a9a4d5 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -31,11 +31,11 @@
 struct in_addr loopback_addr;
 
 /* emulated hosts use the MAC addr 52:55:IP:IP:IP:IP */
-static const uint8_t special_ethaddr[6] = {
+static const uint8_t special_ethaddr[ETH_ALEN] = {
     0x52, 0x55, 0x00, 0x00, 0x00, 0x00
 };
 
-static const uint8_t zero_ethaddr[6] = { 0, 0, 0, 0, 0, 0 };
+static const uint8_t zero_ethaddr[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
 
 /* XXX: suppress those select globals */
 fd_set *global_readfds, *global_writefds, *global_xfds;
@@ -599,42 +599,8 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
 	 global_xfds = NULL;
 }
 
-#define ETH_ALEN 6
-#define ETH_HLEN 14
-
-#define ETH_P_IP	0x0800		/* Internet Protocol packet	*/
-#define ETH_P_ARP	0x0806		/* Address Resolution packet	*/
-
-#define	ARPOP_REQUEST	1		/* ARP request			*/
-#define	ARPOP_REPLY	2		/* ARP reply			*/
-
-struct ethhdr
-{
-	unsigned char	h_dest[ETH_ALEN];	/* destination eth addr	*/
-	unsigned char	h_source[ETH_ALEN];	/* source ether addr	*/
-	unsigned short	h_proto;		/* packet type ID field	*/
-};
-
-struct arphdr
-{
-	unsigned short	ar_hrd;		/* format of hardware address	*/
-	unsigned short	ar_pro;		/* format of protocol address	*/
-	unsigned char	ar_hln;		/* length of hardware address	*/
-	unsigned char	ar_pln;		/* length of protocol address	*/
-	unsigned short	ar_op;		/* ARP opcode (command)		*/
-
-	 /*
-	  *	 Ethernet looks like this : This bit is variable sized however...
-	  */
-	unsigned char		ar_sha[ETH_ALEN];	/* sender hardware address	*/
-	uint32_t		ar_sip;			/* sender IP address		*/
-	unsigned char		ar_tha[ETH_ALEN];	/* target hardware address	*/
-	uint32_t		ar_tip	;		/* target IP address		*/
-} __attribute__((packed));
-
 static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
 {
-    struct ethhdr *eh = (struct ethhdr *)pkt;
     struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN);
     uint8_t arp_reply[max(ETH_HLEN + sizeof(struct arphdr), 64)];
     struct ethhdr *reh = (struct ethhdr *)arp_reply;
@@ -645,6 +611,12 @@ static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
     ar_op = ntohs(ah->ar_op);
     switch(ar_op) {
     case ARPOP_REQUEST:
+        if (ah->ar_tip == ah->ar_sip) {
+            /* Gratuitous ARP */
+            arp_table_add(slirp, ah->ar_sip, ah->ar_sha);
+            return;
+        }
+
         if ((ah->ar_tip & slirp->vnetwork_mask.s_addr) ==
             slirp->vnetwork_addr.s_addr) {
             if (ah->ar_tip == slirp->vnameserver_addr.s_addr ||
@@ -657,8 +629,8 @@ static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
             return;
         arp_ok:
             memset(arp_reply, 0, sizeof(arp_reply));
-            /* XXX: make an ARP request to have the client address */
-            memcpy(slirp->client_ethaddr, eh->h_source, ETH_ALEN);
+
+            arp_table_add(slirp, ah->ar_sip, ah->ar_sha);
 
             /* ARP request for alias/dns mac address */
             memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN);
@@ -679,11 +651,7 @@ static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
         }
         break;
     case ARPOP_REPLY:
-        /* reply to request of client mac address ? */
-        if (!memcmp(slirp->client_ethaddr, zero_ethaddr, ETH_ALEN) &&
-            ah->ar_sip == slirp->client_ipaddr.s_addr) {
-            memcpy(slirp->client_ethaddr, ah->ar_sha, ETH_ALEN);
-        }
+        arp_table_add(slirp, ah->ar_sip, ah->ar_sha);
         break;
     default:
         break;
@@ -729,15 +697,16 @@ void if_encap(Slirp *slirp, const uint8_t *ip_data, int ip_data_len)
 {
     uint8_t buf[1600];
     struct ethhdr *eh = (struct ethhdr *)buf;
+    uint8_t ethaddr[ETH_ALEN];
+    const struct ip *iph = (const struct ip *)ip_data;
 
     if (ip_data_len + ETH_HLEN > sizeof(buf))
         return;
-    
-    if (!memcmp(slirp->client_ethaddr, zero_ethaddr, ETH_ALEN)) {
+
+    if (!arp_table_search(slirp, iph->ip_dst.s_addr, ethaddr)) {
         uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)];
         struct ethhdr *reh = (struct ethhdr *)arp_req;
         struct arphdr *rah = (struct arphdr *)(arp_req + ETH_HLEN);
-        const struct ip *iph = (const struct ip *)ip_data;
 
         /* If the client addr is not known, there is no point in
            sending the packet to it. Normally the sender should have
@@ -765,7 +734,7 @@ void if_encap(Slirp *slirp, const uint8_t *ip_data, int ip_data_len)
         slirp->client_ipaddr = iph->ip_dst;
         slirp_output(slirp->opaque, arp_req, sizeof(arp_req));
     } else {
-        memcpy(eh->h_dest, slirp->client_ethaddr, ETH_ALEN);
+        memcpy(eh->h_dest, ethaddr, ETH_ALEN);
         memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4);
         /* XXX: not correct */
         memcpy(&eh->h_source[2], &slirp->vhost_addr, 4);
diff --git a/slirp/slirp.h b/slirp/slirp.h
index 16bb6ba..2a070e6 100644
--- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -170,6 +170,48 @@ int inet_aton(const char *cp, struct in_addr *ia);
 /* osdep.c */
 int qemu_socket(int domain, int type, int protocol);
 
+#define ETH_ALEN 6
+#define ETH_HLEN 14
+
+#define ETH_P_IP  0x0800        /* Internet Protocol packet  */
+#define ETH_P_ARP 0x0806        /* Address Resolution packet */
+
+#define ARPOP_REQUEST 1         /* ARP request */
+#define ARPOP_REPLY   2         /* ARP reply   */
+
+struct ethhdr {
+    unsigned char  h_dest[ETH_ALEN];   /* destination eth addr */
+    unsigned char  h_source[ETH_ALEN]; /* source ether addr    */
+    unsigned short h_proto;            /* packet type ID field */
+};
+
+struct arphdr {
+    unsigned short ar_hrd;      /* format of hardware address */
+    unsigned short ar_pro;      /* format of protocol address */
+    unsigned char  ar_hln;      /* length of hardware address */
+    unsigned char  ar_pln;      /* length of protocol address */
+    unsigned short ar_op;       /* ARP opcode (command)       */
+
+    /*
+     *  Ethernet looks like this : This bit is variable sized however...
+     */
+    unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */
+    uint32_t      ar_sip;           /* sender IP address       */
+    unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
+    uint32_t      ar_tip;           /* target IP address       */
+} __attribute__((packed));
+
+#define ARP_TABLE_SIZE 16
+
+typedef struct ArpTable {
+    struct arphdr table[ARP_TABLE_SIZE];
+    int next_victim;
+} ArpTable;
+
+void arp_table_add(Slirp *slirp, int ip_addr, uint8_t ethaddr[ETH_ALEN]);
+
+bool arp_table_search(Slirp *slirp, int in_ip_addr,
+                      uint8_t out_ethaddr[ETH_ALEN]);
 
 struct Slirp {
     QTAILQ_ENTRY(Slirp) entry;
@@ -181,9 +223,6 @@ struct Slirp {
     struct in_addr vdhcp_startaddr;
     struct in_addr vnameserver_addr;
 
-    /* ARP cache for the guest IP addresses (XXX: allow many entries) */
-    uint8_t client_ethaddr[6];
-
     struct in_addr client_ipaddr;
     char client_hostname[33];
 
@@ -227,6 +266,8 @@ struct Slirp {
     char *tftp_prefix;
     struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX];
 
+    ArpTable arp_table;
+
     void *opaque;
 };
 
commit 793553acb3d70ae64e459fa067486c6c741133e7
Author: Alexandre Raymond <cerbere at gmail.com>
Date:   Mon Jul 25 23:56:02 2011 -0400

    Makefile: delete config.log in distclean
    
    Distclean should remove anything created by the configure script.
    
    Signed-off-by: Alexandre Raymond <cerbere at gmail.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/Makefile b/Makefile
index 4855251..a0218a3 100644
--- a/Makefile
+++ b/Makefile
@@ -226,6 +226,7 @@ distclean: clean
 	rm -f qemu-doc.fn qemu-doc.fns qemu-doc.info qemu-doc.ky qemu-doc.kys
 	rm -f qemu-doc.log qemu-doc.pdf qemu-doc.pg qemu-doc.toc qemu-doc.tp
 	rm -f qemu-doc.vr
+	rm -f config.log
 	rm -f qemu-tech.info qemu-tech.aux qemu-tech.cp qemu-tech.dvi qemu-tech.fn qemu-tech.info qemu-tech.ky qemu-tech.log qemu-tech.pdf qemu-tech.pg qemu-tech.toc qemu-tech.tp qemu-tech.vr
 	for d in $(TARGET_DIRS) $(QEMULIBS); do \
 	rm -rf $$d || exit 1 ; \
commit 0f1b583ee7db23cb31f68a9d9b55755ca95f9f3f
Author: Zhi Yong Wu <wuzhy at linux.vnet.ibm.com>
Date:   Wed Jul 27 17:48:16 2011 +0800

    HMP: Remove the duplicated info "info kvm" in hmp-commands.hx.
    
    Signed-off-by: Zhi Yong Wu <wuzhy at linux.vnet.ibm.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/hmp-commands.hx b/hmp-commands.hx
index c857827..0ccfb28 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1311,8 +1311,6 @@ show virtual to physical memory mappings (i386, SH4 and SPARC only)
 show the active virtual memory mappings (i386 only)
 @item info jit
 show dynamic compiler info
- at item info kvm
-show KVM information
 @item info numa
 show NUMA information
 @item info kvm
commit d41a75a20f2e8f9ccc64c27b61f730e4cb4ee2c5
Author: Brad <brad at comstyle.com>
Date:   Tue Jul 26 23:11:26 2011 -0400

    configure: display "no" for disabled kvm/vhost-net
    
    Fix configure display for non-Linux OS's and the KVM /
    vhost-net features to show "no" output instead of nothing
    at the end of the line.
    
    Signed-off-by: Brad Smith <brad at comstyle.com>
    Acked-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/configure b/configure
index 77194cf..9d46780 100755
--- a/configure
+++ b/configure
@@ -113,7 +113,6 @@ curl=""
 curses=""
 docs=""
 fdt=""
-kvm=""
 nptl=""
 sdl=""
 vnc="yes"
@@ -129,9 +128,10 @@ xen=""
 xen_ctrl_version=""
 linux_aio=""
 attr=""
-vhost_net=""
 xfs=""
 
+vhost_net="no"
+kvm="no"
 gprof="no"
 debug_tcg="no"
 debug_mon="no"
commit 9197a7c8af41c2a410d5debcf20deabbc20243c0
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Jul 20 12:21:00 2011 +0300

    qxl: bump pci rev
    
    Inform guest drivers about the new features I/O commands we have
    now (async commands, S3 support) if building with newer spice, i.e.
    if SPICE_INTERFACE_QXL_MINOR >= 1.
    
    sneaked in some 81+ column line spliting.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
    Signed-off-by: Alon Levy <alevy at redhat.com>

diff --git a/hw/qxl.c b/hw/qxl.c
index 847a9b8..b684608 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -1566,9 +1566,14 @@ static int qxl_init_common(PCIQXLDevice *qxl)
         pci_device_rev = QXL_REVISION_STABLE_V04;
         break;
     case 2: /* spice 0.6 -- qxl-2 */
-    default:
         pci_device_rev = QXL_REVISION_STABLE_V06;
         break;
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+    case 3: /* qxl-3 */
+#endif
+    default:
+        pci_device_rev = QXL_DEFAULT_REVISION;
+        break;
     }
 
     pci_set_byte(&config[PCI_REVISION_ID], pci_device_rev);
@@ -1830,9 +1835,12 @@ static PCIDeviceInfo qxl_info_primary = {
     .device_id    = QXL_DEVICE_ID_STABLE,
     .class_id     = PCI_CLASS_DISPLAY_VGA,
     .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 64 * 1024 * 1024),
-        DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size, 64 * 1024 * 1024),
-        DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, 2),
+        DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size,
+                           64 * 1024 * 1024),
+        DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size,
+                           64 * 1024 * 1024),
+        DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision,
+                           QXL_DEFAULT_REVISION),
         DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0),
         DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0),
         DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0),
@@ -1851,9 +1859,12 @@ static PCIDeviceInfo qxl_info_secondary = {
     .device_id    = QXL_DEVICE_ID_STABLE,
     .class_id     = PCI_CLASS_DISPLAY_OTHER,
     .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 64 * 1024 * 1024),
-        DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size, 64 * 1024 * 1024),
-        DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, 2),
+        DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size,
+                           64 * 1024 * 1024),
+        DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size,
+                           64 * 1024 * 1024),
+        DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision,
+                           QXL_DEFAULT_REVISION),
         DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0),
         DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0),
         DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0),
diff --git a/hw/qxl.h b/hw/qxl.h
index 1046205..4bcf7e1 100644
--- a/hw/qxl.h
+++ b/hw/qxl.h
@@ -102,6 +102,12 @@ typedef struct PCIQXLDevice {
         }                                                               \
     } while (0)
 
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V10
+#else
+#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V06
+#endif
+
 /* qxl.c */
 void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
 void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...);
commit 3e16b9c53493d6107c5a1ec810ace2447fcb11eb
Author: Alon Levy <alevy at redhat.com>
Date:   Wed Jul 20 12:20:59 2011 +0300

    qxl: add QXL_IO_FLUSH_{SURFACES,RELEASE} for guest S3&S4 support
    
    Add two new IOs.
     QXL_IO_FLUSH_SURFACES - equivalent to update area for all surfaces, used
      to reduce vmexits from NumSurfaces to 1 on guest S3, S4 and resolution change (windows
      driver implementation is such that this is done on each of those occasions).
     QXL_IO_FLUSH_RELEASE - used to ensure anything on last_release is put on the release ring
      for the client to free.
    
    Signed-off-by: Yonit Halperin <yhalperi at redhat.com>
    Signed-off-by: Alon Levy <alevy at redhat.com>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/qxl.c b/hw/qxl.c
index d3109e4..847a9b8 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -185,6 +185,13 @@ static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id,
     }
 }
 
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+static void qxl_spice_flush_surfaces_async(PCIQXLDevice *qxl)
+{
+    spice_qxl_flush_surfaces_async(&qxl->ssd.qxl, 0);
+}
+#endif
+
 void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
                                uint32_t count)
 {
@@ -1184,6 +1191,8 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
         goto async_common;
     case QXL_IO_DESTROY_ALL_SURFACES_ASYNC:
         io_port = QXL_IO_DESTROY_ALL_SURFACES;
+        goto async_common;
+    case QXL_IO_FLUSH_SURFACES_ASYNC:
 async_common:
         async = QXL_ASYNC;
         qemu_mutex_lock(&d->async_lock);
@@ -1296,6 +1305,27 @@ async_common:
         }
         qxl_spice_destroy_surface_wait(d, val, async);
         break;
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+    case QXL_IO_FLUSH_RELEASE: {
+        QXLReleaseRing *ring = &d->ram->release_ring;
+        if (ring->prod - ring->cons + 1 == ring->num_items) {
+            fprintf(stderr,
+                "ERROR: no flush, full release ring [p%d,%dc]\n",
+                ring->prod, ring->cons);
+        }
+        qxl_push_free_res(d, 1 /* flush */);
+        dprint(d, 1, "QXL_IO_FLUSH_RELEASE exit (%s, s#=%d, res#=%d,%p)\n",
+            qxl_mode_to_string(d->mode), d->guest_surfaces.count,
+            d->num_free_res, d->last_release);
+        break;
+    }
+    case QXL_IO_FLUSH_SURFACES_ASYNC:
+        dprint(d, 1, "QXL_IO_FLUSH_SURFACES_ASYNC (%d) (%s, s#=%d, res#=%d)\n",
+               val, qxl_mode_to_string(d->mode), d->guest_surfaces.count,
+               d->num_free_res);
+        qxl_spice_flush_surfaces_async(d);
+        break;
+#endif
     case QXL_IO_DESTROY_ALL_SURFACES:
         d->mode = QXL_MODE_UNDEFINED;
         qxl_spice_destroy_surfaces(d, async);
commit 5ff4e36c804157bd84af43c139f8cd3a59722db9
Author: Alon Levy <alevy at redhat.com>
Date:   Wed Jul 20 12:20:58 2011 +0300

    qxl: async io support using new spice api
    
    Some of the QXL port i/o commands are waiting for the spice server to
    complete certain actions.  Add async versions for these commands, so we
    don't block the vcpu while the spice server processses the command.
    Instead the qxl device will raise an IRQ when done.
    
    The async command processing relies on an added QXLInterface::async_complete
    and added QXLWorker::*_async additions, in spice server qxl >= 3.1
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
    Signed-off-by: Alon Levy     <alevy at redhat.com>

diff --git a/hw/qxl-render.c b/hw/qxl-render.c
index 60b822d..643ff2d 100644
--- a/hw/qxl-render.c
+++ b/hw/qxl-render.c
@@ -125,7 +125,7 @@ void qxl_render_update(PCIQXLDevice *qxl)
 
     memset(dirty, 0, sizeof(dirty));
     qxl_spice_update_area(qxl, 0, &update,
-                          dirty, ARRAY_SIZE(dirty), 1);
+                          dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC);
 
     for (i = 0; i < ARRAY_SIZE(dirty); i++) {
         if (qemu_spice_rect_is_empty(dirty+i)) {
diff --git a/hw/qxl.c b/hw/qxl.c
index 23e3240..d3109e4 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -120,7 +120,7 @@ static QXLMode qxl_modes[] = {
 static PCIQXLDevice *qxl0;
 
 static void qxl_send_events(PCIQXLDevice *d, uint32_t events);
-static void qxl_destroy_primary(PCIQXLDevice *d);
+static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async);
 static void qxl_reset_memslots(PCIQXLDevice *d);
 static void qxl_reset_surfaces(PCIQXLDevice *d);
 static void qxl_ring_set_dirty(PCIQXLDevice *qxl);
@@ -144,22 +144,47 @@ void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...)
 void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
                            struct QXLRect *area, struct QXLRect *dirty_rects,
                            uint32_t num_dirty_rects,
-                           uint32_t clear_dirty_region)
+                           uint32_t clear_dirty_region,
+                           qxl_async_io async)
 {
-    qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area, dirty_rects,
-                             num_dirty_rects, clear_dirty_region);
+    if (async == QXL_SYNC) {
+        qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area,
+                        dirty_rects, num_dirty_rects, clear_dirty_region);
+    } else {
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+        spice_qxl_update_area_async(&qxl->ssd.qxl, surface_id, area,
+                                    clear_dirty_region, 0);
+#else
+        abort();
+#endif
+    }
 }
 
-void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id)
+static void qxl_spice_destroy_surface_wait_complete(PCIQXLDevice *qxl,
+                                                    uint32_t id)
 {
     qemu_mutex_lock(&qxl->track_lock);
-    PANIC_ON(id >= NUM_SURFACES);
-    qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id);
     qxl->guest_surfaces.cmds[id] = 0;
     qxl->guest_surfaces.count--;
     qemu_mutex_unlock(&qxl->track_lock);
 }
 
+static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id,
+                                           qxl_async_io async)
+{
+    if (async) {
+#if SPICE_INTERFACE_QXL_MINOR < 1
+        abort();
+#else
+        spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id,
+                                        (uint64_t)id);
+#endif
+    } else {
+        qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id);
+        qxl_spice_destroy_surface_wait_complete(qxl, id);
+    }
+}
+
 void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
                                uint32_t count)
 {
@@ -176,15 +201,28 @@ void qxl_spice_reset_memslots(PCIQXLDevice *qxl)
     qxl->ssd.worker->reset_memslots(qxl->ssd.worker);
 }
 
-void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl)
+static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl)
 {
     qemu_mutex_lock(&qxl->track_lock);
-    qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker);
     memset(&qxl->guest_surfaces.cmds, 0, sizeof(qxl->guest_surfaces.cmds));
     qxl->guest_surfaces.count = 0;
     qemu_mutex_unlock(&qxl->track_lock);
 }
 
+static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async)
+{
+    if (async) {
+#if SPICE_INTERFACE_QXL_MINOR < 1
+        abort();
+#else
+        spice_qxl_destroy_surfaces_async(&qxl->ssd.qxl, 0);
+#endif
+    } else {
+        qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker);
+        qxl_spice_destroy_surfaces_complete(qxl);
+    }
+}
+
 void qxl_spice_reset_image_cache(PCIQXLDevice *qxl)
 {
     qxl->ssd.worker->reset_image_cache(qxl->ssd.worker);
@@ -689,6 +727,38 @@ static int interface_flush_resources(QXLInstance *sin)
     return ret;
 }
 
+static void qxl_create_guest_primary_complete(PCIQXLDevice *d);
+
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+
+/* called from spice server thread context only */
+static void interface_async_complete(QXLInstance *sin, uint64_t cookie)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    uint32_t current_async;
+
+    qemu_mutex_lock(&qxl->async_lock);
+    current_async = qxl->current_async;
+    qxl->current_async = QXL_UNDEFINED_IO;
+    qemu_mutex_unlock(&qxl->async_lock);
+
+    dprint(qxl, 2, "async_complete: %d (%ld) done\n", current_async, cookie);
+    switch (current_async) {
+    case QXL_IO_CREATE_PRIMARY_ASYNC:
+        qxl_create_guest_primary_complete(qxl);
+        break;
+    case QXL_IO_DESTROY_ALL_SURFACES_ASYNC:
+        qxl_spice_destroy_surfaces_complete(qxl);
+        break;
+    case QXL_IO_DESTROY_SURFACE_ASYNC:
+        qxl_spice_destroy_surface_wait_complete(qxl, (uint32_t)cookie);
+        break;
+    }
+    qxl_send_events(qxl, QXL_INTERRUPT_IO_CMD);
+}
+
+#endif
+
 static const QXLInterface qxl_interface = {
     .base.type               = SPICE_INTERFACE_QXL,
     .base.description        = "qxl gpu",
@@ -708,6 +778,9 @@ static const QXLInterface qxl_interface = {
     .req_cursor_notification = interface_req_cursor_notification,
     .notify_update           = interface_notify_update,
     .flush_resources         = interface_flush_resources,
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+    .async_complete          = interface_async_complete,
+#endif
 };
 
 static void qxl_enter_vga_mode(PCIQXLDevice *d)
@@ -727,7 +800,7 @@ static void qxl_exit_vga_mode(PCIQXLDevice *d)
         return;
     }
     dprint(d, 1, "%s\n", __FUNCTION__);
-    qxl_destroy_primary(d);
+    qxl_destroy_primary(d, QXL_SYNC);
 }
 
 static void qxl_set_irq(PCIQXLDevice *d)
@@ -824,13 +897,14 @@ static void qxl_vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 
     if (qxl->mode != QXL_MODE_VGA) {
         dprint(qxl, 1, "%s\n", __FUNCTION__);
-        qxl_destroy_primary(qxl);
+        qxl_destroy_primary(qxl, QXL_SYNC);
         qxl_soft_reset(qxl);
     }
     vga_ioport_write(opaque, addr, val);
 }
 
-static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta)
+static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta,
+                            qxl_async_io async)
 {
     static const int regions[] = {
         QXL_RAM_RANGE_INDEX,
@@ -900,7 +974,7 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta)
            __FUNCTION__, memslot.slot_id,
            memslot.virt_start, memslot.virt_end);
 
-    qemu_spice_add_memslot(&d->ssd, &memslot);
+    qemu_spice_add_memslot(&d->ssd, &memslot, async);
     d->guest_slots[slot_id].ptr = (void*)memslot.virt_start;
     d->guest_slots[slot_id].size = memslot.virt_end - memslot.virt_start;
     d->guest_slots[slot_id].delta = delta;
@@ -925,7 +999,7 @@ static void qxl_reset_surfaces(PCIQXLDevice *d)
 {
     dprint(d, 1, "%s:\n", __FUNCTION__);
     d->mode = QXL_MODE_UNDEFINED;
-    qxl_spice_destroy_surfaces(d);
+    qxl_spice_destroy_surfaces(d, QXL_SYNC);
 }
 
 /* called from spice server thread context only */
@@ -950,7 +1024,14 @@ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id)
     }
 }
 
-static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm)
+static void qxl_create_guest_primary_complete(PCIQXLDevice *qxl)
+{
+    /* for local rendering */
+    qxl_render_resize(qxl);
+}
+
+static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm,
+                                     qxl_async_io async)
 {
     QXLDevSurfaceCreate surface;
     QXLSurfaceCreate *sc = &qxl->guest_primary.surface;
@@ -978,22 +1059,26 @@ static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm)
 
     qxl->mode = QXL_MODE_NATIVE;
     qxl->cmdflags = 0;
-    qemu_spice_create_primary_surface(&qxl->ssd, 0, &surface);
+    qemu_spice_create_primary_surface(&qxl->ssd, 0, &surface, async);
 
-    /* for local rendering */
-    qxl_render_resize(qxl);
+    if (async == QXL_SYNC) {
+        qxl_create_guest_primary_complete(qxl);
+    }
 }
 
-static void qxl_destroy_primary(PCIQXLDevice *d)
+/* return 1 if surface destoy was initiated (in QXL_ASYNC case) or
+ * done (in QXL_SYNC case), 0 otherwise. */
+static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async)
 {
     if (d->mode == QXL_MODE_UNDEFINED) {
-        return;
+        return 0;
     }
 
     dprint(d, 1, "%s\n", __FUNCTION__);
 
     d->mode = QXL_MODE_UNDEFINED;
-    qemu_spice_destroy_primary_surface(&d->ssd, 0);
+    qemu_spice_destroy_primary_surface(&d->ssd, 0, async);
+    return 1;
 }
 
 static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm)
@@ -1023,10 +1108,10 @@ static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm)
     }
 
     d->guest_slots[0].slot = slot;
-    qxl_add_memslot(d, 0, devmem);
+    qxl_add_memslot(d, 0, devmem, QXL_SYNC);
 
     d->guest_primary.surface = surface;
-    qxl_create_guest_primary(d, 0);
+    qxl_create_guest_primary(d, 0, QXL_SYNC);
 
     d->mode = QXL_MODE_COMPAT;
     d->cmdflags = QXL_COMMAND_FLAG_COMPAT;
@@ -1044,6 +1129,10 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
 {
     PCIQXLDevice *d = opaque;
     uint32_t io_port = addr - d->io_base;
+    qxl_async_io async = QXL_SYNC;
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+    uint32_t orig_io_port = io_port;
+#endif
 
     switch (io_port) {
     case QXL_IO_RESET:
@@ -1053,6 +1142,10 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
     case QXL_IO_CREATE_PRIMARY:
     case QXL_IO_UPDATE_IRQ:
     case QXL_IO_LOG:
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+    case QXL_IO_MEMSLOT_ADD_ASYNC:
+    case QXL_IO_CREATE_PRIMARY_ASYNC:
+#endif
         break;
     default:
         if (d->mode != QXL_MODE_VGA) {
@@ -1060,15 +1153,61 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
         }
         dprint(d, 1, "%s: unexpected port 0x%x (%s) in vga mode\n",
             __func__, io_port, io_port_to_string(io_port));
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+        /* be nice to buggy guest drivers */
+        if (io_port >= QXL_IO_UPDATE_AREA_ASYNC &&
+            io_port <= QXL_IO_DESTROY_ALL_SURFACES_ASYNC) {
+            qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
+        }
+#endif
         return;
     }
 
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+    /* we change the io_port to avoid ifdeffery in the main switch */
+    orig_io_port = io_port;
+    switch (io_port) {
+    case QXL_IO_UPDATE_AREA_ASYNC:
+        io_port = QXL_IO_UPDATE_AREA;
+        goto async_common;
+    case QXL_IO_MEMSLOT_ADD_ASYNC:
+        io_port = QXL_IO_MEMSLOT_ADD;
+        goto async_common;
+    case QXL_IO_CREATE_PRIMARY_ASYNC:
+        io_port = QXL_IO_CREATE_PRIMARY;
+        goto async_common;
+    case QXL_IO_DESTROY_PRIMARY_ASYNC:
+        io_port = QXL_IO_DESTROY_PRIMARY;
+        goto async_common;
+    case QXL_IO_DESTROY_SURFACE_ASYNC:
+        io_port = QXL_IO_DESTROY_SURFACE_WAIT;
+        goto async_common;
+    case QXL_IO_DESTROY_ALL_SURFACES_ASYNC:
+        io_port = QXL_IO_DESTROY_ALL_SURFACES;
+async_common:
+        async = QXL_ASYNC;
+        qemu_mutex_lock(&d->async_lock);
+        if (d->current_async != QXL_UNDEFINED_IO) {
+            qxl_guest_bug(d, "%d async started before last (%d) complete",
+                io_port, d->current_async);
+            qemu_mutex_unlock(&d->async_lock);
+            return;
+        }
+        d->current_async = orig_io_port;
+        qemu_mutex_unlock(&d->async_lock);
+        dprint(d, 2, "start async %d (%d)\n", io_port, val);
+        break;
+    default:
+        break;
+    }
+#endif
+
     switch (io_port) {
     case QXL_IO_UPDATE_AREA:
     {
         QXLRect update = d->ram->update_area;
         qxl_spice_update_area(d, d->ram->update_surface,
-                              &update, NULL, 0, 0);
+                              &update, NULL, 0, 0, async);
         break;
     }
     case QXL_IO_NOTIFY_CMD:
@@ -1116,7 +1255,7 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
             break;
         }
         d->guest_slots[val].slot = d->ram->mem_slot;
-        qxl_add_memslot(d, val, 0);
+        qxl_add_memslot(d, val, 0, async);
         break;
     case QXL_IO_MEMSLOT_DEL:
         if (val >= NUM_MEMSLOTS) {
@@ -1127,31 +1266,56 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
         break;
     case QXL_IO_CREATE_PRIMARY:
         if (val != 0) {
-            qxl_guest_bug(d, "QXL_IO_CREATE_PRIMARY: val != 0");
-            break;
+            qxl_guest_bug(d, "QXL_IO_CREATE_PRIMARY (async=%d): val != 0",
+                          async);
+            goto cancel_async;
         }
-        dprint(d, 1, "QXL_IO_CREATE_PRIMARY\n");
+        dprint(d, 1, "QXL_IO_CREATE_PRIMARY async=%d\n", async);
         d->guest_primary.surface = d->ram->create_surface;
-        qxl_create_guest_primary(d, 0);
+        qxl_create_guest_primary(d, 0, async);
         break;
     case QXL_IO_DESTROY_PRIMARY:
         if (val != 0) {
-            qxl_guest_bug(d, "QXL_IO_DESTROY_PRIMARY: val != 0");
-            break;
+            qxl_guest_bug(d, "QXL_IO_DESTROY_PRIMARY (async=%d): val != 0",
+                          async);
+            goto cancel_async;
+        }
+        dprint(d, 1, "QXL_IO_DESTROY_PRIMARY (async=%d) (%s)\n", async,
+               qxl_mode_to_string(d->mode));
+        if (!qxl_destroy_primary(d, async)) {
+            dprint(d, 1, "QXL_IO_DESTROY_PRIMARY_ASYNC in %s, ignored\n",
+                    qxl_mode_to_string(d->mode));
+            goto cancel_async;
         }
-        dprint(d, 1, "QXL_IO_DESTROY_PRIMARY (%s)\n", qxl_mode_to_string(d->mode));
-        qxl_destroy_primary(d);
         break;
     case QXL_IO_DESTROY_SURFACE_WAIT:
-        qxl_spice_destroy_surface_wait(d, val);
+        if (val >= NUM_SURFACES) {
+            qxl_guest_bug(d, "QXL_IO_DESTROY_SURFACE (async=%d):"
+                             "%d >= NUM_SURFACES", async, val);
+            goto cancel_async;
+        }
+        qxl_spice_destroy_surface_wait(d, val, async);
         break;
     case QXL_IO_DESTROY_ALL_SURFACES:
-        qxl_spice_destroy_surfaces(d);
+        d->mode = QXL_MODE_UNDEFINED;
+        qxl_spice_destroy_surfaces(d, async);
         break;
     default:
         fprintf(stderr, "%s: ioport=0x%x, abort()\n", __FUNCTION__, io_port);
         abort();
     }
+    return;
+cancel_async:
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+    if (async) {
+        qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
+        qemu_mutex_lock(&d->async_lock);
+        d->current_async = QXL_UNDEFINED_IO;
+        qemu_mutex_unlock(&d->async_lock);
+    }
+#else
+    return;
+#endif
 }
 
 static uint32_t ioport_read(void *opaque, uint32_t addr)
@@ -1364,6 +1528,8 @@ static int qxl_init_common(PCIQXLDevice *qxl)
     qxl->num_memslots = NUM_MEMSLOTS;
     qxl->num_surfaces = NUM_SURFACES;
     qemu_mutex_init(&qxl->track_lock);
+    qemu_mutex_init(&qxl->async_lock);
+    qxl->current_async = QXL_UNDEFINED_IO;
 
     switch (qxl->revision) {
     case 1: /* spice 0.4 -- qxl-1 */
@@ -1528,9 +1694,9 @@ static int qxl_post_load(void *opaque, int version)
             if (!d->guest_slots[i].active) {
                 continue;
             }
-            qxl_add_memslot(d, i, 0);
+            qxl_add_memslot(d, i, 0, QXL_SYNC);
         }
-        qxl_create_guest_primary(d, 1);
+        qxl_create_guest_primary(d, 1, QXL_SYNC);
 
         /* replay surface-create and cursor-set commands */
         cmds = qemu_mallocz(sizeof(QXLCommandExt) * (NUM_SURFACES + 1));
diff --git a/hw/qxl.h b/hw/qxl.h
index 32ca5a0..1046205 100644
--- a/hw/qxl.h
+++ b/hw/qxl.h
@@ -15,6 +15,8 @@ enum qxl_mode {
     QXL_MODE_NATIVE,
 };
 
+#define QXL_UNDEFINED_IO UINT32_MAX
+
 typedef struct PCIQXLDevice {
     PCIDevice          pci;
     SimpleSpiceDisplay ssd;
@@ -30,6 +32,9 @@ typedef struct PCIQXLDevice {
     int32_t            num_memslots;
     int32_t            num_surfaces;
 
+    uint32_t           current_async;
+    QemuMutex          async_lock;
+
     struct guest_slots {
         QXLMemSlot     slot;
         void           *ptr;
@@ -104,13 +109,12 @@ void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...);
 void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
                            struct QXLRect *area, struct QXLRect *dirty_rects,
                            uint32_t num_dirty_rects,
-                           uint32_t clear_dirty_region);
-void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id);
+                           uint32_t clear_dirty_region,
+                           qxl_async_io async);
 void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
                                uint32_t count);
 void qxl_spice_oom(PCIQXLDevice *qxl);
 void qxl_spice_reset_memslots(PCIQXLDevice *qxl);
-void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl);
 void qxl_spice_reset_image_cache(PCIQXLDevice *qxl);
 void qxl_spice_reset_cursor(PCIQXLDevice *qxl);
 
@@ -122,3 +126,9 @@ void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext);
 void qxl_render_resize(PCIQXLDevice *qxl);
 void qxl_render_update(PCIQXLDevice *qxl);
 void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext);
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+void qxl_spice_update_area_async(PCIQXLDevice *qxl, uint32_t surface_id,
+                                 struct QXLRect *area,
+                                 uint32_t clear_dirty_region,
+                                 int is_vga);
+#endif
diff --git a/ui/spice-display.c b/ui/spice-display.c
index af10ae8..683d454 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -62,10 +62,18 @@ void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r)
     dest->right = MAX(dest->right, r->right);
 }
 
-
-void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot)
-{
-    ssd->worker->add_memslot(ssd->worker, memslot);
+void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot,
+                            qxl_async_io async)
+{
+    if (async != QXL_SYNC) {
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+        spice_qxl_add_memslot_async(&ssd->qxl, memslot, 0);
+#else
+        abort();
+#endif
+    } else {
+        ssd->worker->add_memslot(ssd->worker, memslot);
+    }
 }
 
 void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid, uint32_t sid)
@@ -74,14 +82,33 @@ void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid, uint32_t sid)
 }
 
 void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id,
-                                       QXLDevSurfaceCreate *surface)
-{
-    ssd->worker->create_primary_surface(ssd->worker, id, surface);
+                                       QXLDevSurfaceCreate *surface,
+                                       qxl_async_io async)
+{
+    if (async != QXL_SYNC) {
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+        spice_qxl_create_primary_surface_async(&ssd->qxl, id, surface, 0);
+#else
+        abort();
+#endif
+    } else {
+        ssd->worker->create_primary_surface(ssd->worker, id, surface);
+    }
 }
 
-void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id)
+
+void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd,
+                                        uint32_t id, qxl_async_io async)
 {
-    ssd->worker->destroy_primary_surface(ssd->worker, id);
+    if (async != QXL_SYNC) {
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+        spice_qxl_destroy_primary_surface_async(&ssd->qxl, id, 0);
+#else
+        abort();
+#endif
+    } else {
+        ssd->worker->destroy_primary_surface(ssd->worker, id);
+    }
 }
 
 void qemu_spice_wakeup(SimpleSpiceDisplay *ssd)
@@ -198,7 +225,7 @@ void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd)
     memset(&memslot, 0, sizeof(memslot));
     memslot.slot_group_id = MEMSLOT_GROUP_HOST;
     memslot.virt_end = ~0;
-    qemu_spice_add_memslot(ssd, &memslot);
+    qemu_spice_add_memslot(ssd, &memslot, QXL_SYNC);
 }
 
 void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
@@ -218,14 +245,14 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
     surface.mem        = (intptr_t)ssd->buf;
     surface.group_id   = MEMSLOT_GROUP_HOST;
 
-    qemu_spice_create_primary_surface(ssd, 0, &surface);
+    qemu_spice_create_primary_surface(ssd, 0, &surface, QXL_SYNC);
 }
 
 void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd)
 {
     dprint(1, "%s:\n", __FUNCTION__);
 
-    qemu_spice_destroy_primary_surface(ssd, 0);
+    qemu_spice_destroy_primary_surface(ssd, 0, QXL_SYNC);
 }
 
 void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason)
diff --git a/ui/spice-display.h b/ui/spice-display.h
index abe99c7..1388641 100644
--- a/ui/spice-display.h
+++ b/ui/spice-display.h
@@ -33,6 +33,20 @@
 
 #define NUM_SURFACES 1024
 
+/*
+ * Internal enum to differenciate between options for
+ * io calls that have a sync (old) version and an _async (new)
+ * version:
+ *  QXL_SYNC: use the old version
+ *  QXL_ASYNC: use the new version and make sure there are no two
+ *   happening at the same time. This is used for guest initiated
+ *   calls
+ */
+typedef enum qxl_async_io {
+    QXL_SYNC,
+    QXL_ASYNC,
+} qxl_async_io;
+
 typedef struct SimpleSpiceDisplay SimpleSpiceDisplay;
 typedef struct SimpleSpiceUpdate SimpleSpiceUpdate;
 
@@ -82,12 +96,15 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
 void qemu_spice_display_resize(SimpleSpiceDisplay *ssd);
 void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd);
 
-void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot);
+void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot,
+                            qxl_async_io async);
 void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid,
                             uint32_t sid);
 void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id,
-                                       QXLDevSurfaceCreate *surface);
-void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id);
+                                       QXLDevSurfaceCreate *surface,
+                                       qxl_async_io async);
+void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd,
+                                        uint32_t id, qxl_async_io async);
 void qemu_spice_wakeup(SimpleSpiceDisplay *ssd);
 void qemu_spice_start(SimpleSpiceDisplay *ssd);
 void qemu_spice_stop(SimpleSpiceDisplay *ssd);
commit bafc72ab01cd5a058f1d07d1bb80ae0b27ff190a
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Wed Jul 27 14:21:32 2011 +0200

    slirp: Take maintainer token
    
    Anthony asked me to pick up the maintenance of this subsystem, and I
    agreed.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>

diff --git a/MAINTAINERS b/MAINTAINERS
index 6115e4e..7cbcd7e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -431,9 +431,10 @@ S: Maintained
 F: net/
 
 SLIRP
-M: qemu-devel at nongnu.org
-S: Orphan
+M: Jan Kiszka <jan.kiszka at siemens.com>
+S: Maintained
 F: slirp/
+T: git://git.kiszka.org/qemu.git queues/slirp
 
 Usermode Emulation
 ------------------
commit ba1d1afdfeeb5ec6cbfd0052ab298d9b7cb7e5ba
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Mon Jul 25 19:42:37 2011 +0200

    posix-aio-compat: Allow read after EOF
    
    In order to be able to transparently replace bdrv_read calls by bdrv_co_read,
    reading beyond EOF must produce zeros instead of short reads for AIO, too.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/posix-aio-compat.c b/posix-aio-compat.c
index 788d113..8dc00cb 100644
--- a/posix-aio-compat.c
+++ b/posix-aio-compat.c
@@ -198,6 +198,12 @@ static ssize_t handle_aiocb_rw_vector(struct qemu_paiocb *aiocb)
     return len;
 }
 
+/*
+ * Read/writes the data to/from a given linear buffer.
+ *
+ * Returns the number of bytes handles or -errno in case of an error. Short
+ * reads are only returned if the end of the file is reached.
+ */
 static ssize_t handle_aiocb_rw_linear(struct qemu_paiocb *aiocb, char *buf)
 {
     ssize_t offset = 0;
@@ -334,6 +340,19 @@ static void *aio_thread(void *unused)
 
         switch (aiocb->aio_type & QEMU_AIO_TYPE_MASK) {
         case QEMU_AIO_READ:
+            ret = handle_aiocb_rw(aiocb);
+            if (ret >= 0 && ret < aiocb->aio_nbytes && aiocb->common.bs->growable) {
+                /* A short read means that we have reached EOF. Pad the buffer
+                 * with zeros for bytes after EOF. */
+                QEMUIOVector qiov;
+
+                qemu_iovec_init_external(&qiov, aiocb->aio_iov,
+                                         aiocb->aio_niov);
+                qemu_iovec_memset_skip(&qiov, 0, aiocb->aio_nbytes - ret, ret);
+
+                ret = aiocb->aio_nbytes;
+            }
+            break;
         case QEMU_AIO_WRITE:
             ret = handle_aiocb_rw(aiocb);
             break;
commit e680cfa7e20f5049c475ac94f998a79c9997b48d
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Wed Jul 13 15:42:52 2011 +0200

    coroutines: Use one global bottom half for CoQueue
    
    Now that AsyncContexts don't exist any more, we can use one global bottom half
    for restarting coroutines instead of allocating a new one every time (before
    removing AsyncContexts, the problem with having a global BH was that it had to
    belong to a single AsyncContexts and wouldn't be executed in a different one -
    which leads to deadlocks)
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/qemu-coroutine-lock.c b/qemu-coroutine-lock.c
index abaa1f7..a80f437 100644
--- a/qemu-coroutine-lock.c
+++ b/qemu-coroutine-lock.c
@@ -30,14 +30,10 @@
 
 static QTAILQ_HEAD(, Coroutine) unlock_bh_queue =
     QTAILQ_HEAD_INITIALIZER(unlock_bh_queue);
-
-struct unlock_bh {
-    QEMUBH *bh;
-};
+static QEMUBH* unlock_bh;
 
 static void qemu_co_queue_next_bh(void *opaque)
 {
-    struct unlock_bh *unlock_bh = opaque;
     Coroutine *next;
 
     trace_qemu_co_queue_next_bh();
@@ -45,14 +41,15 @@ static void qemu_co_queue_next_bh(void *opaque)
         QTAILQ_REMOVE(&unlock_bh_queue, next, co_queue_next);
         qemu_coroutine_enter(next, NULL);
     }
-
-    qemu_bh_delete(unlock_bh->bh);
-    qemu_free(unlock_bh);
 }
 
 void qemu_co_queue_init(CoQueue *queue)
 {
     QTAILQ_INIT(&queue->entries);
+
+    if (!unlock_bh) {
+        unlock_bh = qemu_bh_new(qemu_co_queue_next_bh, NULL);
+    }
 }
 
 void coroutine_fn qemu_co_queue_wait(CoQueue *queue)
@@ -65,7 +62,6 @@ void coroutine_fn qemu_co_queue_wait(CoQueue *queue)
 
 bool qemu_co_queue_next(CoQueue *queue)
 {
-    struct unlock_bh *unlock_bh;
     Coroutine *next;
 
     next = QTAILQ_FIRST(&queue->entries);
@@ -73,10 +69,7 @@ bool qemu_co_queue_next(CoQueue *queue)
         QTAILQ_REMOVE(&queue->entries, next, co_queue_next);
         QTAILQ_INSERT_TAIL(&unlock_bh_queue, next, co_queue_next);
         trace_qemu_co_queue_next(next);
-
-        unlock_bh = qemu_malloc(sizeof(*unlock_bh));
-        unlock_bh->bh = qemu_bh_new(qemu_co_queue_next_bh, unlock_bh);
-        qemu_bh_schedule(unlock_bh->bh);
+        qemu_bh_schedule(unlock_bh);
     }
 
     return (next != NULL);
commit 384acbf46b70edf0d2c1648aa1a92a90bcf7057d
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Fri Jul 15 16:36:40 2011 +0200

    async: Remove AsyncContext
    
    The purpose of AsyncContexts was to protect qcow and qcow2 against reentrancy
    during an emulated bdrv_read/write (which includes a qemu_aio_wait() call and
    can run AIO callbacks of different requests if it weren't for AsyncContexts).
    
    Now both qcow and qcow2 are protected by CoMutexes and AsyncContexts can be
    removed.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/async.c b/async.c
index fd313df..3fe70b9 100644
--- a/async.c
+++ b/async.c
@@ -25,92 +25,8 @@
 #include "qemu-common.h"
 #include "qemu-aio.h"
 
-/*
- * An AsyncContext protects the callbacks of AIO requests and Bottom Halves
- * against interfering with each other. A typical example is qcow2 that accepts
- * asynchronous requests, but relies for manipulation of its metadata on
- * synchronous bdrv_read/write that doesn't trigger any callbacks.
- *
- * However, these functions are often emulated using AIO which means that AIO
- * callbacks must be run - but at the same time we must not run callbacks of
- * other requests as they might start to modify metadata and corrupt the
- * internal state of the caller of bdrv_read/write.
- *
- * To achieve the desired semantics we switch into a new AsyncContext.
- * Callbacks must only be run if they belong to the current AsyncContext.
- * Otherwise they need to be queued until their own context is active again.
- * This is how you can make qemu_aio_wait() wait only for your own callbacks.
- *
- * The AsyncContexts form a stack. When you leave a AsyncContexts, you always
- * return to the old ("parent") context.
- */
-struct AsyncContext {
-    /* Consecutive number of the AsyncContext (position in the stack) */
-    int id;
-
-    /* Anchor of the list of Bottom Halves belonging to the context */
-    struct QEMUBH *first_bh;
-
-    /* Link to parent context */
-    struct AsyncContext *parent;
-};
-
-/* The currently active AsyncContext */
-static struct AsyncContext *async_context = &(struct AsyncContext) { 0 };
-
-/*
- * Enter a new AsyncContext. Already scheduled Bottom Halves and AIO callbacks
- * won't be called until this context is left again.
- */
-void async_context_push(void)
-{
-    struct AsyncContext *new = qemu_mallocz(sizeof(*new));
-    new->parent = async_context;
-    new->id = async_context->id + 1;
-    async_context = new;
-}
-
-/* Run queued AIO completions and destroy Bottom Half */
-static void bh_run_aio_completions(void *opaque)
-{
-    QEMUBH **bh = opaque;
-    qemu_bh_delete(*bh);
-    qemu_free(bh);
-    qemu_aio_process_queue();
-}
-/*
- * Leave the currently active AsyncContext. All Bottom Halves belonging to the
- * old context are executed before changing the context.
- */
-void async_context_pop(void)
-{
-    struct AsyncContext *old = async_context;
-    QEMUBH **bh;
-
-    /* Flush the bottom halves, we don't want to lose them */
-    while (qemu_bh_poll());
-
-    /* Switch back to the parent context */
-    async_context = async_context->parent;
-    qemu_free(old);
-
-    if (async_context == NULL) {
-        abort();
-    }
-
-    /* Schedule BH to run any queued AIO completions as soon as possible */
-    bh = qemu_malloc(sizeof(*bh));
-    *bh = qemu_bh_new(bh_run_aio_completions, bh);
-    qemu_bh_schedule(*bh);
-}
-
-/*
- * Returns the ID of the currently active AsyncContext
- */
-int get_async_context_id(void)
-{
-    return async_context->id;
-}
+/* Anchor of the list of Bottom Halves belonging to the context */
+static struct QEMUBH *first_bh;
 
 /***********************************************************/
 /* bottom halves (can be seen as timers which expire ASAP) */
@@ -130,8 +46,8 @@ QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque)
     bh = qemu_mallocz(sizeof(QEMUBH));
     bh->cb = cb;
     bh->opaque = opaque;
-    bh->next = async_context->first_bh;
-    async_context->first_bh = bh;
+    bh->next = first_bh;
+    first_bh = bh;
     return bh;
 }
 
@@ -141,7 +57,7 @@ int qemu_bh_poll(void)
     int ret;
 
     ret = 0;
-    for (bh = async_context->first_bh; bh; bh = next) {
+    for (bh = first_bh; bh; bh = next) {
         next = bh->next;
         if (!bh->deleted && bh->scheduled) {
             bh->scheduled = 0;
@@ -153,7 +69,7 @@ int qemu_bh_poll(void)
     }
 
     /* remove deleted bhs */
-    bhp = &async_context->first_bh;
+    bhp = &first_bh;
     while (*bhp) {
         bh = *bhp;
         if (bh->deleted) {
@@ -199,7 +115,7 @@ void qemu_bh_update_timeout(int *timeout)
 {
     QEMUBH *bh;
 
-    for (bh = async_context->first_bh; bh; bh = bh->next) {
+    for (bh = first_bh; bh; bh = bh->next) {
         if (!bh->deleted && bh->scheduled) {
             if (bh->idle) {
                 /* idle bottom halves will be polled at least
diff --git a/block.c b/block.c
index e6abea8..0d05b4b 100644
--- a/block.c
+++ b/block.c
@@ -2777,8 +2777,6 @@ static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num,
     struct iovec iov;
     QEMUIOVector qiov;
 
-    async_context_push();
-
     async_ret = NOT_DONE;
     iov.iov_base = (void *)buf;
     iov.iov_len = nb_sectors * BDRV_SECTOR_SIZE;
@@ -2796,7 +2794,6 @@ static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num,
 
 
 fail:
-    async_context_pop();
     return async_ret;
 }
 
@@ -2808,8 +2805,6 @@ static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
     struct iovec iov;
     QEMUIOVector qiov;
 
-    async_context_push();
-
     async_ret = NOT_DONE;
     iov.iov_base = (void *)buf;
     iov.iov_len = nb_sectors * BDRV_SECTOR_SIZE;
@@ -2825,7 +2820,6 @@ static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
     }
 
 fail:
-    async_context_pop();
     return async_ret;
 }
 
diff --git a/block/qed-table.c b/block/qed-table.c
index d38c673..d96afa8 100644
--- a/block/qed-table.c
+++ b/block/qed-table.c
@@ -179,16 +179,12 @@ int qed_read_l1_table_sync(BDRVQEDState *s)
 {
     int ret = -EINPROGRESS;
 
-    async_context_push();
-
     qed_read_table(s, s->header.l1_table_offset,
                    s->l1_table, qed_sync_cb, &ret);
     while (ret == -EINPROGRESS) {
         qemu_aio_wait();
     }
 
-    async_context_pop();
-
     return ret;
 }
 
@@ -205,15 +201,11 @@ int qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index,
 {
     int ret = -EINPROGRESS;
 
-    async_context_push();
-
     qed_write_l1_table(s, index, n, qed_sync_cb, &ret);
     while (ret == -EINPROGRESS) {
         qemu_aio_wait();
     }
 
-    async_context_pop();
-
     return ret;
 }
 
@@ -282,14 +274,11 @@ int qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request, uint64_t offset
 {
     int ret = -EINPROGRESS;
 
-    async_context_push();
-
     qed_read_l2_table(s, request, offset, qed_sync_cb, &ret);
     while (ret == -EINPROGRESS) {
         qemu_aio_wait();
     }
 
-    async_context_pop();
     return ret;
 }
 
@@ -307,13 +296,10 @@ int qed_write_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
 {
     int ret = -EINPROGRESS;
 
-    async_context_push();
-
     qed_write_l2_table(s, request, index, n, flush, qed_sync_cb, &ret);
     while (ret == -EINPROGRESS) {
         qemu_aio_wait();
     }
 
-    async_context_pop();
     return ret;
 }
diff --git a/block/qed.c b/block/qed.c
index 3970379..333f067 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -680,16 +680,12 @@ static int bdrv_qed_is_allocated(BlockDriverState *bs, int64_t sector_num,
     };
     QEDRequest request = { .l2_table = NULL };
 
-    async_context_push();
-
     qed_find_cluster(s, &request, pos, len, qed_is_allocated_cb, &cb);
 
     while (cb.is_allocated == -1) {
         qemu_aio_wait();
     }
 
-    async_context_pop();
-
     qed_unref_l2_cache_entry(request.l2_table);
 
     return cb.is_allocated;
diff --git a/linux-aio.c b/linux-aio.c
index 68f4b3d..dc3faf2 100644
--- a/linux-aio.c
+++ b/linux-aio.c
@@ -31,7 +31,6 @@ struct qemu_laiocb {
     struct iocb iocb;
     ssize_t ret;
     size_t nbytes;
-    int async_context_id;
     QLIST_ENTRY(qemu_laiocb) node;
 };
 
@@ -39,7 +38,6 @@ struct qemu_laio_state {
     io_context_t ctx;
     int efd;
     int count;
-    QLIST_HEAD(, qemu_laiocb) completed_reqs;
 };
 
 static inline ssize_t io_event_ret(struct io_event *ev)
@@ -49,7 +47,6 @@ static inline ssize_t io_event_ret(struct io_event *ev)
 
 /*
  * Completes an AIO request (calls the callback and frees the ACB).
- * Be sure to be in the right AsyncContext before calling this function.
  */
 static void qemu_laio_process_completion(struct qemu_laio_state *s,
     struct qemu_laiocb *laiocb)
@@ -72,42 +69,12 @@ static void qemu_laio_process_completion(struct qemu_laio_state *s,
 }
 
 /*
- * Processes all queued AIO requests, i.e. requests that have return from OS
- * but their callback was not called yet. Requests that cannot have their
- * callback called in the current AsyncContext, remain in the queue.
- *
- * Returns 1 if at least one request could be completed, 0 otherwise.
+ * All requests are directly processed when they complete, so there's nothing
+ * left to do during qemu_aio_wait().
  */
 static int qemu_laio_process_requests(void *opaque)
 {
-    struct qemu_laio_state *s = opaque;
-    struct qemu_laiocb *laiocb, *next;
-    int res = 0;
-
-    QLIST_FOREACH_SAFE (laiocb, &s->completed_reqs, node, next) {
-        if (laiocb->async_context_id == get_async_context_id()) {
-            qemu_laio_process_completion(s, laiocb);
-            QLIST_REMOVE(laiocb, node);
-            res = 1;
-        }
-    }
-
-    return res;
-}
-
-/*
- * Puts a request in the completion queue so that its callback is called the
- * next time when it's possible. If we already are in the right AsyncContext,
- * the request is completed immediately instead.
- */
-static void qemu_laio_enqueue_completed(struct qemu_laio_state *s,
-    struct qemu_laiocb* laiocb)
-{
-    if (laiocb->async_context_id == get_async_context_id()) {
-        qemu_laio_process_completion(s, laiocb);
-    } else {
-        QLIST_INSERT_HEAD(&s->completed_reqs, laiocb, node);
-    }
+    return 0;
 }
 
 static void qemu_laio_completion_cb(void *opaque)
@@ -141,7 +108,7 @@ static void qemu_laio_completion_cb(void *opaque)
                     container_of(iocb, struct qemu_laiocb, iocb);
 
             laiocb->ret = io_event_ret(&events[i]);
-            qemu_laio_enqueue_completed(s, laiocb);
+            qemu_laio_process_completion(s, laiocb);
         }
     }
 }
@@ -204,7 +171,6 @@ BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
     laiocb->nbytes = nb_sectors * 512;
     laiocb->ctx = s;
     laiocb->ret = -EINPROGRESS;
-    laiocb->async_context_id = get_async_context_id();
 
     iocbs = &laiocb->iocb;
 
@@ -239,7 +205,6 @@ void *laio_init(void)
     struct qemu_laio_state *s;
 
     s = qemu_mallocz(sizeof(*s));
-    QLIST_INIT(&s->completed_reqs);
     s->efd = eventfd(0, 0);
     if (s->efd == -1)
         goto out_free_state;
diff --git a/posix-aio-compat.c b/posix-aio-compat.c
index c4116e3..788d113 100644
--- a/posix-aio-compat.c
+++ b/posix-aio-compat.c
@@ -49,8 +49,6 @@ struct qemu_paiocb {
     ssize_t ret;
     int active;
     struct qemu_paiocb *next;
-
-    int async_context_id;
 };
 
 typedef struct PosixAioState {
@@ -420,7 +418,6 @@ static int posix_aio_process_queue(void *opaque)
     struct qemu_paiocb *acb, **pacb;
     int ret;
     int result = 0;
-    int async_context_id = get_async_context_id();
 
     for(;;) {
         pacb = &s->first_aio;
@@ -429,12 +426,6 @@ static int posix_aio_process_queue(void *opaque)
             if (!acb)
                 return result;
 
-            /* we're only interested in requests in the right context */
-            if (acb->async_context_id != async_context_id) {
-                pacb = &acb->next;
-                continue;
-            }
-
             ret = qemu_paio_error(acb);
             if (ret == ECANCELED) {
                 /* remove the request */
@@ -575,7 +566,6 @@ BlockDriverAIOCB *paio_submit(BlockDriverState *bs, int fd,
     acb->aio_type = type;
     acb->aio_fildes = fd;
     acb->ev_signo = SIGUSR2;
-    acb->async_context_id = get_async_context_id();
 
     if (qiov) {
         acb->aio_iov = qiov->iov;
@@ -604,7 +594,6 @@ BlockDriverAIOCB *paio_ioctl(BlockDriverState *bs, int fd,
     acb->aio_type = QEMU_AIO_IOCTL;
     acb->aio_fildes = fd;
     acb->ev_signo = SIGUSR2;
-    acb->async_context_id = get_async_context_id();
     acb->aio_offset = 0;
     acb->aio_ioctl_buf = buf;
     acb->aio_ioctl_cmd = req;
diff --git a/qemu-common.h b/qemu-common.h
index 1e3c665..8f21a8c 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -115,10 +115,6 @@ int qemu_main(int argc, char **argv, char **envp);
 /* bottom halves */
 typedef void QEMUBHFunc(void *opaque);
 
-void async_context_push(void);
-void async_context_pop(void);
-int get_async_context_id(void);
-
 QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque);
 void qemu_bh_schedule(QEMUBH *bh);
 /* Bottom halfs that are scheduled from a bottom half handler are instantly
commit 52b8eb60132b27ad53476490e9d7579003390cfa
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Fri Jul 15 16:27:42 2011 +0200

    qcow: Use coroutines
    
    The old qcow format is another user of the AsyncContext infrastructure.
    Converting it to coroutines (and therefore CoMutexes) allows to remove
    AsyncContexts.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/qcow.c b/block/qcow.c
index 227b104..6447c2a 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -73,6 +73,7 @@ typedef struct BDRVQcowState {
     uint32_t crypt_method_header;
     AES_KEY aes_encrypt_key;
     AES_KEY aes_decrypt_key;
+    CoMutex lock;
 } BDRVQcowState;
 
 static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset);
@@ -517,11 +518,11 @@ static AIOPool qcow_aio_pool = {
 
 static QCowAIOCB *qcow_aio_setup(BlockDriverState *bs,
         int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque, int is_write)
+        int is_write)
 {
     QCowAIOCB *acb;
 
-    acb = qemu_aio_get(&qcow_aio_pool, bs, cb, opaque);
+    acb = qemu_aio_get(&qcow_aio_pool, bs, NULL, NULL);
     if (!acb)
         return NULL;
     acb->hd_aiocb = NULL;
@@ -542,48 +543,15 @@ static QCowAIOCB *qcow_aio_setup(BlockDriverState *bs,
     return acb;
 }
 
-static void qcow_aio_read_cb(void *opaque, int ret);
-static void qcow_aio_write_cb(void *opaque, int ret);
-
-static void qcow_aio_rw_bh(void *opaque)
-{
-    QCowAIOCB *acb = opaque;
-    qemu_bh_delete(acb->bh);
-    acb->bh = NULL;
-
-    if (acb->is_write) {
-        qcow_aio_write_cb(opaque, 0);
-    } else {
-        qcow_aio_read_cb(opaque, 0);
-    }
-}
-
-static int qcow_schedule_bh(QEMUBHFunc *cb, QCowAIOCB *acb)
-{
-    if (acb->bh) {
-        return -EIO;
-    }
-
-    acb->bh = qemu_bh_new(cb, acb);
-    if (!acb->bh) {
-        return -EIO;
-    }
-
-    qemu_bh_schedule(acb->bh);
-
-    return 0;
-}
-
-static void qcow_aio_read_cb(void *opaque, int ret)
+static int qcow_aio_read_cb(void *opaque)
 {
     QCowAIOCB *acb = opaque;
     BlockDriverState *bs = acb->common.bs;
     BDRVQcowState *s = bs->opaque;
     int index_in_cluster;
+    int ret;
 
     acb->hd_aiocb = NULL;
-    if (ret < 0)
-        goto done;
 
  redo:
     /* post process the read buffer */
@@ -605,8 +573,7 @@ static void qcow_aio_read_cb(void *opaque, int ret)
 
     if (acb->nb_sectors == 0) {
         /* request completed */
-        ret = 0;
-        goto done;
+        return 0;
     }
 
     /* prepare next AIO request */
@@ -623,11 +590,12 @@ static void qcow_aio_read_cb(void *opaque, int ret)
             acb->hd_iov.iov_base = (void *)acb->buf;
             acb->hd_iov.iov_len = acb->n * 512;
             qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
-            acb->hd_aiocb = bdrv_aio_readv(bs->backing_hd, acb->sector_num,
-                &acb->hd_qiov, acb->n, qcow_aio_read_cb, acb);
-            if (acb->hd_aiocb == NULL) {
-                ret = -EIO;
-                goto done;
+            qemu_co_mutex_unlock(&s->lock);
+            ret = bdrv_co_readv(bs->backing_hd, acb->sector_num,
+                                acb->n, &acb->hd_qiov);
+            qemu_co_mutex_lock(&s->lock);
+            if (ret < 0) {
+                return -EIO;
             }
         } else {
             /* Note: in this case, no need to wait */
@@ -637,64 +605,56 @@ static void qcow_aio_read_cb(void *opaque, int ret)
     } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
         /* add AIO support for compressed blocks ? */
         if (decompress_cluster(bs, acb->cluster_offset) < 0) {
-            ret = -EIO;
-            goto done;
+            return -EIO;
         }
         memcpy(acb->buf,
                s->cluster_cache + index_in_cluster * 512, 512 * acb->n);
         goto redo;
     } else {
         if ((acb->cluster_offset & 511) != 0) {
-            ret = -EIO;
-            goto done;
+            return -EIO;
         }
         acb->hd_iov.iov_base = (void *)acb->buf;
         acb->hd_iov.iov_len = acb->n * 512;
         qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
-        acb->hd_aiocb = bdrv_aio_readv(bs->file,
+        qemu_co_mutex_unlock(&s->lock);
+        ret = bdrv_co_readv(bs->file,
                             (acb->cluster_offset >> 9) + index_in_cluster,
-                            &acb->hd_qiov, acb->n, qcow_aio_read_cb, acb);
-        if (acb->hd_aiocb == NULL) {
-            ret = -EIO;
-            goto done;
+                            acb->n, &acb->hd_qiov);
+        qemu_co_mutex_lock(&s->lock);
+        if (ret < 0) {
+            return ret;
         }
     }
 
-    return;
-
-done:
-    if (acb->qiov->niov > 1) {
-        qemu_iovec_from_buffer(acb->qiov, acb->orig_buf, acb->qiov->size);
-        qemu_vfree(acb->orig_buf);
-    }
-    acb->common.cb(acb->common.opaque, ret);
-    qemu_aio_release(acb);
+    return 1;
 }
 
-static BlockDriverAIOCB *qcow_aio_readv(BlockDriverState *bs,
-        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque)
+static int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
+                         int nb_sectors, QEMUIOVector *qiov)
 {
+    BDRVQcowState *s = bs->opaque;
     QCowAIOCB *acb;
     int ret;
 
-    acb = qcow_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
-    if (!acb)
-        return NULL;
+    acb = qcow_aio_setup(bs, sector_num, qiov, nb_sectors, 0);
 
-    ret = qcow_schedule_bh(qcow_aio_rw_bh, acb);
-    if (ret < 0) {
-        if (acb->qiov->niov > 1) {
-            qemu_vfree(acb->orig_buf);
-        }
-        qemu_aio_release(acb);
-        return NULL;
+    qemu_co_mutex_lock(&s->lock);
+    do {
+        ret = qcow_aio_read_cb(acb);
+    } while (ret > 0);
+    qemu_co_mutex_unlock(&s->lock);
+
+    if (acb->qiov->niov > 1) {
+        qemu_iovec_from_buffer(acb->qiov, acb->orig_buf, acb->qiov->size);
+        qemu_vfree(acb->orig_buf);
     }
+    qemu_aio_release(acb);
 
-    return &acb->common;
+    return ret;
 }
 
-static void qcow_aio_write_cb(void *opaque, int ret)
+static int qcow_aio_write_cb(void *opaque)
 {
     QCowAIOCB *acb = opaque;
     BlockDriverState *bs = acb->common.bs;
@@ -702,20 +662,17 @@ static void qcow_aio_write_cb(void *opaque, int ret)
     int index_in_cluster;
     uint64_t cluster_offset;
     const uint8_t *src_buf;
+    int ret;
 
     acb->hd_aiocb = NULL;
 
-    if (ret < 0)
-        goto done;
-
     acb->nb_sectors -= acb->n;
     acb->sector_num += acb->n;
     acb->buf += acb->n * 512;
 
     if (acb->nb_sectors == 0) {
         /* request completed */
-        ret = 0;
-        goto done;
+        return 0;
     }
 
     index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
@@ -726,16 +683,11 @@ static void qcow_aio_write_cb(void *opaque, int ret)
                                         index_in_cluster,
                                         index_in_cluster + acb->n);
     if (!cluster_offset || (cluster_offset & 511) != 0) {
-        ret = -EIO;
-        goto done;
+        return -EIO;
     }
     if (s->crypt_method) {
         if (!acb->cluster_data) {
             acb->cluster_data = qemu_mallocz(s->cluster_size);
-            if (!acb->cluster_data) {
-                ret = -ENOMEM;
-                goto done;
-            }
         }
         encrypt_sectors(s, acb->sector_num, acb->cluster_data, acb->buf,
                         acb->n, 1, &s->aes_encrypt_key);
@@ -747,26 +699,19 @@ static void qcow_aio_write_cb(void *opaque, int ret)
     acb->hd_iov.iov_base = (void *)src_buf;
     acb->hd_iov.iov_len = acb->n * 512;
     qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
-    acb->hd_aiocb = bdrv_aio_writev(bs->file,
-                                    (cluster_offset >> 9) + index_in_cluster,
-                                    &acb->hd_qiov, acb->n,
-                                    qcow_aio_write_cb, acb);
-    if (acb->hd_aiocb == NULL) {
-        ret = -EIO;
-        goto done;
+    qemu_co_mutex_unlock(&s->lock);
+    ret = bdrv_co_writev(bs->file,
+                         (cluster_offset >> 9) + index_in_cluster,
+                         acb->n, &acb->hd_qiov);
+    qemu_co_mutex_lock(&s->lock);
+    if (ret < 0) {
+        return ret;
     }
-    return;
-
-done:
-    if (acb->qiov->niov > 1)
-        qemu_vfree(acb->orig_buf);
-    acb->common.cb(acb->common.opaque, ret);
-    qemu_aio_release(acb);
+    return 1;
 }
 
-static BlockDriverAIOCB *qcow_aio_writev(BlockDriverState *bs,
-        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque)
+static int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
+                          int nb_sectors, QEMUIOVector *qiov)
 {
     BDRVQcowState *s = bs->opaque;
     QCowAIOCB *acb;
@@ -774,21 +719,20 @@ static BlockDriverAIOCB *qcow_aio_writev(BlockDriverState *bs,
 
     s->cluster_cache_offset = -1; /* disable compressed cache */
 
-    acb = qcow_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
-    if (!acb)
-        return NULL;
+    acb = qcow_aio_setup(bs, sector_num, qiov, nb_sectors, 1);
 
+    qemu_co_mutex_lock(&s->lock);
+    do {
+        ret = qcow_aio_write_cb(acb);
+    } while (ret > 0);
+    qemu_co_mutex_unlock(&s->lock);
 
-    ret = qcow_schedule_bh(qcow_aio_rw_bh, acb);
-    if (ret < 0) {
-        if (acb->qiov->niov > 1) {
-            qemu_vfree(acb->orig_buf);
-        }
-        qemu_aio_release(acb);
-        return NULL;
+    if (acb->qiov->niov > 1) {
+        qemu_vfree(acb->orig_buf);
     }
+    qemu_aio_release(acb);
 
-    return &acb->common;
+    return ret;
 }
 
 static void qcow_close(BlockDriverState *bs)
@@ -1020,8 +964,8 @@ static BlockDriver bdrv_qcow = {
     .bdrv_is_allocated	= qcow_is_allocated,
     .bdrv_set_key	= qcow_set_key,
     .bdrv_make_empty	= qcow_make_empty,
-    .bdrv_aio_readv	= qcow_aio_readv,
-    .bdrv_aio_writev	= qcow_aio_writev,
+    .bdrv_co_readv  = qcow_co_readv,
+    .bdrv_co_writev = qcow_co_writev,
     .bdrv_aio_flush	= qcow_aio_flush,
     .bdrv_write_compressed = qcow_write_compressed,
     .bdrv_get_info	= qcow_get_info,
commit 68d100e905453ebbeea8e915f4f18a2bd4339fe8
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Thu Jun 30 17:42:09 2011 +0200

    qcow2: Use coroutines
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 882f50a..81cf77d 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -697,12 +697,12 @@ err:
  * m->depends_on is set to NULL and the other fields in m are meaningless.
  *
  * If the cluster is newly allocated, m->nb_clusters is set to the number of
- * contiguous clusters that have been allocated. This may be 0 if the request
- * conflict with another write request in flight; in this case, m->depends_on
- * is set and the remaining fields of m are meaningless.
+ * contiguous clusters that have been allocated. In this case, the other
+ * fields of m are valid and contain information about the first allocated
+ * cluster.
  *
- * If m->nb_clusters is non-zero, the other fields of m are valid and contain
- * information about the first allocated cluster.
+ * If the request conflicts with another write request in flight, the coroutine
+ * is queued and will be reentered when the dependency has completed.
  *
  * Return 0 on success and -errno in error cases
  */
@@ -721,6 +721,7 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
         return ret;
     }
 
+again:
     nb_clusters = size_to_clusters(s, n_end << 9);
 
     nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
@@ -792,12 +793,12 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
             }
 
             if (nb_clusters == 0) {
-                /* Set dependency and wait for a callback */
-                m->depends_on = old_alloc;
-                m->nb_clusters = 0;
-                *num = 0;
-
-                goto out_wait_dependency;
+                /* Wait for the dependency to complete. We need to recheck
+                 * the free/allocated clusters when we continue. */
+                qemu_co_mutex_unlock(&s->lock);
+                qemu_co_queue_wait(&old_alloc->dependent_requests);
+                qemu_co_mutex_lock(&s->lock);
+                goto again;
             }
         }
     }
@@ -834,9 +835,6 @@ out:
 
     return 0;
 
-out_wait_dependency:
-    return qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
-
 fail:
     qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
 fail_put:
diff --git a/block/qcow2.c b/block/qcow2.c
index 48e1b95..f07d550 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -276,6 +276,9 @@ static int qcow2_open(BlockDriverState *bs, int flags)
         goto fail;
     }
 
+    /* Initialise locks */
+    qemu_co_mutex_init(&s->lock);
+
 #ifdef DEBUG_ALLOC
     qcow2_check_refcounts(bs);
 #endif
@@ -379,7 +382,6 @@ typedef struct QCowAIOCB {
     uint64_t cluster_offset;
     uint8_t *cluster_data;
     bool is_write;
-    BlockDriverAIOCB *hd_aiocb;
     QEMUIOVector hd_qiov;
     QEMUBH *bh;
     QCowL2Meta l2meta;
@@ -389,8 +391,6 @@ typedef struct QCowAIOCB {
 static void qcow2_aio_cancel(BlockDriverAIOCB *blockacb)
 {
     QCowAIOCB *acb = container_of(blockacb, QCowAIOCB, common);
-    if (acb->hd_aiocb)
-        bdrv_aio_cancel(acb->hd_aiocb);
     qemu_aio_release(acb);
 }
 
@@ -399,46 +399,16 @@ static AIOPool qcow2_aio_pool = {
     .cancel             = qcow2_aio_cancel,
 };
 
-static void qcow2_aio_read_cb(void *opaque, int ret);
-static void qcow2_aio_write_cb(void *opaque, int ret);
-
-static void qcow2_aio_rw_bh(void *opaque)
-{
-    QCowAIOCB *acb = opaque;
-    qemu_bh_delete(acb->bh);
-    acb->bh = NULL;
-
-    if (acb->is_write) {
-        qcow2_aio_write_cb(opaque, 0);
-    } else {
-        qcow2_aio_read_cb(opaque, 0);
-    }
-}
-
-static int qcow2_schedule_bh(QEMUBHFunc *cb, QCowAIOCB *acb)
-{
-    if (acb->bh)
-        return -EIO;
-
-    acb->bh = qemu_bh_new(cb, acb);
-    if (!acb->bh)
-        return -EIO;
-
-    qemu_bh_schedule(acb->bh);
-
-    return 0;
-}
-
-static void qcow2_aio_read_cb(void *opaque, int ret)
+/*
+ * Returns 0 when the request is completed successfully, 1 when there is still
+ * a part left to do and -errno in error cases.
+ */
+static int qcow2_aio_read_cb(QCowAIOCB *acb)
 {
-    QCowAIOCB *acb = opaque;
     BlockDriverState *bs = acb->common.bs;
     BDRVQcowState *s = bs->opaque;
     int index_in_cluster, n1;
-
-    acb->hd_aiocb = NULL;
-    if (ret < 0)
-        goto done;
+    int ret;
 
     /* post process the read buffer */
     if (!acb->cluster_offset) {
@@ -463,8 +433,7 @@ static void qcow2_aio_read_cb(void *opaque, int ret)
 
     if (acb->remaining_sectors == 0) {
         /* request completed */
-        ret = 0;
-        goto done;
+        return 0;
     }
 
     /* prepare next AIO request */
@@ -477,7 +446,7 @@ static void qcow2_aio_read_cb(void *opaque, int ret)
     ret = qcow2_get_cluster_offset(bs, acb->sector_num << 9,
         &acb->cur_nr_sectors, &acb->cluster_offset);
     if (ret < 0) {
-        goto done;
+        return ret;
     }
 
     index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
@@ -494,42 +463,35 @@ static void qcow2_aio_read_cb(void *opaque, int ret)
                 acb->sector_num, acb->cur_nr_sectors);
             if (n1 > 0) {
                 BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
-                acb->hd_aiocb = bdrv_aio_readv(bs->backing_hd, acb->sector_num,
-                                    &acb->hd_qiov, n1, qcow2_aio_read_cb, acb);
-                if (acb->hd_aiocb == NULL) {
-                    ret = -EIO;
-                    goto done;
+                qemu_co_mutex_unlock(&s->lock);
+                ret = bdrv_co_readv(bs->backing_hd, acb->sector_num,
+                                    n1, &acb->hd_qiov);
+                qemu_co_mutex_lock(&s->lock);
+                if (ret < 0) {
+                    return ret;
                 }
-            } else {
-                ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb);
-                if (ret < 0)
-                    goto done;
             }
+            return 1;
         } else {
             /* Note: in this case, no need to wait */
             qemu_iovec_memset(&acb->hd_qiov, 0, 512 * acb->cur_nr_sectors);
-            ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb);
-            if (ret < 0)
-                goto done;
+            return 1;
         }
     } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
         /* add AIO support for compressed blocks ? */
         ret = qcow2_decompress_cluster(bs, acb->cluster_offset);
         if (ret < 0) {
-            goto done;
+            return ret;
         }
 
         qemu_iovec_from_buffer(&acb->hd_qiov,
             s->cluster_cache + index_in_cluster * 512,
             512 * acb->cur_nr_sectors);
 
-        ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb);
-        if (ret < 0)
-            goto done;
+        return 1;
     } else {
         if ((acb->cluster_offset & 511) != 0) {
-            ret = -EIO;
-            goto done;
+            return -EIO;
         }
 
         if (s->crypt_method) {
@@ -550,21 +512,17 @@ static void qcow2_aio_read_cb(void *opaque, int ret)
         }
 
         BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
-        acb->hd_aiocb = bdrv_aio_readv(bs->file,
+        qemu_co_mutex_unlock(&s->lock);
+        ret = bdrv_co_readv(bs->file,
                             (acb->cluster_offset >> 9) + index_in_cluster,
-                            &acb->hd_qiov, acb->cur_nr_sectors,
-                            qcow2_aio_read_cb, acb);
-        if (acb->hd_aiocb == NULL) {
-            ret = -EIO;
-            goto done;
+                            acb->cur_nr_sectors, &acb->hd_qiov);
+        qemu_co_mutex_lock(&s->lock);
+        if (ret < 0) {
+            return ret;
         }
     }
 
-    return;
-done:
-    acb->common.cb(acb->common.opaque, ret);
-    qemu_iovec_destroy(&acb->hd_qiov);
-    qemu_aio_release(acb);
+    return 1;
 }
 
 static QCowAIOCB *qcow2_aio_setup(BlockDriverState *bs, int64_t sector_num,
@@ -577,7 +535,6 @@ static QCowAIOCB *qcow2_aio_setup(BlockDriverState *bs, int64_t sector_num,
     acb = qemu_aio_get(&qcow2_aio_pool, bs, cb, opaque);
     if (!acb)
         return NULL;
-    acb->hd_aiocb = NULL;
     acb->sector_num = sector_num;
     acb->qiov = qiov;
     acb->is_write = is_write;
@@ -589,70 +546,65 @@ static QCowAIOCB *qcow2_aio_setup(BlockDriverState *bs, int64_t sector_num,
     acb->cur_nr_sectors = 0;
     acb->cluster_offset = 0;
     acb->l2meta.nb_clusters = 0;
-    QLIST_INIT(&acb->l2meta.dependent_requests);
+    qemu_co_queue_init(&acb->l2meta.dependent_requests);
     return acb;
 }
 
-static BlockDriverAIOCB *qcow2_aio_readv(BlockDriverState *bs,
-                                         int64_t sector_num,
-                                         QEMUIOVector *qiov, int nb_sectors,
-                                         BlockDriverCompletionFunc *cb,
-                                         void *opaque)
+static int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
+                          int nb_sectors, QEMUIOVector *qiov)
 {
+    BDRVQcowState *s = bs->opaque;
     QCowAIOCB *acb;
     int ret;
 
-    acb = qcow2_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
-    if (!acb)
-        return NULL;
+    acb = qcow2_aio_setup(bs, sector_num, qiov, nb_sectors, NULL, NULL, 0);
 
-    ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb);
-    if (ret < 0) {
-        qemu_iovec_destroy(&acb->hd_qiov);
-        qemu_aio_release(acb);
-        return NULL;
-    }
+    qemu_co_mutex_lock(&s->lock);
+    do {
+        ret = qcow2_aio_read_cb(acb);
+    } while (ret > 0);
+    qemu_co_mutex_unlock(&s->lock);
 
-    return &acb->common;
+    qemu_iovec_destroy(&acb->hd_qiov);
+    qemu_aio_release(acb);
+
+    return ret;
 }
 
-static void run_dependent_requests(QCowL2Meta *m)
+static void run_dependent_requests(BDRVQcowState *s, QCowL2Meta *m)
 {
-    QCowAIOCB *req;
-    QCowAIOCB *next;
-
     /* Take the request off the list of running requests */
     if (m->nb_clusters != 0) {
         QLIST_REMOVE(m, next_in_flight);
     }
 
     /* Restart all dependent requests */
-    QLIST_FOREACH_SAFE(req, &m->dependent_requests, next_depend, next) {
-        qcow2_aio_write_cb(req, 0);
+    if (!qemu_co_queue_empty(&m->dependent_requests)) {
+        qemu_co_mutex_unlock(&s->lock);
+        while(qemu_co_queue_next(&m->dependent_requests));
+        qemu_co_mutex_lock(&s->lock);
     }
-
-    /* Empty the list for the next part of the request */
-    QLIST_INIT(&m->dependent_requests);
 }
 
-static void qcow2_aio_write_cb(void *opaque, int ret)
+/*
+ * Returns 0 when the request is completed successfully, 1 when there is still
+ * a part left to do and -errno in error cases.
+ */
+static int qcow2_aio_write_cb(QCowAIOCB *acb)
 {
-    QCowAIOCB *acb = opaque;
     BlockDriverState *bs = acb->common.bs;
     BDRVQcowState *s = bs->opaque;
     int index_in_cluster;
     int n_end;
+    int ret;
 
-    acb->hd_aiocb = NULL;
-
-    if (ret >= 0) {
-        ret = qcow2_alloc_cluster_link_l2(bs, &acb->l2meta);
-    }
+    ret = qcow2_alloc_cluster_link_l2(bs, &acb->l2meta);
 
-    run_dependent_requests(&acb->l2meta);
+    run_dependent_requests(s, &acb->l2meta);
 
-    if (ret < 0)
-        goto done;
+    if (ret < 0) {
+        return ret;
+    }
 
     acb->remaining_sectors -= acb->cur_nr_sectors;
     acb->sector_num += acb->cur_nr_sectors;
@@ -660,8 +612,7 @@ static void qcow2_aio_write_cb(void *opaque, int ret)
 
     if (acb->remaining_sectors == 0) {
         /* request completed */
-        ret = 0;
-        goto done;
+        return 0;
     }
 
     index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
@@ -673,18 +624,10 @@ static void qcow2_aio_write_cb(void *opaque, int ret)
     ret = qcow2_alloc_cluster_offset(bs, acb->sector_num << 9,
         index_in_cluster, n_end, &acb->cur_nr_sectors, &acb->l2meta);
     if (ret < 0) {
-        goto done;
+        return ret;
     }
 
     acb->cluster_offset = acb->l2meta.cluster_offset;
-
-    /* Need to wait for another request? If so, we are done for now. */
-    if (acb->l2meta.nb_clusters == 0 && acb->l2meta.depends_on != NULL) {
-        QLIST_INSERT_HEAD(&acb->l2meta.depends_on->dependent_requests,
-            acb, next_depend);
-        return;
-    }
-
     assert((acb->cluster_offset & 511) == 0);
 
     qemu_iovec_reset(&acb->hd_qiov);
@@ -709,51 +652,40 @@ static void qcow2_aio_write_cb(void *opaque, int ret)
     }
 
     BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
-    acb->hd_aiocb = bdrv_aio_writev(bs->file,
-                                    (acb->cluster_offset >> 9) + index_in_cluster,
-                                    &acb->hd_qiov, acb->cur_nr_sectors,
-                                    qcow2_aio_write_cb, acb);
-    if (acb->hd_aiocb == NULL) {
-        ret = -EIO;
-        goto fail;
+    qemu_co_mutex_unlock(&s->lock);
+    ret = bdrv_co_writev(bs->file,
+                         (acb->cluster_offset >> 9) + index_in_cluster,
+                         acb->cur_nr_sectors, &acb->hd_qiov);
+    qemu_co_mutex_lock(&s->lock);
+    if (ret < 0) {
+        return ret;
     }
 
-    return;
-
-fail:
-    if (acb->l2meta.nb_clusters != 0) {
-        QLIST_REMOVE(&acb->l2meta, next_in_flight);
-    }
-done:
-    acb->common.cb(acb->common.opaque, ret);
-    qemu_iovec_destroy(&acb->hd_qiov);
-    qemu_aio_release(acb);
+    return 1;
 }
 
-static BlockDriverAIOCB *qcow2_aio_writev(BlockDriverState *bs,
-                                          int64_t sector_num,
-                                          QEMUIOVector *qiov, int nb_sectors,
-                                          BlockDriverCompletionFunc *cb,
-                                          void *opaque)
+static int qcow2_co_writev(BlockDriverState *bs,
+                           int64_t sector_num,
+                           int nb_sectors,
+                           QEMUIOVector *qiov)
 {
     BDRVQcowState *s = bs->opaque;
     QCowAIOCB *acb;
     int ret;
 
+    acb = qcow2_aio_setup(bs, sector_num, qiov, nb_sectors, NULL, NULL, 1);
     s->cluster_cache_offset = -1; /* disable compressed cache */
 
-    acb = qcow2_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
-    if (!acb)
-        return NULL;
+    qemu_co_mutex_lock(&s->lock);
+    do {
+        ret = qcow2_aio_write_cb(acb);
+    } while (ret > 0);
+    qemu_co_mutex_unlock(&s->lock);
 
-    ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb);
-    if (ret < 0) {
-        qemu_iovec_destroy(&acb->hd_qiov);
-        qemu_aio_release(acb);
-        return NULL;
-    }
+    qemu_iovec_destroy(&acb->hd_qiov);
+    qemu_aio_release(acb);
 
-    return &acb->common;
+    return ret;
 }
 
 static void qcow2_close(BlockDriverState *bs)
@@ -881,7 +813,7 @@ static int preallocate(BlockDriverState *bs)
 
     nb_sectors = bdrv_getlength(bs) >> 9;
     offset = 0;
-    QLIST_INIT(&meta.dependent_requests);
+    qemu_co_queue_init(&meta.dependent_requests);
     meta.cluster_offset = 0;
 
     while (nb_sectors) {
@@ -899,7 +831,7 @@ static int preallocate(BlockDriverState *bs)
 
         /* There are no dependent requests, but we need to remove our request
          * from the list of in-flight requests */
-        run_dependent_requests(&meta);
+        run_dependent_requests(bs->opaque, &meta);
 
         /* TODO Preallocate data if requested */
 
@@ -1387,8 +1319,8 @@ static BlockDriver bdrv_qcow2 = {
     .bdrv_set_key       = qcow2_set_key,
     .bdrv_make_empty    = qcow2_make_empty,
 
-    .bdrv_aio_readv     = qcow2_aio_readv,
-    .bdrv_aio_writev    = qcow2_aio_writev,
+    .bdrv_co_readv      = qcow2_co_readv,
+    .bdrv_co_writev     = qcow2_co_writev,
     .bdrv_aio_flush     = qcow2_aio_flush,
 
     .bdrv_discard           = qcow2_discard,
diff --git a/block/qcow2.h b/block/qcow2.h
index 6a0a21b..de23abe 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -26,6 +26,7 @@
 #define BLOCK_QCOW2_H
 
 #include "aes.h"
+#include "qemu-coroutine.h"
 
 //#define DEBUG_ALLOC
 //#define DEBUG_ALLOC2
@@ -114,6 +115,8 @@ typedef struct BDRVQcowState {
     int64_t free_cluster_index;
     int64_t free_byte_offset;
 
+    CoMutex lock;
+
     uint32_t crypt_method; /* current crypt method, 0 if no key yet */
     uint32_t crypt_method_header;
     AES_KEY aes_encrypt_key;
@@ -146,7 +149,7 @@ typedef struct QCowL2Meta
     int nb_available;
     int nb_clusters;
     struct QCowL2Meta *depends_on;
-    QLIST_HEAD(QCowAioDependencies, QCowAIOCB) dependent_requests;
+    CoQueue dependent_requests;
 
     QLIST_ENTRY(QCowL2Meta) next_in_flight;
 } QCowL2Meta;
commit b96e92470ab4a87268e8b174602eaea6c508003b
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Thu Jun 30 17:56:46 2011 +0200

    coroutines: Locks
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/Makefile.objs b/Makefile.objs
index 9549e2a..89ca361 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -12,7 +12,7 @@ oslib-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o
 
 #######################################################################
 # coroutines
-coroutine-obj-y = qemu-coroutine.o
+coroutine-obj-y = qemu-coroutine.o qemu-coroutine-lock.o
 ifeq ($(CONFIG_UCONTEXT_COROUTINE),y)
 coroutine-obj-$(CONFIG_POSIX) += coroutine-ucontext.o
 else
diff --git a/qemu-coroutine-int.h b/qemu-coroutine-int.h
index 64915c2..d495615 100644
--- a/qemu-coroutine-int.h
+++ b/qemu-coroutine-int.h
@@ -38,6 +38,7 @@ struct Coroutine {
     void *entry_arg;
     Coroutine *caller;
     QLIST_ENTRY(Coroutine) pool_next;
+    QTAILQ_ENTRY(Coroutine) co_queue_next;
 };
 
 Coroutine *qemu_coroutine_new(void);
diff --git a/qemu-coroutine-lock.c b/qemu-coroutine-lock.c
new file mode 100644
index 0000000..abaa1f7
--- /dev/null
+++ b/qemu-coroutine-lock.c
@@ -0,0 +1,124 @@
+/*
+ * coroutine queues and locks
+ *
+ * Copyright (c) 2011 Kevin Wolf <kwolf at redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu-common.h"
+#include "qemu-coroutine.h"
+#include "qemu-coroutine-int.h"
+#include "qemu-queue.h"
+#include "trace.h"
+
+static QTAILQ_HEAD(, Coroutine) unlock_bh_queue =
+    QTAILQ_HEAD_INITIALIZER(unlock_bh_queue);
+
+struct unlock_bh {
+    QEMUBH *bh;
+};
+
+static void qemu_co_queue_next_bh(void *opaque)
+{
+    struct unlock_bh *unlock_bh = opaque;
+    Coroutine *next;
+
+    trace_qemu_co_queue_next_bh();
+    while ((next = QTAILQ_FIRST(&unlock_bh_queue))) {
+        QTAILQ_REMOVE(&unlock_bh_queue, next, co_queue_next);
+        qemu_coroutine_enter(next, NULL);
+    }
+
+    qemu_bh_delete(unlock_bh->bh);
+    qemu_free(unlock_bh);
+}
+
+void qemu_co_queue_init(CoQueue *queue)
+{
+    QTAILQ_INIT(&queue->entries);
+}
+
+void coroutine_fn qemu_co_queue_wait(CoQueue *queue)
+{
+    Coroutine *self = qemu_coroutine_self();
+    QTAILQ_INSERT_TAIL(&queue->entries, self, co_queue_next);
+    qemu_coroutine_yield();
+    assert(qemu_in_coroutine());
+}
+
+bool qemu_co_queue_next(CoQueue *queue)
+{
+    struct unlock_bh *unlock_bh;
+    Coroutine *next;
+
+    next = QTAILQ_FIRST(&queue->entries);
+    if (next) {
+        QTAILQ_REMOVE(&queue->entries, next, co_queue_next);
+        QTAILQ_INSERT_TAIL(&unlock_bh_queue, next, co_queue_next);
+        trace_qemu_co_queue_next(next);
+
+        unlock_bh = qemu_malloc(sizeof(*unlock_bh));
+        unlock_bh->bh = qemu_bh_new(qemu_co_queue_next_bh, unlock_bh);
+        qemu_bh_schedule(unlock_bh->bh);
+    }
+
+    return (next != NULL);
+}
+
+bool qemu_co_queue_empty(CoQueue *queue)
+{
+    return (QTAILQ_FIRST(&queue->entries) == NULL);
+}
+
+void qemu_co_mutex_init(CoMutex *mutex)
+{
+    memset(mutex, 0, sizeof(*mutex));
+    qemu_co_queue_init(&mutex->queue);
+}
+
+void coroutine_fn qemu_co_mutex_lock(CoMutex *mutex)
+{
+    Coroutine *self = qemu_coroutine_self();
+
+    trace_qemu_co_mutex_lock_entry(mutex, self);
+
+    while (mutex->locked) {
+        qemu_co_queue_wait(&mutex->queue);
+    }
+
+    mutex->locked = true;
+
+    trace_qemu_co_mutex_lock_return(mutex, self);
+}
+
+void coroutine_fn qemu_co_mutex_unlock(CoMutex *mutex)
+{
+    Coroutine *self = qemu_coroutine_self();
+
+    trace_qemu_co_mutex_unlock_entry(mutex, self);
+
+    assert(mutex->locked == true);
+    assert(qemu_in_coroutine());
+
+    mutex->locked = false;
+    qemu_co_queue_next(&mutex->queue);
+
+    trace_qemu_co_mutex_unlock_return(mutex, self);
+}
diff --git a/qemu-coroutine.h b/qemu-coroutine.h
index 08255c7..2f2fd95 100644
--- a/qemu-coroutine.h
+++ b/qemu-coroutine.h
@@ -5,6 +5,7 @@
  *
  * Authors:
  *  Stefan Hajnoczi    <stefanha at linux.vnet.ibm.com>
+ *  Kevin Wolf         <kwolf at redhat.com>
  *
  * This work is licensed under the terms of the GNU LGPL, version 2 or later.
  * See the COPYING.LIB file in the top-level directory.
@@ -15,6 +16,7 @@
 #define QEMU_COROUTINE_H
 
 #include <stdbool.h>
+#include "qemu-queue.h"
 
 /**
  * Coroutines are a mechanism for stack switching and can be used for
@@ -92,4 +94,66 @@ Coroutine *coroutine_fn qemu_coroutine_self(void);
  */
 bool qemu_in_coroutine(void);
 
+
+
+/**
+ * CoQueues are a mechanism to queue coroutines in order to continue executing
+ * them later. They provide the fundamental primitives on which coroutine locks
+ * are built.
+ */
+typedef struct CoQueue {
+    QTAILQ_HEAD(, Coroutine) entries;
+} CoQueue;
+
+/**
+ * Initialise a CoQueue. This must be called before any other operation is used
+ * on the CoQueue.
+ */
+void qemu_co_queue_init(CoQueue *queue);
+
+/**
+ * Adds the current coroutine to the CoQueue and transfers control to the
+ * caller of the coroutine.
+ */
+void coroutine_fn qemu_co_queue_wait(CoQueue *queue);
+
+/**
+ * Restarts the next coroutine in the CoQueue and removes it from the queue.
+ *
+ * Returns true if a coroutine was restarted, false if the queue is empty.
+ */
+bool qemu_co_queue_next(CoQueue *queue);
+
+/**
+ * Checks if the CoQueue is empty.
+ */
+bool qemu_co_queue_empty(CoQueue *queue);
+
+
+/**
+ * Provides a mutex that can be used to synchronise coroutines
+ */
+typedef struct CoMutex {
+    bool locked;
+    CoQueue queue;
+} CoMutex;
+
+/**
+ * Initialises a CoMutex. This must be called before any other operation is used
+ * on the CoMutex.
+ */
+void qemu_co_mutex_init(CoMutex *mutex);
+
+/**
+ * Locks the mutex. If the lock cannot be taken immediately, control is
+ * transferred to the caller of the current coroutine.
+ */
+void coroutine_fn qemu_co_mutex_lock(CoMutex *mutex);
+
+/**
+ * Unlocks the mutex and schedules the next coroutine that was waiting for this
+ * lock to be run.
+ */
+void coroutine_fn qemu_co_mutex_unlock(CoMutex *mutex);
+
 #endif /* QEMU_COROUTINE_H */
diff --git a/trace-events b/trace-events
index bc9be30..19d31e3 100644
--- a/trace-events
+++ b/trace-events
@@ -433,3 +433,11 @@ disable xen_platform_log(char *s) "xen platform: %s"
 disable qemu_coroutine_enter(void *from, void *to, void *opaque) "from %p to %p opaque %p"
 disable qemu_coroutine_yield(void *from, void *to) "from %p to %p"
 disable qemu_coroutine_terminate(void *co) "self %p"
+
+# qemu-coroutine-lock.c
+disable qemu_co_queue_next_bh(void) ""
+disable qemu_co_queue_next(void *next) "next %p"
+disable qemu_co_mutex_lock_entry(void *mutex, void *self) "mutex %p self %p"
+disable qemu_co_mutex_lock_return(void *mutex, void *self) "mutex %p self %p"
+disable qemu_co_mutex_unlock_entry(void *mutex, void *self) "mutex %p self %p"
+disable qemu_co_mutex_unlock_return(void *mutex, void *self) "mutex %p self %p"
commit f9f05dc58c50d19ad762e6c1ce6b5def9814a4ed
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Fri Jul 15 13:50:26 2011 +0200

    block: Add bdrv_co_readv/writev emulation
    
    In order to be able to call bdrv_co_readv/writev for drivers that don't
    implement the functions natively, add an emulation that uses the AIO functions
    to implement them.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index 0d973e6..e6abea8 100644
--- a/block.c
+++ b/block.c
@@ -64,6 +64,12 @@ static BlockDriverAIOCB *bdrv_co_aio_readv_em(BlockDriverState *bs,
 static BlockDriverAIOCB *bdrv_co_aio_writev_em(BlockDriverState *bs,
         int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
         BlockDriverCompletionFunc *cb, void *opaque);
+static int coroutine_fn bdrv_co_readv_em(BlockDriverState *bs,
+                                         int64_t sector_num, int nb_sectors,
+                                         QEMUIOVector *iov);
+static int coroutine_fn bdrv_co_writev_em(BlockDriverState *bs,
+                                         int64_t sector_num, int nb_sectors,
+                                         QEMUIOVector *iov);
 
 static QTAILQ_HEAD(, BlockDriverState) bdrv_states =
     QTAILQ_HEAD_INITIALIZER(bdrv_states);
@@ -182,14 +188,19 @@ void bdrv_register(BlockDriver *bdrv)
         bdrv->bdrv_aio_writev = bdrv_co_aio_writev_em;
         bdrv->bdrv_read = bdrv_read_em;
         bdrv->bdrv_write = bdrv_write_em;
-     } else if (!bdrv->bdrv_aio_readv) {
-        /* add AIO emulation layer */
-        bdrv->bdrv_aio_readv = bdrv_aio_readv_em;
-        bdrv->bdrv_aio_writev = bdrv_aio_writev_em;
-    } else if (!bdrv->bdrv_read) {
-        /* add synchronous IO emulation layer */
-        bdrv->bdrv_read = bdrv_read_em;
-        bdrv->bdrv_write = bdrv_write_em;
+     } else {
+        bdrv->bdrv_co_readv = bdrv_co_readv_em;
+        bdrv->bdrv_co_writev = bdrv_co_writev_em;
+
+        if (!bdrv->bdrv_aio_readv) {
+            /* add AIO emulation layer */
+            bdrv->bdrv_aio_readv = bdrv_aio_readv_em;
+            bdrv->bdrv_aio_writev = bdrv_aio_writev_em;
+        } else if (!bdrv->bdrv_read) {
+            /* add synchronous IO emulation layer */
+            bdrv->bdrv_read = bdrv_read_em;
+            bdrv->bdrv_write = bdrv_write_em;
+        }
     }
 
     if (!bdrv->bdrv_aio_flush)
@@ -2856,6 +2867,62 @@ void qemu_aio_release(void *p)
 }
 
 /**************************************************************/
+/* Coroutine block device emulation */
+
+typedef struct CoroutineIOCompletion {
+    Coroutine *coroutine;
+    int ret;
+} CoroutineIOCompletion;
+
+static void bdrv_co_io_em_complete(void *opaque, int ret)
+{
+    CoroutineIOCompletion *co = opaque;
+
+    co->ret = ret;
+    qemu_coroutine_enter(co->coroutine, NULL);
+}
+
+static int coroutine_fn bdrv_co_io_em(BlockDriverState *bs, int64_t sector_num,
+                                      int nb_sectors, QEMUIOVector *iov,
+                                      bool is_write)
+{
+    CoroutineIOCompletion co = {
+        .coroutine = qemu_coroutine_self(),
+    };
+    BlockDriverAIOCB *acb;
+
+    if (is_write) {
+        acb = bdrv_aio_writev(bs, sector_num, iov, nb_sectors,
+                              bdrv_co_io_em_complete, &co);
+    } else {
+        acb = bdrv_aio_readv(bs, sector_num, iov, nb_sectors,
+                             bdrv_co_io_em_complete, &co);
+    }
+
+    trace_bdrv_co_io(is_write, acb);
+    if (!acb) {
+        return -EIO;
+    }
+    qemu_coroutine_yield();
+
+    return co.ret;
+}
+
+static int coroutine_fn bdrv_co_readv_em(BlockDriverState *bs,
+                                         int64_t sector_num, int nb_sectors,
+                                         QEMUIOVector *iov)
+{
+    return bdrv_co_io_em(bs, sector_num, nb_sectors, iov, false);
+}
+
+static int coroutine_fn bdrv_co_writev_em(BlockDriverState *bs,
+                                         int64_t sector_num, int nb_sectors,
+                                         QEMUIOVector *iov)
+{
+    return bdrv_co_io_em(bs, sector_num, nb_sectors, iov, true);
+}
+
+/**************************************************************/
 /* removable device support */
 
 /**
diff --git a/trace-events b/trace-events
index 46bceca..bc9be30 100644
--- a/trace-events
+++ b/trace-events
@@ -68,6 +68,7 @@ disable bdrv_aio_writev(void *bs, int64_t sector_num, int nb_sectors, void *opaq
 disable bdrv_set_locked(void *bs, int locked) "bs %p locked %d"
 disable bdrv_co_readv(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
 disable bdrv_co_writev(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
+disable bdrv_co_io(int is_write, void *acb) "is_write %d acb %p"
 
 # hw/virtio-blk.c
 disable virtio_blk_req_complete(void *req, int status) "req %p status %d"
commit 68485420187094c26f86faee5c7f68b5d6a03603
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Thu Jun 30 10:05:46 2011 +0200

    block: Emulate AIO functions with bdrv_co_readv/writev
    
    Use the bdrv_co_readv/writev callbacks to implement bdrv_aio_readv/writev and
    bdrv_read/write if a driver provides the coroutine version instead of the
    synchronous or AIO version.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index 1329299..0d973e6 100644
--- a/block.c
+++ b/block.c
@@ -28,6 +28,7 @@
 #include "block_int.h"
 #include "module.h"
 #include "qemu-objects.h"
+#include "qemu-coroutine.h"
 
 #ifdef CONFIG_BSD
 #include <sys/types.h>
@@ -57,6 +58,12 @@ static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num,
                         uint8_t *buf, int nb_sectors);
 static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
                          const uint8_t *buf, int nb_sectors);
+static BlockDriverAIOCB *bdrv_co_aio_readv_em(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque);
+static BlockDriverAIOCB *bdrv_co_aio_writev_em(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque);
 
 static QTAILQ_HEAD(, BlockDriverState) bdrv_states =
     QTAILQ_HEAD_INITIALIZER(bdrv_states);
@@ -169,7 +176,13 @@ void path_combine(char *dest, int dest_size,
 
 void bdrv_register(BlockDriver *bdrv)
 {
-    if (!bdrv->bdrv_aio_readv) {
+    if (bdrv->bdrv_co_readv) {
+        /* Emulate AIO by coroutines, and sync by AIO */
+        bdrv->bdrv_aio_readv = bdrv_co_aio_readv_em;
+        bdrv->bdrv_aio_writev = bdrv_co_aio_writev_em;
+        bdrv->bdrv_read = bdrv_read_em;
+        bdrv->bdrv_write = bdrv_write_em;
+     } else if (!bdrv->bdrv_aio_readv) {
         /* add AIO emulation layer */
         bdrv->bdrv_aio_readv = bdrv_aio_readv_em;
         bdrv->bdrv_aio_writev = bdrv_aio_writev_em;
@@ -2614,6 +2627,89 @@ static BlockDriverAIOCB *bdrv_aio_writev_em(BlockDriverState *bs,
     return bdrv_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
 }
 
+
+typedef struct BlockDriverAIOCBCoroutine {
+    BlockDriverAIOCB common;
+    BlockRequest req;
+    bool is_write;
+    QEMUBH* bh;
+} BlockDriverAIOCBCoroutine;
+
+static void bdrv_aio_co_cancel_em(BlockDriverAIOCB *blockacb)
+{
+    qemu_aio_flush();
+}
+
+static AIOPool bdrv_em_co_aio_pool = {
+    .aiocb_size         = sizeof(BlockDriverAIOCBCoroutine),
+    .cancel             = bdrv_aio_co_cancel_em,
+};
+
+static void bdrv_co_rw_bh(void *opaque)
+{
+    BlockDriverAIOCBCoroutine *acb = opaque;
+
+    acb->common.cb(acb->common.opaque, acb->req.error);
+    qemu_bh_delete(acb->bh);
+    qemu_aio_release(acb);
+}
+
+static void coroutine_fn bdrv_co_rw(void *opaque)
+{
+    BlockDriverAIOCBCoroutine *acb = opaque;
+    BlockDriverState *bs = acb->common.bs;
+
+    if (!acb->is_write) {
+        acb->req.error = bs->drv->bdrv_co_readv(bs, acb->req.sector,
+            acb->req.nb_sectors, acb->req.qiov);
+    } else {
+        acb->req.error = bs->drv->bdrv_co_writev(bs, acb->req.sector,
+            acb->req.nb_sectors, acb->req.qiov);
+    }
+
+    acb->bh = qemu_bh_new(bdrv_co_rw_bh, acb);
+    qemu_bh_schedule(acb->bh);
+}
+
+static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
+                                               int64_t sector_num,
+                                               QEMUIOVector *qiov,
+                                               int nb_sectors,
+                                               BlockDriverCompletionFunc *cb,
+                                               void *opaque,
+                                               bool is_write)
+{
+    Coroutine *co;
+    BlockDriverAIOCBCoroutine *acb;
+
+    acb = qemu_aio_get(&bdrv_em_co_aio_pool, bs, cb, opaque);
+    acb->req.sector = sector_num;
+    acb->req.nb_sectors = nb_sectors;
+    acb->req.qiov = qiov;
+    acb->is_write = is_write;
+
+    co = qemu_coroutine_create(bdrv_co_rw);
+    qemu_coroutine_enter(co, acb);
+
+    return &acb->common;
+}
+
+static BlockDriverAIOCB *bdrv_co_aio_readv_em(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque,
+                                 false);
+}
+
+static BlockDriverAIOCB *bdrv_co_aio_writev_em(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    return bdrv_co_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque,
+                                 true);
+}
+
 static BlockDriverAIOCB *bdrv_aio_flush_em(BlockDriverState *bs,
         BlockDriverCompletionFunc *cb, void *opaque)
 {
commit da1fa91d6cca8a6d3da9c2b222fa485429db297c
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Thu Jul 14 17:27:13 2011 +0200

    block: Add bdrv_co_readv/writev
    
    Add new block driver callbacks bdrv_co_readv/writev, which work on a
    QEMUIOVector like bdrv_aio_*, but don't need a callback. The function may only
    be called inside a coroutine, so a block driver implementing this interface can
    yield instead of blocking during I/O.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/Makefile.objs b/Makefile.objs
index 5679e1f..9549e2a 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -25,6 +25,7 @@ coroutine-obj-$(CONFIG_WIN32) += coroutine-win32.o
 
 block-obj-y = cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.o async.o
 block-obj-y += nbd.o block.o aio.o aes.o qemu-config.o qemu-progress.o qemu-sockets.o
+block-obj-y += $(coroutine-obj-y)
 block-obj-$(CONFIG_POSIX) += posix-aio-compat.o
 block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
 
@@ -79,7 +80,6 @@ common-obj-y += readline.o console.o cursor.o qemu-error.o
 common-obj-y += $(oslib-obj-y)
 common-obj-$(CONFIG_WIN32) += os-win32.o
 common-obj-$(CONFIG_POSIX) += os-posix.o
-common-obj-y += $(coroutine-obj-y)
 
 common-obj-y += tcg-runtime.o host-utils.o
 common-obj-y += irq.o ioport.o input.o
diff --git a/block.c b/block.c
index 4c66b2c..1329299 100644
--- a/block.c
+++ b/block.c
@@ -1110,6 +1110,51 @@ int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset,
     return 0;
 }
 
+int coroutine_fn bdrv_co_readv(BlockDriverState *bs, int64_t sector_num,
+    int nb_sectors, QEMUIOVector *qiov)
+{
+    BlockDriver *drv = bs->drv;
+
+    trace_bdrv_co_readv(bs, sector_num, nb_sectors);
+
+    if (!drv) {
+        return -ENOMEDIUM;
+    }
+    if (bdrv_check_request(bs, sector_num, nb_sectors)) {
+        return -EIO;
+    }
+
+    return drv->bdrv_co_readv(bs, sector_num, nb_sectors, qiov);
+}
+
+int coroutine_fn bdrv_co_writev(BlockDriverState *bs, int64_t sector_num,
+    int nb_sectors, QEMUIOVector *qiov)
+{
+    BlockDriver *drv = bs->drv;
+
+    trace_bdrv_co_writev(bs, sector_num, nb_sectors);
+
+    if (!bs->drv) {
+        return -ENOMEDIUM;
+    }
+    if (bs->read_only) {
+        return -EACCES;
+    }
+    if (bdrv_check_request(bs, sector_num, nb_sectors)) {
+        return -EIO;
+    }
+
+    if (bs->dirty_bitmap) {
+        set_dirty_bitmap(bs, sector_num, nb_sectors, 1);
+    }
+
+    if (bs->wr_highest_sector < sector_num + nb_sectors - 1) {
+        bs->wr_highest_sector = sector_num + nb_sectors - 1;
+    }
+
+    return drv->bdrv_co_writev(bs, sector_num, nb_sectors, qiov);
+}
+
 /**
  * Truncate file to 'offset' bytes (needed only for file protocols)
  */
diff --git a/block.h b/block.h
index e672bc6..a3bfaaf 100644
--- a/block.h
+++ b/block.h
@@ -4,6 +4,7 @@
 #include "qemu-aio.h"
 #include "qemu-common.h"
 #include "qemu-option.h"
+#include "qemu-coroutine.h"
 #include "qobject.h"
 
 /* block.c */
@@ -85,6 +86,10 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
                 const void *buf, int count);
 int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset,
     const void *buf, int count);
+int coroutine_fn bdrv_co_readv(BlockDriverState *bs, int64_t sector_num,
+    int nb_sectors, QEMUIOVector *qiov);
+int coroutine_fn bdrv_co_writev(BlockDriverState *bs, int64_t sector_num,
+    int nb_sectors, QEMUIOVector *qiov);
 int bdrv_truncate(BlockDriverState *bs, int64_t offset);
 int64_t bdrv_getlength(BlockDriverState *bs);
 int64_t bdrv_get_allocated_file_size(BlockDriverState *bs);
diff --git a/block_int.h b/block_int.h
index efefbee..f6d02b3 100644
--- a/block_int.h
+++ b/block_int.h
@@ -27,6 +27,7 @@
 #include "block.h"
 #include "qemu-option.h"
 #include "qemu-queue.h"
+#include "qemu-coroutine.h"
 
 #define BLOCK_FLAG_ENCRYPT	1
 #define BLOCK_FLAG_COMPAT6	4
@@ -77,6 +78,11 @@ struct BlockDriver {
     int (*bdrv_discard)(BlockDriverState *bs, int64_t sector_num,
                         int nb_sectors);
 
+    int coroutine_fn (*bdrv_co_readv)(BlockDriverState *bs,
+        int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
+    int coroutine_fn (*bdrv_co_writev)(BlockDriverState *bs,
+        int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
+
     int (*bdrv_aio_multiwrite)(BlockDriverState *bs, BlockRequest *reqs,
         int num_reqs);
     int (*bdrv_merge_requests)(BlockDriverState *bs, BlockRequest* a,
diff --git a/trace-events b/trace-events
index 136f775..46bceca 100644
--- a/trace-events
+++ b/trace-events
@@ -66,6 +66,8 @@ disable bdrv_aio_flush(void *bs, void *opaque) "bs %p opaque %p"
 disable bdrv_aio_readv(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
 disable bdrv_aio_writev(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
 disable bdrv_set_locked(void *bs, int locked) "bs %p locked %d"
+disable bdrv_co_readv(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
+disable bdrv_co_writev(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
 
 # hw/virtio-blk.c
 disable virtio_blk_req_complete(void *req, int status) "req %p status %d"
commit 5e3840ce24040cbd1957008489cbc136c43ca391
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Thu May 12 08:27:39 2011 +0100

    coroutine: add test-coroutine --benchmark-lifecycle
    
    Add a microbenchmark for coroutine create, enter, and return (aka
    lifecycle).  This is a useful benchmark because users are expected to
    create many coroutines, one per I/O request for example, and we
    therefore need to provide good performance in that scenario.
    
    To run:
    
      make test-coroutine
      ./test-coroutine --benchmark-lifecycle 20000000
    
    This will do 20,000,000 coroutine create, enter, return iterations and
    print the resulting time.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/test-coroutine.c b/test-coroutine.c
index 9e9d3c9..bf9f3e9 100644
--- a/test-coroutine.c
+++ b/test-coroutine.c
@@ -150,6 +150,33 @@ static void test_lifecycle(void)
     g_assert(done); /* expect done to be true (second time) */
 }
 
+/*
+ * Lifecycle benchmark
+ */
+
+static void coroutine_fn empty_coroutine(void *opaque)
+{
+    /* Do nothing */
+}
+
+static void perf_lifecycle(void)
+{
+    Coroutine *coroutine;
+    unsigned int i, max;
+    double duration;
+
+    max = 1000000;
+
+    g_test_timer_start();
+    for (i = 0; i < max; i++) {
+        coroutine = qemu_coroutine_create(empty_coroutine);
+        qemu_coroutine_enter(coroutine, NULL);
+    }
+    duration = g_test_timer_elapsed();
+
+    g_test_message("Lifecycle %u iterations: %f s\n", max, duration);
+}
+
 int main(int argc, char **argv)
 {
     g_test_init(&argc, &argv, NULL);
@@ -158,5 +185,8 @@ int main(int argc, char **argv)
     g_test_add_func("/basic/nesting", test_nesting);
     g_test_add_func("/basic/self", test_self);
     g_test_add_func("/basic/in_coroutine", test_in_coroutine);
+    if (g_test_perf()) {
+        g_test_add_func("/perf/lifecycle", perf_lifecycle);
+    }
     return g_test_run();
 }
commit aa7ee42ed3b2c196de9f390fc9a5e339dd7417e3
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Tue May 10 10:21:18 2011 +0100

    coroutine: add test-coroutine automated tests
    
    To run automated tests for coroutines:
    
      make test-coroutine
      ./test-coroutine
    
    On success the program terminates with exit status 0.  On failure an
    error message is written to stderr and the program exits with exit
    status 1.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/.gitignore b/.gitignore
index 54835bc..59c343c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,6 +36,7 @@ qemu-io
 qemu-ga
 qemu-monitor.texi
 QMP/qmp-commands.txt
+test-coroutine
 .gdbinit
 *.a
 *.aux
diff --git a/Makefile b/Makefile
index 4855251..2becedc 100644
--- a/Makefile
+++ b/Makefile
@@ -151,7 +151,7 @@ qemu-io$(EXESUF): qemu-io.o cmd.o qemu-tool.o qemu-error.o $(oslib-obj-y) $(trac
 qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
 	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"  GEN   $@")
 
-check-qint.o check-qstring.o check-qdict.o check-qlist.o check-qfloat.o check-qjson.o: $(GENERATED_HEADERS)
+check-qint.o check-qstring.o check-qdict.o check-qlist.o check-qfloat.o check-qjson.o test-coroutine.o: $(GENERATED_HEADERS)
 
 CHECK_PROG_DEPS = qemu-malloc.o $(oslib-obj-y) $(trace-obj-y) qemu-tool.o
 
@@ -161,6 +161,7 @@ check-qdict: check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qlist.o $(C
 check-qlist: check-qlist.o qlist.o qint.o $(CHECK_PROG_DEPS)
 check-qfloat: check-qfloat.o qfloat.o $(CHECK_PROG_DEPS)
 check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o error.o qerror.o qemu-error.o $(CHECK_PROG_DEPS)
+test-coroutine: test-coroutine.o qemu-timer-common.o async.o $(coroutine-obj-y) $(CHECK_PROG_DEPS)
 
 $(qapi-obj-y): $(GENERATED_HEADERS)
 qapi-dir := qapi-generated
diff --git a/test-coroutine.c b/test-coroutine.c
new file mode 100644
index 0000000..9e9d3c9
--- /dev/null
+++ b/test-coroutine.c
@@ -0,0 +1,162 @@
+/*
+ * Coroutine tests
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Stefan Hajnoczi    <stefanha at linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include <glib.h>
+#include "qemu-coroutine.h"
+
+/*
+ * Check that qemu_in_coroutine() works
+ */
+
+static void coroutine_fn verify_in_coroutine(void *opaque)
+{
+    g_assert(qemu_in_coroutine());
+}
+
+static void test_in_coroutine(void)
+{
+    Coroutine *coroutine;
+
+    g_assert(!qemu_in_coroutine());
+
+    coroutine = qemu_coroutine_create(verify_in_coroutine);
+    qemu_coroutine_enter(coroutine, NULL);
+}
+
+/*
+ * Check that qemu_coroutine_self() works
+ */
+
+static void coroutine_fn verify_self(void *opaque)
+{
+    g_assert(qemu_coroutine_self() == opaque);
+}
+
+static void test_self(void)
+{
+    Coroutine *coroutine;
+
+    coroutine = qemu_coroutine_create(verify_self);
+    qemu_coroutine_enter(coroutine, coroutine);
+}
+
+/*
+ * Check that coroutines may nest multiple levels
+ */
+
+typedef struct {
+    unsigned int n_enter;   /* num coroutines entered */
+    unsigned int n_return;  /* num coroutines returned */
+    unsigned int max;       /* maximum level of nesting */
+} NestData;
+
+static void coroutine_fn nest(void *opaque)
+{
+    NestData *nd = opaque;
+
+    nd->n_enter++;
+
+    if (nd->n_enter < nd->max) {
+        Coroutine *child;
+
+        child = qemu_coroutine_create(nest);
+        qemu_coroutine_enter(child, nd);
+    }
+
+    nd->n_return++;
+}
+
+static void test_nesting(void)
+{
+    Coroutine *root;
+    NestData nd = {
+        .n_enter  = 0,
+        .n_return = 0,
+        .max      = 128,
+    };
+
+    root = qemu_coroutine_create(nest);
+    qemu_coroutine_enter(root, &nd);
+
+    /* Must enter and return from max nesting level */
+    g_assert_cmpint(nd.n_enter, ==, nd.max);
+    g_assert_cmpint(nd.n_return, ==, nd.max);
+}
+
+/*
+ * Check that yield/enter transfer control correctly
+ */
+
+static void coroutine_fn yield_5_times(void *opaque)
+{
+    bool *done = opaque;
+    int i;
+
+    for (i = 0; i < 5; i++) {
+        qemu_coroutine_yield();
+    }
+    *done = true;
+}
+
+static void test_yield(void)
+{
+    Coroutine *coroutine;
+    bool done = false;
+    int i = -1; /* one extra time to return from coroutine */
+
+    coroutine = qemu_coroutine_create(yield_5_times);
+    while (!done) {
+        qemu_coroutine_enter(coroutine, &done);
+        i++;
+    }
+    g_assert_cmpint(i, ==, 5); /* coroutine must yield 5 times */
+}
+
+/*
+ * Check that creation, enter, and return work
+ */
+
+static void coroutine_fn set_and_exit(void *opaque)
+{
+    bool *done = opaque;
+
+    *done = true;
+}
+
+static void test_lifecycle(void)
+{
+    Coroutine *coroutine;
+    bool done = false;
+
+    /* Create, enter, and return from coroutine */
+    coroutine = qemu_coroutine_create(set_and_exit);
+    qemu_coroutine_enter(coroutine, &done);
+    g_assert(done); /* expect done to be true (first time) */
+
+    /* Repeat to check that no state affects this test */
+    done = false;
+    coroutine = qemu_coroutine_create(set_and_exit);
+    qemu_coroutine_enter(coroutine, &done);
+    g_assert(done); /* expect done to be true (second time) */
+}
+
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+    g_test_add_func("/basic/lifecycle", test_lifecycle);
+    g_test_add_func("/basic/yield", test_yield);
+    g_test_add_func("/basic/nesting", test_nesting);
+    g_test_add_func("/basic/self", test_self);
+    g_test_add_func("/basic/in_coroutine", test_in_coroutine);
+    return g_test_run();
+}
commit 4995f0d6212c65312f746c0d0076429f25e68415
Author: Alon Levy <alevy at redhat.com>
Date:   Thu Jul 28 12:34:13 2011 +0300

    libcacard: use INSTALL_DATA for data
    
    Signed-off-by: Alon Levy <alevy at redhat.com>

diff --git a/libcacard/Makefile b/libcacard/Makefile
index bc34bf2..5cd7594 100644
--- a/libcacard/Makefile
+++ b/libcacard/Makefile
@@ -55,9 +55,8 @@ install-libcacard: libcacard.pc libcacard.la vscclient
 	$(INSTALL_DIR) "$(DESTDIR)$(bindir)"
 	libtool --mode=install $(INSTALL_PROG) vscclient "$(DESTDIR)$(bindir)"
 	libtool --mode=install $(INSTALL_PROG) libcacard.la "$(DESTDIR)$(libdir)"
-	libtool --mode=install $(INSTALL_PROG) libcacard.pc "$(DESTDIR)$(libdir)/pkgconfig"
+	libtool --mode=install $(INSTALL_DATA) libcacard.pc "$(DESTDIR)$(libdir)/pkgconfig"
 	for inc in *.h; do \
-		libtool --mode=install $(INSTALL_PROG) $(libcacard_srcpath)/$$inc "$(DESTDIR)$(libcacard_includedir)"; \
+		libtool --mode=install $(INSTALL_DATA) $(libcacard_srcpath)/$$inc "$(DESTDIR)$(libcacard_includedir)"; \
 	done
-
 endif
commit 67494323f2c782fe3e65c60529fe9dfa613fc500
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Mon Aug 1 21:26:03 2011 +0000

    Sparc: fix non-faulting unassigned memory accesses
    
    Commit b14ef7c9ab41ea824c3ccadb070ad95567cca84e
    introduced cpu_unassigned_access() function. On Sparc,
    the function does not restore AREG0 used for global CPUState
    on function exit, causing bugs with non-faulting unassigned
    memory accesses. Alpha, Microblaze and MIPS are not affected.
    
    Fix by restoring AREG0 on exit. Remove excess saving by
    do_unassigned_access() functions.
    
    Also ignore unassigned accesses outside of CPU context.
    
    Reported-by: Bob Breuer <breuerr at mc.net>
    Tested-by: Bob Breuer <breuerr at mc.net>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
index c1c4d4b..5aeca2b 100644
--- a/target-sparc/op_helper.c
+++ b/target-sparc/op_helper.c
@@ -4252,13 +4252,8 @@ void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
 static void do_unassigned_access(target_phys_addr_t addr, int is_write,
                                  int is_exec, int is_asi, int size)
 {
-    CPUState *saved_env;
     int fault_type;
 
-    /* XXX: hack to restore env in all cases, even if not called from
-       generated code */
-    saved_env = env;
-    env = cpu_single_env;
 #ifdef DEBUG_UNASSIGNED
     if (is_asi)
         printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx
@@ -4306,8 +4301,6 @@ static void do_unassigned_access(target_phys_addr_t addr, int is_write,
     if (env->mmuregs[0] & MMU_NF) {
         tlb_flush(env, 1);
     }
-
-    env = saved_env;
 }
 #endif
 #else
@@ -4319,13 +4312,6 @@ static void do_unassigned_access(target_phys_addr_t addr, int is_write,
                                  int is_exec, int is_asi, int size)
 #endif
 {
-    CPUState *saved_env;
-
-    /* XXX: hack to restore env in all cases, even if not called from
-       generated code */
-    saved_env = env;
-    env = cpu_single_env;
-
 #ifdef DEBUG_UNASSIGNED
     printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx
            "\n", addr, env->pc);
@@ -4335,8 +4321,6 @@ static void do_unassigned_access(target_phys_addr_t addr, int is_write,
         raise_exception(TT_CODE_ACCESS);
     else
         raise_exception(TT_DATA_ACCESS);
-
-    env = saved_env;
 }
 #endif
 
@@ -4370,7 +4354,14 @@ void helper_tick_set_limit(void *opaque, uint64_t limit)
 void cpu_unassigned_access(CPUState *env1, target_phys_addr_t addr,
                            int is_write, int is_exec, int is_asi, int size)
 {
+    CPUState *saved_env;
+
+    saved_env = env;
     env = env1;
-    do_unassigned_access(addr, is_write, is_exec, is_asi, size);
+    /* Ignore unassigned accesses outside of CPU context */
+    if (env1) {
+        do_unassigned_access(addr, is_write, is_exec, is_asi, size);
+    }
+    env = saved_env;
 }
 #endif
commit e21a298a7b7a5c5e8edc4912dec3b497497c347d
Author: Alon Levy <alevy at redhat.com>
Date:   Wed Jul 20 12:20:57 2011 +0300

    qxl: only disallow specific io's in vga mode
    
    Since the driver is still in operation even after moving to UNDEFINED, i.e.
    by destroying primary in any way.
    
    Signed-off-by: Alon Levy <alevy at redhat.com>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/qxl.c b/hw/qxl.c
index c50eaf9..23e3240 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -1055,8 +1055,9 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
     case QXL_IO_LOG:
         break;
     default:
-        if (d->mode == QXL_MODE_NATIVE || d->mode == QXL_MODE_COMPAT)
+        if (d->mode != QXL_MODE_VGA) {
             break;
+        }
         dprint(d, 1, "%s: unexpected port 0x%x (%s) in vga mode\n",
             __func__, io_port, io_port_to_string(io_port));
         return;
commit 7635392ce6844702b4e0faadfa558a6972e16098
Author: Alon Levy <alevy at redhat.com>
Date:   Wed Jul 20 12:20:56 2011 +0300

    qxl: make qxl_guest_bug take variable arguments
    
    Signed-off-by: Alon Levy <alevy at redhat.com>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/qxl.c b/hw/qxl.c
index 28c8b5d..c50eaf9 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -125,13 +125,18 @@ static void qxl_reset_memslots(PCIQXLDevice *d);
 static void qxl_reset_surfaces(PCIQXLDevice *d);
 static void qxl_ring_set_dirty(PCIQXLDevice *qxl);
 
-void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg)
+void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...)
 {
 #if SPICE_INTERFACE_QXL_MINOR >= 1
     qxl_send_events(qxl, QXL_INTERRUPT_ERROR);
 #endif
     if (qxl->guestdebug) {
-        fprintf(stderr, "qxl-%d: guest bug: %s\n", qxl->id, msg);
+        va_list ap;
+        va_start(ap, msg);
+        fprintf(stderr, "qxl-%d: guest bug: ", qxl->id);
+        vfprintf(stderr, msg, ap);
+        fprintf(stderr, "\n");
+        va_end(ap);
     }
 }
 
diff --git a/hw/qxl.h b/hw/qxl.h
index 5db9aae..32ca5a0 100644
--- a/hw/qxl.h
+++ b/hw/qxl.h
@@ -99,7 +99,7 @@ typedef struct PCIQXLDevice {
 
 /* qxl.c */
 void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
-void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg);
+void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...);
 
 void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
                            struct QXLRect *area, struct QXLRect *dirty_rects,
commit 2bce0400579f58ccb33d201cde9e63c39750faf4
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Jul 20 12:20:55 2011 +0300

    qxl: error handling fixes and cleanups.
    
    Add qxl_guest_bug() function which is supposed to be called in case
    sanity checks of guest requests fail.  It raises an error IRQ and
    logs a message in case guest debugging is enabled.
    
    Make PANIC_ON() abort instead of exit.  That macro should be used
    for qemu bugs only, any guest-triggerable stuff should use the new
    qxl_guest_bug() function instead.
    
    Convert a few easy cases from PANIC_ON() to qxl_guest_bug() to
    show intended usage.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/qxl.c b/hw/qxl.c
index 6e66021..28c8b5d 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -125,6 +125,16 @@ static void qxl_reset_memslots(PCIQXLDevice *d);
 static void qxl_reset_surfaces(PCIQXLDevice *d);
 static void qxl_ring_set_dirty(PCIQXLDevice *qxl);
 
+void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg)
+{
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+    qxl_send_events(qxl, QXL_INTERRUPT_ERROR);
+#endif
+    if (qxl->guestdebug) {
+        fprintf(stderr, "qxl-%d: guest bug: %s\n", qxl->id, msg);
+    }
+}
+
 
 void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
                            struct QXLRect *area, struct QXLRect *dirty_rects,
@@ -1091,22 +1101,38 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
         qxl_hard_reset(d, 0);
         break;
     case QXL_IO_MEMSLOT_ADD:
-        PANIC_ON(val >= NUM_MEMSLOTS);
-        PANIC_ON(d->guest_slots[val].active);
+        if (val >= NUM_MEMSLOTS) {
+            qxl_guest_bug(d, "QXL_IO_MEMSLOT_ADD: val out of range");
+            break;
+        }
+        if (d->guest_slots[val].active) {
+            qxl_guest_bug(d, "QXL_IO_MEMSLOT_ADD: memory slot already active");
+            break;
+        }
         d->guest_slots[val].slot = d->ram->mem_slot;
         qxl_add_memslot(d, val, 0);
         break;
     case QXL_IO_MEMSLOT_DEL:
+        if (val >= NUM_MEMSLOTS) {
+            qxl_guest_bug(d, "QXL_IO_MEMSLOT_DEL: val out of range");
+            break;
+        }
         qxl_del_memslot(d, val);
         break;
     case QXL_IO_CREATE_PRIMARY:
-        PANIC_ON(val != 0);
+        if (val != 0) {
+            qxl_guest_bug(d, "QXL_IO_CREATE_PRIMARY: val != 0");
+            break;
+        }
         dprint(d, 1, "QXL_IO_CREATE_PRIMARY\n");
         d->guest_primary.surface = d->ram->create_surface;
         qxl_create_guest_primary(d, 0);
         break;
     case QXL_IO_DESTROY_PRIMARY:
-        PANIC_ON(val != 0);
+        if (val != 0) {
+            qxl_guest_bug(d, "QXL_IO_DESTROY_PRIMARY: val != 0");
+            break;
+        }
         dprint(d, 1, "QXL_IO_DESTROY_PRIMARY (%s)\n", qxl_mode_to_string(d->mode));
         qxl_destroy_primary(d);
         break;
diff --git a/hw/qxl.h b/hw/qxl.h
index 5d0e85e..5db9aae 100644
--- a/hw/qxl.h
+++ b/hw/qxl.h
@@ -86,7 +86,7 @@ typedef struct PCIQXLDevice {
 
 #define PANIC_ON(x) if ((x)) {                         \
     printf("%s: PANIC %s failed\n", __FUNCTION__, #x); \
-    exit(-1);                                          \
+    abort();                                           \
 }
 
 #define dprint(_qxl, _level, _fmt, ...)                                 \
@@ -99,6 +99,7 @@ typedef struct PCIQXLDevice {
 
 /* qxl.c */
 void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
+void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg);
 
 void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
                            struct QXLRect *area, struct QXLRect *dirty_rects,
commit 8b92e2989eddaca0bef5076135d2dee3c06f6700
Author: Alon Levy <alevy at redhat.com>
Date:   Wed Jul 20 12:20:54 2011 +0300

    qxl: add io_port_to_string
    
    Signed-off-by: Alon Levy <alevy at redhat.com>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/qxl.c b/hw/qxl.c
index 416bd48..6e66021 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -409,6 +409,43 @@ static const char *qxl_mode_to_string(int mode)
     return "INVALID";
 }
 
+static const char *io_port_to_string(uint32_t io_port)
+{
+    if (io_port >= QXL_IO_RANGE_SIZE) {
+        return "out of range";
+    }
+    static const char *io_port_to_string[QXL_IO_RANGE_SIZE + 1] = {
+        [QXL_IO_NOTIFY_CMD]             = "QXL_IO_NOTIFY_CMD",
+        [QXL_IO_NOTIFY_CURSOR]          = "QXL_IO_NOTIFY_CURSOR",
+        [QXL_IO_UPDATE_AREA]            = "QXL_IO_UPDATE_AREA",
+        [QXL_IO_UPDATE_IRQ]             = "QXL_IO_UPDATE_IRQ",
+        [QXL_IO_NOTIFY_OOM]             = "QXL_IO_NOTIFY_OOM",
+        [QXL_IO_RESET]                  = "QXL_IO_RESET",
+        [QXL_IO_SET_MODE]               = "QXL_IO_SET_MODE",
+        [QXL_IO_LOG]                    = "QXL_IO_LOG",
+        [QXL_IO_MEMSLOT_ADD]            = "QXL_IO_MEMSLOT_ADD",
+        [QXL_IO_MEMSLOT_DEL]            = "QXL_IO_MEMSLOT_DEL",
+        [QXL_IO_DETACH_PRIMARY]         = "QXL_IO_DETACH_PRIMARY",
+        [QXL_IO_ATTACH_PRIMARY]         = "QXL_IO_ATTACH_PRIMARY",
+        [QXL_IO_CREATE_PRIMARY]         = "QXL_IO_CREATE_PRIMARY",
+        [QXL_IO_DESTROY_PRIMARY]        = "QXL_IO_DESTROY_PRIMARY",
+        [QXL_IO_DESTROY_SURFACE_WAIT]   = "QXL_IO_DESTROY_SURFACE_WAIT",
+        [QXL_IO_DESTROY_ALL_SURFACES]   = "QXL_IO_DESTROY_ALL_SURFACES",
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+        [QXL_IO_UPDATE_AREA_ASYNC]      = "QXL_IO_UPDATE_AREA_ASYNC",
+        [QXL_IO_MEMSLOT_ADD_ASYNC]      = "QXL_IO_MEMSLOT_ADD_ASYNC",
+        [QXL_IO_CREATE_PRIMARY_ASYNC]   = "QXL_IO_CREATE_PRIMARY_ASYNC",
+        [QXL_IO_DESTROY_PRIMARY_ASYNC]  = "QXL_IO_DESTROY_PRIMARY_ASYNC",
+        [QXL_IO_DESTROY_SURFACE_ASYNC]  = "QXL_IO_DESTROY_SURFACE_ASYNC",
+        [QXL_IO_DESTROY_ALL_SURFACES_ASYNC]
+                                        = "QXL_IO_DESTROY_ALL_SURFACES_ASYNC",
+        [QXL_IO_FLUSH_SURFACES_ASYNC]   = "QXL_IO_FLUSH_SURFACES_ASYNC",
+        [QXL_IO_FLUSH_RELEASE]          = "QXL_IO_FLUSH_RELEASE",
+#endif
+    };
+    return io_port_to_string[io_port];
+}
+
 /* called from spice server thread context only */
 static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
 {
@@ -1005,7 +1042,8 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
     default:
         if (d->mode == QXL_MODE_NATIVE || d->mode == QXL_MODE_COMPAT)
             break;
-        dprint(d, 1, "%s: unexpected port 0x%x in vga mode\n", __FUNCTION__, io_port);
+        dprint(d, 1, "%s: unexpected port 0x%x (%s) in vga mode\n",
+            __func__, io_port, io_port_to_string(io_port));
         return;
     }
 
commit 14898cf6e9994319e7947b223f637f964f9256e0
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Jul 20 12:20:53 2011 +0300

    qxl: fix surface tracking & locking
    
    Surface tracking needs proper locking since it is used from vcpu and spice
    worker threads, add it.  Also reset the surface counter when zapping all
    surfaces.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/qxl.c b/hw/qxl.c
index 803a364..416bd48 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -137,7 +137,12 @@ void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
 
 void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id)
 {
+    qemu_mutex_lock(&qxl->track_lock);
+    PANIC_ON(id >= NUM_SURFACES);
     qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id);
+    qxl->guest_surfaces.cmds[id] = 0;
+    qxl->guest_surfaces.count--;
+    qemu_mutex_unlock(&qxl->track_lock);
 }
 
 void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
@@ -158,7 +163,11 @@ void qxl_spice_reset_memslots(PCIQXLDevice *qxl)
 
 void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl)
 {
+    qemu_mutex_lock(&qxl->track_lock);
     qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker);
+    memset(&qxl->guest_surfaces.cmds, 0, sizeof(qxl->guest_surfaces.cmds));
+    qxl->guest_surfaces.count = 0;
+    qemu_mutex_unlock(&qxl->track_lock);
 }
 
 void qxl_spice_reset_image_cache(PCIQXLDevice *qxl)
@@ -317,6 +326,7 @@ static void qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext)
         QXLSurfaceCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
         uint32_t id = le32_to_cpu(cmd->surface_id);
         PANIC_ON(id >= NUM_SURFACES);
+        qemu_mutex_lock(&qxl->track_lock);
         if (cmd->type == QXL_SURFACE_CMD_CREATE) {
             qxl->guest_surfaces.cmds[id] = ext->cmd.data;
             qxl->guest_surfaces.count++;
@@ -327,6 +337,7 @@ static void qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext)
             qxl->guest_surfaces.cmds[id] = 0;
             qxl->guest_surfaces.count--;
         }
+        qemu_mutex_unlock(&qxl->track_lock);
         break;
     }
     case QXL_CMD_CURSOR:
@@ -863,7 +874,6 @@ static void qxl_reset_surfaces(PCIQXLDevice *d)
     dprint(d, 1, "%s:\n", __FUNCTION__);
     d->mode = QXL_MODE_UNDEFINED;
     qxl_spice_destroy_surfaces(d);
-    memset(&d->guest_surfaces.cmds, 0, sizeof(d->guest_surfaces.cmds));
 }
 
 /* called from spice server thread context only */
@@ -1283,6 +1293,7 @@ static int qxl_init_common(PCIQXLDevice *qxl)
     qxl->generation = 1;
     qxl->num_memslots = NUM_MEMSLOTS;
     qxl->num_surfaces = NUM_SURFACES;
+    qemu_mutex_init(&qxl->track_lock);
 
     switch (qxl->revision) {
     case 1: /* spice 0.4 -- qxl-1 */
diff --git a/hw/qxl.h b/hw/qxl.h
index e62b9d0..5d0e85e 100644
--- a/hw/qxl.h
+++ b/hw/qxl.h
@@ -55,6 +55,8 @@ typedef struct PCIQXLDevice {
     } guest_surfaces;
     QXLPHYSICAL        guest_cursor;
 
+    QemuMutex          track_lock;
+
     /* thread signaling */
     pthread_t          main;
     int                pipe[2];
commit aee32bf333b13994d9eafb768129e4c2c8688887
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Jul 20 12:20:52 2011 +0300

    spice/qxl: move worker wrappers
    
    Move the wrapper functions which are used by qxl only to qxl.c.
    Rename them from qemu_spice_* to qxl_spice_*.  Also pass in a
    qxl state pointer instead of a SimpleSpiceDisplay pointer.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/qxl-render.c b/hw/qxl-render.c
index bef5f14..60b822d 100644
--- a/hw/qxl-render.c
+++ b/hw/qxl-render.c
@@ -124,8 +124,8 @@ void qxl_render_update(PCIQXLDevice *qxl)
     update.bottom = qxl->guest_primary.surface.height;
 
     memset(dirty, 0, sizeof(dirty));
-    qemu_spice_update_area(&qxl->ssd, 0, &update,
-                           dirty, ARRAY_SIZE(dirty), 1);
+    qxl_spice_update_area(qxl, 0, &update,
+                          dirty, ARRAY_SIZE(dirty), 1);
 
     for (i = 0; i < ARRAY_SIZE(dirty); i++) {
         if (qemu_spice_rect_is_empty(dirty+i)) {
diff --git a/hw/qxl.c b/hw/qxl.c
index 2127fa3..803a364 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -125,6 +125,53 @@ static void qxl_reset_memslots(PCIQXLDevice *d);
 static void qxl_reset_surfaces(PCIQXLDevice *d);
 static void qxl_ring_set_dirty(PCIQXLDevice *qxl);
 
+
+void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
+                           struct QXLRect *area, struct QXLRect *dirty_rects,
+                           uint32_t num_dirty_rects,
+                           uint32_t clear_dirty_region)
+{
+    qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area, dirty_rects,
+                             num_dirty_rects, clear_dirty_region);
+}
+
+void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id)
+{
+    qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id);
+}
+
+void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
+                               uint32_t count)
+{
+    qxl->ssd.worker->loadvm_commands(qxl->ssd.worker, ext, count);
+}
+
+void qxl_spice_oom(PCIQXLDevice *qxl)
+{
+    qxl->ssd.worker->oom(qxl->ssd.worker);
+}
+
+void qxl_spice_reset_memslots(PCIQXLDevice *qxl)
+{
+    qxl->ssd.worker->reset_memslots(qxl->ssd.worker);
+}
+
+void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl)
+{
+    qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker);
+}
+
+void qxl_spice_reset_image_cache(PCIQXLDevice *qxl)
+{
+    qxl->ssd.worker->reset_image_cache(qxl->ssd.worker);
+}
+
+void qxl_spice_reset_cursor(PCIQXLDevice *qxl)
+{
+    qxl->ssd.worker->reset_cursor(qxl->ssd.worker);
+}
+
+
 static inline uint32_t msb_mask(uint32_t val)
 {
     uint32_t mask;
@@ -684,8 +731,8 @@ static void qxl_hard_reset(PCIQXLDevice *d, int loadvm)
     dprint(d, 1, "%s: start%s\n", __FUNCTION__,
            loadvm ? " (loadvm)" : "");
 
-    qemu_spice_reset_cursor(&d->ssd);
-    qemu_spice_reset_image_cache(&d->ssd);
+    qxl_spice_reset_cursor(d);
+    qxl_spice_reset_image_cache(d);
     qxl_reset_surfaces(d);
     qxl_reset_memslots(d);
 
@@ -807,7 +854,7 @@ static void qxl_del_memslot(PCIQXLDevice *d, uint32_t slot_id)
 static void qxl_reset_memslots(PCIQXLDevice *d)
 {
     dprint(d, 1, "%s:\n", __FUNCTION__);
-    qemu_spice_reset_memslots(&d->ssd);
+    qxl_spice_reset_memslots(d);
     memset(&d->guest_slots, 0, sizeof(d->guest_slots));
 }
 
@@ -815,7 +862,7 @@ static void qxl_reset_surfaces(PCIQXLDevice *d)
 {
     dprint(d, 1, "%s:\n", __FUNCTION__);
     d->mode = QXL_MODE_UNDEFINED;
-    qemu_spice_destroy_surfaces(&d->ssd);
+    qxl_spice_destroy_surfaces(d);
     memset(&d->guest_surfaces.cmds, 0, sizeof(d->guest_surfaces.cmds));
 }
 
@@ -956,8 +1003,8 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
     case QXL_IO_UPDATE_AREA:
     {
         QXLRect update = d->ram->update_area;
-        qemu_spice_update_area(&d->ssd, d->ram->update_surface,
-                               &update, NULL, 0, 0);
+        qxl_spice_update_area(d, d->ram->update_surface,
+                              &update, NULL, 0, 0);
         break;
     }
     case QXL_IO_NOTIFY_CMD:
@@ -978,7 +1025,7 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
             break;
         }
         d->oom_running = 1;
-        qemu_spice_oom(&d->ssd);
+        qxl_spice_oom(d);
         d->oom_running = 0;
         break;
     case QXL_IO_SET_MODE:
@@ -1016,10 +1063,10 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
         qxl_destroy_primary(d);
         break;
     case QXL_IO_DESTROY_SURFACE_WAIT:
-        qemu_spice_destroy_surface_wait(&d->ssd, val);
+        qxl_spice_destroy_surface_wait(d, val);
         break;
     case QXL_IO_DESTROY_ALL_SURFACES:
-        qemu_spice_destroy_surfaces(&d->ssd);
+        qxl_spice_destroy_surfaces(d);
         break;
     default:
         fprintf(stderr, "%s: ioport=0x%x, abort()\n", __FUNCTION__, io_port);
@@ -1419,7 +1466,7 @@ static int qxl_post_load(void *opaque, int version)
         cmds[out].cmd.type = QXL_CMD_CURSOR;
         cmds[out].group_id = MEMSLOT_GROUP_GUEST;
         out++;
-        qemu_spice_loadvm_commands(&d->ssd, cmds, out);
+        qxl_spice_loadvm_commands(d, cmds, out);
         qemu_free(cmds);
 
         break;
diff --git a/hw/qxl.h b/hw/qxl.h
index f6c450d..e62b9d0 100644
--- a/hw/qxl.h
+++ b/hw/qxl.h
@@ -98,6 +98,19 @@ typedef struct PCIQXLDevice {
 /* qxl.c */
 void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
 
+void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
+                           struct QXLRect *area, struct QXLRect *dirty_rects,
+                           uint32_t num_dirty_rects,
+                           uint32_t clear_dirty_region);
+void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id);
+void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
+                               uint32_t count);
+void qxl_spice_oom(PCIQXLDevice *qxl);
+void qxl_spice_reset_memslots(PCIQXLDevice *qxl);
+void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl);
+void qxl_spice_reset_image_cache(PCIQXLDevice *qxl);
+void qxl_spice_reset_cursor(PCIQXLDevice *qxl);
+
 /* qxl-logger.c */
 void qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id);
 void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext);
diff --git a/ui/spice-display.c b/ui/spice-display.c
index 93e25bf..af10ae8 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -63,15 +63,6 @@ void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r)
 }
 
 
-void qemu_spice_update_area(SimpleSpiceDisplay *ssd, uint32_t surface_id,
-                            struct QXLRect *area, struct QXLRect *dirty_rects,
-                            uint32_t num_dirty_rects,
-                            uint32_t clear_dirty_region)
-{
-    ssd->worker->update_area(ssd->worker, surface_id, area, dirty_rects,
-                             num_dirty_rects, clear_dirty_region);
-}
-
 void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot)
 {
     ssd->worker->add_memslot(ssd->worker, memslot);
@@ -93,27 +84,11 @@ void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id)
     ssd->worker->destroy_primary_surface(ssd->worker, id);
 }
 
-void qemu_spice_destroy_surface_wait(SimpleSpiceDisplay *ssd, uint32_t id)
-{
-    ssd->worker->destroy_surface_wait(ssd->worker, id);
-}
-
-void qemu_spice_loadvm_commands(SimpleSpiceDisplay *ssd,
-                                struct QXLCommandExt *ext, uint32_t count)
-{
-    ssd->worker->loadvm_commands(ssd->worker, ext, count);
-}
-
 void qemu_spice_wakeup(SimpleSpiceDisplay *ssd)
 {
     ssd->worker->wakeup(ssd->worker);
 }
 
-void qemu_spice_oom(SimpleSpiceDisplay *ssd)
-{
-    ssd->worker->oom(ssd->worker);
-}
-
 void qemu_spice_start(SimpleSpiceDisplay *ssd)
 {
     ssd->worker->start(ssd->worker);
@@ -124,27 +99,6 @@ void qemu_spice_stop(SimpleSpiceDisplay *ssd)
     ssd->worker->stop(ssd->worker);
 }
 
-void qemu_spice_reset_memslots(SimpleSpiceDisplay *ssd)
-{
-    ssd->worker->reset_memslots(ssd->worker);
-}
-
-void qemu_spice_destroy_surfaces(SimpleSpiceDisplay *ssd)
-{
-    ssd->worker->destroy_surfaces(ssd->worker);
-}
-
-void qemu_spice_reset_image_cache(SimpleSpiceDisplay *ssd)
-{
-    ssd->worker->reset_image_cache(ssd->worker);
-}
-
-void qemu_spice_reset_cursor(SimpleSpiceDisplay *ssd)
-{
-    ssd->worker->reset_cursor(ssd->worker);
-}
-
-
 static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
 {
     SimpleSpiceUpdate *update;
diff --git a/ui/spice-display.h b/ui/spice-display.h
index eb7a573..abe99c7 100644
--- a/ui/spice-display.h
+++ b/ui/spice-display.h
@@ -82,24 +82,12 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
 void qemu_spice_display_resize(SimpleSpiceDisplay *ssd);
 void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd);
 
-void qemu_spice_update_area(SimpleSpiceDisplay *ssd, uint32_t surface_id,
-                            struct QXLRect *area, struct QXLRect *dirty_rects,
-                            uint32_t num_dirty_rects,
-                            uint32_t clear_dirty_region);
 void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot);
 void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid,
                             uint32_t sid);
 void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id,
                                        QXLDevSurfaceCreate *surface);
 void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id);
-void qemu_spice_destroy_surface_wait(SimpleSpiceDisplay *ssd, uint32_t id);
-void qemu_spice_loadvm_commands(SimpleSpiceDisplay *ssd,
-                                struct QXLCommandExt *ext, uint32_t count);
 void qemu_spice_wakeup(SimpleSpiceDisplay *ssd);
-void qemu_spice_oom(SimpleSpiceDisplay *ssd);
 void qemu_spice_start(SimpleSpiceDisplay *ssd);
 void qemu_spice_stop(SimpleSpiceDisplay *ssd);
-void qemu_spice_reset_memslots(SimpleSpiceDisplay *ssd);
-void qemu_spice_destroy_surfaces(SimpleSpiceDisplay *ssd);
-void qemu_spice_reset_image_cache(SimpleSpiceDisplay *ssd);
-void qemu_spice_reset_cursor(SimpleSpiceDisplay *ssd);
commit a963f876c80e07a195850a6ab243371b6f93756e
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Jul 20 12:20:51 2011 +0300

    spice: add qemu_spice_display_init_common
    
    Factor out SimpleSpiceDisplay initialization into
    qemu_spice_display_init_common() and call it from
    both qxl.c (for vga mode) and spice-display.c
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/qxl.c b/hw/qxl.c
index 5deb776..2127fa3 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -1315,12 +1315,7 @@ static int qxl_init_primary(PCIDevice *dev)
 
     vga->ds = graphic_console_init(qxl_hw_update, qxl_hw_invalidate,
                                    qxl_hw_screen_dump, qxl_hw_text_update, qxl);
-    qxl->ssd.ds = vga->ds;
-    qemu_mutex_init(&qxl->ssd.lock);
-    qxl->ssd.mouse_x = -1;
-    qxl->ssd.mouse_y = -1;
-    qxl->ssd.bufsize = (16 * 1024 * 1024);
-    qxl->ssd.buf = qemu_malloc(qxl->ssd.bufsize);
+    qemu_spice_display_init_common(&qxl->ssd, vga->ds);
 
     qxl0 = qxl;
     register_displaychangelistener(vga->ds, &display_listener);
diff --git a/ui/spice-display.c b/ui/spice-display.c
index 1e6a38f..93e25bf 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -286,6 +286,16 @@ void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason)
     ssd->running = running;
 }
 
+void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd, DisplayState *ds)
+{
+    ssd->ds = ds;
+    qemu_mutex_init(&ssd->lock);
+    ssd->mouse_x = -1;
+    ssd->mouse_y = -1;
+    ssd->bufsize = (16 * 1024 * 1024);
+    ssd->buf = qemu_malloc(ssd->bufsize);
+}
+
 /* display listener callbacks */
 
 void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
@@ -499,12 +509,7 @@ static DisplayChangeListener display_listener = {
 void qemu_spice_display_init(DisplayState *ds)
 {
     assert(sdpy.ds == NULL);
-    sdpy.ds = ds;
-    qemu_mutex_init(&sdpy.lock);
-    sdpy.mouse_x = -1;
-    sdpy.mouse_y = -1;
-    sdpy.bufsize = (16 * 1024 * 1024);
-    sdpy.buf = qemu_malloc(sdpy.bufsize);
+    qemu_spice_display_init_common(&sdpy, ds);
     register_displaychangelistener(ds, &display_listener);
 
     sdpy.qxl.base.sif = &dpy_interface.base;
diff --git a/ui/spice-display.h b/ui/spice-display.h
index 5b06b11..eb7a573 100644
--- a/ui/spice-display.h
+++ b/ui/spice-display.h
@@ -75,6 +75,7 @@ void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd);
 void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd);
 void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd);
 void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason);
+void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd, DisplayState *ds);
 
 void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
                                int x, int y, int w, int h);
commit 5c59d118161cccf6952b013f71387515f3c91e0a
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Jul 20 12:20:50 2011 +0300

    spice: add worker wrapper functions.
    
    Add wrapper functions for all spice worker calls.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/qxl-render.c b/hw/qxl-render.c
index 1316066..bef5f14 100644
--- a/hw/qxl-render.c
+++ b/hw/qxl-render.c
@@ -124,8 +124,8 @@ void qxl_render_update(PCIQXLDevice *qxl)
     update.bottom = qxl->guest_primary.surface.height;
 
     memset(dirty, 0, sizeof(dirty));
-    qxl->ssd.worker->update_area(qxl->ssd.worker, 0, &update,
-                                 dirty, ARRAY_SIZE(dirty), 1);
+    qemu_spice_update_area(&qxl->ssd, 0, &update,
+                           dirty, ARRAY_SIZE(dirty), 1);
 
     for (i = 0; i < ARRAY_SIZE(dirty); i++) {
         if (qemu_spice_rect_is_empty(dirty+i)) {
diff --git a/hw/qxl.c b/hw/qxl.c
index a6fb7f0..5deb776 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -684,8 +684,8 @@ static void qxl_hard_reset(PCIQXLDevice *d, int loadvm)
     dprint(d, 1, "%s: start%s\n", __FUNCTION__,
            loadvm ? " (loadvm)" : "");
 
-    d->ssd.worker->reset_cursor(d->ssd.worker);
-    d->ssd.worker->reset_image_cache(d->ssd.worker);
+    qemu_spice_reset_cursor(&d->ssd);
+    qemu_spice_reset_image_cache(&d->ssd);
     qxl_reset_surfaces(d);
     qxl_reset_memslots(d);
 
@@ -790,7 +790,7 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta)
            __FUNCTION__, memslot.slot_id,
            memslot.virt_start, memslot.virt_end);
 
-    d->ssd.worker->add_memslot(d->ssd.worker, &memslot);
+    qemu_spice_add_memslot(&d->ssd, &memslot);
     d->guest_slots[slot_id].ptr = (void*)memslot.virt_start;
     d->guest_slots[slot_id].size = memslot.virt_end - memslot.virt_start;
     d->guest_slots[slot_id].delta = delta;
@@ -800,14 +800,14 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta)
 static void qxl_del_memslot(PCIQXLDevice *d, uint32_t slot_id)
 {
     dprint(d, 1, "%s: slot %d\n", __FUNCTION__, slot_id);
-    d->ssd.worker->del_memslot(d->ssd.worker, MEMSLOT_GROUP_HOST, slot_id);
+    qemu_spice_del_memslot(&d->ssd, MEMSLOT_GROUP_HOST, slot_id);
     d->guest_slots[slot_id].active = 0;
 }
 
 static void qxl_reset_memslots(PCIQXLDevice *d)
 {
     dprint(d, 1, "%s:\n", __FUNCTION__);
-    d->ssd.worker->reset_memslots(d->ssd.worker);
+    qemu_spice_reset_memslots(&d->ssd);
     memset(&d->guest_slots, 0, sizeof(d->guest_slots));
 }
 
@@ -815,7 +815,7 @@ static void qxl_reset_surfaces(PCIQXLDevice *d)
 {
     dprint(d, 1, "%s:\n", __FUNCTION__);
     d->mode = QXL_MODE_UNDEFINED;
-    d->ssd.worker->destroy_surfaces(d->ssd.worker);
+    qemu_spice_destroy_surfaces(&d->ssd);
     memset(&d->guest_surfaces.cmds, 0, sizeof(d->guest_surfaces.cmds));
 }
 
@@ -869,7 +869,7 @@ static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm)
 
     qxl->mode = QXL_MODE_NATIVE;
     qxl->cmdflags = 0;
-    qxl->ssd.worker->create_primary_surface(qxl->ssd.worker, 0, &surface);
+    qemu_spice_create_primary_surface(&qxl->ssd, 0, &surface);
 
     /* for local rendering */
     qxl_render_resize(qxl);
@@ -884,7 +884,7 @@ static void qxl_destroy_primary(PCIQXLDevice *d)
     dprint(d, 1, "%s\n", __FUNCTION__);
 
     d->mode = QXL_MODE_UNDEFINED;
-    d->ssd.worker->destroy_primary_surface(d->ssd.worker, 0);
+    qemu_spice_destroy_primary_surface(&d->ssd, 0);
 }
 
 static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm)
@@ -956,15 +956,15 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
     case QXL_IO_UPDATE_AREA:
     {
         QXLRect update = d->ram->update_area;
-        d->ssd.worker->update_area(d->ssd.worker, d->ram->update_surface,
-                                   &update, NULL, 0, 0);
+        qemu_spice_update_area(&d->ssd, d->ram->update_surface,
+                               &update, NULL, 0, 0);
         break;
     }
     case QXL_IO_NOTIFY_CMD:
-        d->ssd.worker->wakeup(d->ssd.worker);
+        qemu_spice_wakeup(&d->ssd);
         break;
     case QXL_IO_NOTIFY_CURSOR:
-        d->ssd.worker->wakeup(d->ssd.worker);
+        qemu_spice_wakeup(&d->ssd);
         break;
     case QXL_IO_UPDATE_IRQ:
         qxl_set_irq(d);
@@ -978,7 +978,7 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
             break;
         }
         d->oom_running = 1;
-        d->ssd.worker->oom(d->ssd.worker);
+        qemu_spice_oom(&d->ssd);
         d->oom_running = 0;
         break;
     case QXL_IO_SET_MODE:
@@ -1016,10 +1016,10 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
         qxl_destroy_primary(d);
         break;
     case QXL_IO_DESTROY_SURFACE_WAIT:
-        d->ssd.worker->destroy_surface_wait(d->ssd.worker, val);
+        qemu_spice_destroy_surface_wait(&d->ssd, val);
         break;
     case QXL_IO_DESTROY_ALL_SURFACES:
-        d->ssd.worker->destroy_surfaces(d->ssd.worker);
+        qemu_spice_destroy_surfaces(&d->ssd);
         break;
     default:
         fprintf(stderr, "%s: ioport=0x%x, abort()\n", __FUNCTION__, io_port);
@@ -1424,7 +1424,7 @@ static int qxl_post_load(void *opaque, int version)
         cmds[out].cmd.type = QXL_CMD_CURSOR;
         cmds[out].group_id = MEMSLOT_GROUP_GUEST;
         out++;
-        d->ssd.worker->loadvm_commands(d->ssd.worker, cmds, out);
+        qemu_spice_loadvm_commands(&d->ssd, cmds, out);
         qemu_free(cmds);
 
         break;
diff --git a/ui/spice-display.c b/ui/spice-display.c
index feeee73..1e6a38f 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -62,6 +62,89 @@ void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r)
     dest->right = MAX(dest->right, r->right);
 }
 
+
+void qemu_spice_update_area(SimpleSpiceDisplay *ssd, uint32_t surface_id,
+                            struct QXLRect *area, struct QXLRect *dirty_rects,
+                            uint32_t num_dirty_rects,
+                            uint32_t clear_dirty_region)
+{
+    ssd->worker->update_area(ssd->worker, surface_id, area, dirty_rects,
+                             num_dirty_rects, clear_dirty_region);
+}
+
+void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot)
+{
+    ssd->worker->add_memslot(ssd->worker, memslot);
+}
+
+void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid, uint32_t sid)
+{
+    ssd->worker->del_memslot(ssd->worker, gid, sid);
+}
+
+void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id,
+                                       QXLDevSurfaceCreate *surface)
+{
+    ssd->worker->create_primary_surface(ssd->worker, id, surface);
+}
+
+void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id)
+{
+    ssd->worker->destroy_primary_surface(ssd->worker, id);
+}
+
+void qemu_spice_destroy_surface_wait(SimpleSpiceDisplay *ssd, uint32_t id)
+{
+    ssd->worker->destroy_surface_wait(ssd->worker, id);
+}
+
+void qemu_spice_loadvm_commands(SimpleSpiceDisplay *ssd,
+                                struct QXLCommandExt *ext, uint32_t count)
+{
+    ssd->worker->loadvm_commands(ssd->worker, ext, count);
+}
+
+void qemu_spice_wakeup(SimpleSpiceDisplay *ssd)
+{
+    ssd->worker->wakeup(ssd->worker);
+}
+
+void qemu_spice_oom(SimpleSpiceDisplay *ssd)
+{
+    ssd->worker->oom(ssd->worker);
+}
+
+void qemu_spice_start(SimpleSpiceDisplay *ssd)
+{
+    ssd->worker->start(ssd->worker);
+}
+
+void qemu_spice_stop(SimpleSpiceDisplay *ssd)
+{
+    ssd->worker->stop(ssd->worker);
+}
+
+void qemu_spice_reset_memslots(SimpleSpiceDisplay *ssd)
+{
+    ssd->worker->reset_memslots(ssd->worker);
+}
+
+void qemu_spice_destroy_surfaces(SimpleSpiceDisplay *ssd)
+{
+    ssd->worker->destroy_surfaces(ssd->worker);
+}
+
+void qemu_spice_reset_image_cache(SimpleSpiceDisplay *ssd)
+{
+    ssd->worker->reset_image_cache(ssd->worker);
+}
+
+void qemu_spice_reset_cursor(SimpleSpiceDisplay *ssd)
+{
+    ssd->worker->reset_cursor(ssd->worker);
+}
+
+
 static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
 {
     SimpleSpiceUpdate *update;
@@ -161,7 +244,7 @@ void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd)
     memset(&memslot, 0, sizeof(memslot));
     memslot.slot_group_id = MEMSLOT_GROUP_HOST;
     memslot.virt_end = ~0;
-    ssd->worker->add_memslot(ssd->worker, &memslot);
+    qemu_spice_add_memslot(ssd, &memslot);
 }
 
 void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
@@ -181,14 +264,14 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
     surface.mem        = (intptr_t)ssd->buf;
     surface.group_id   = MEMSLOT_GROUP_HOST;
 
-    ssd->worker->create_primary_surface(ssd->worker, 0, &surface);
+    qemu_spice_create_primary_surface(ssd, 0, &surface);
 }
 
 void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd)
 {
     dprint(1, "%s:\n", __FUNCTION__);
 
-    ssd->worker->destroy_primary_surface(ssd->worker, 0);
+    qemu_spice_destroy_primary_surface(ssd, 0);
 }
 
 void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason)
@@ -196,9 +279,9 @@ void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason)
     SimpleSpiceDisplay *ssd = opaque;
 
     if (running) {
-        ssd->worker->start(ssd->worker);
+        qemu_spice_start(ssd);
     } else {
-        ssd->worker->stop(ssd->worker);
+        qemu_spice_stop(ssd);
     }
     ssd->running = running;
 }
@@ -267,7 +350,7 @@ void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd)
 
     if (ssd->notify) {
         ssd->notify = 0;
-        ssd->worker->wakeup(ssd->worker);
+        qemu_spice_wakeup(ssd);
         dprint(2, "%s: notify\n", __FUNCTION__);
     }
 }
diff --git a/ui/spice-display.h b/ui/spice-display.h
index 2f95f68..5b06b11 100644
--- a/ui/spice-display.h
+++ b/ui/spice-display.h
@@ -80,3 +80,25 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
                                int x, int y, int w, int h);
 void qemu_spice_display_resize(SimpleSpiceDisplay *ssd);
 void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd);
+
+void qemu_spice_update_area(SimpleSpiceDisplay *ssd, uint32_t surface_id,
+                            struct QXLRect *area, struct QXLRect *dirty_rects,
+                            uint32_t num_dirty_rects,
+                            uint32_t clear_dirty_region);
+void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot);
+void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid,
+                            uint32_t sid);
+void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id,
+                                       QXLDevSurfaceCreate *surface);
+void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id);
+void qemu_spice_destroy_surface_wait(SimpleSpiceDisplay *ssd, uint32_t id);
+void qemu_spice_loadvm_commands(SimpleSpiceDisplay *ssd,
+                                struct QXLCommandExt *ext, uint32_t count);
+void qemu_spice_wakeup(SimpleSpiceDisplay *ssd);
+void qemu_spice_oom(SimpleSpiceDisplay *ssd);
+void qemu_spice_start(SimpleSpiceDisplay *ssd);
+void qemu_spice_stop(SimpleSpiceDisplay *ssd);
+void qemu_spice_reset_memslots(SimpleSpiceDisplay *ssd);
+void qemu_spice_destroy_surfaces(SimpleSpiceDisplay *ssd);
+void qemu_spice_reset_image_cache(SimpleSpiceDisplay *ssd);
+void qemu_spice_reset_cursor(SimpleSpiceDisplay *ssd);
commit d0e2fce5366bff40cf2bf48d2f6ff72b4d8de124
Author: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Date:   Thu Jun 9 23:11:06 2011 +0530

    coroutine: implement coroutines using gthread
    
    On platforms that don't support makecontext(3) use gthread based
    coroutine implementation.
    
    Darwin has makecontext(3) but getcontext(3) is stubbed out to return
    ENOTSUP.  Andreas Färber <andreas.faerber at web.de> debugged this and
    contributed the ./configure test which solves the issue for Darwin/ppc64
    (and ppc) v10.5.
    
    [Original patch by Aneesh, made consistent with coroutine-ucontext.c and
    switched to GStaticPrivate by Stefan.  Tested on Linux and OpenBSD.]
    
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/Makefile.objs b/Makefile.objs
index 28e1762..5679e1f 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -13,7 +13,11 @@ oslib-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o
 #######################################################################
 # coroutines
 coroutine-obj-y = qemu-coroutine.o
+ifeq ($(CONFIG_UCONTEXT_COROUTINE),y)
 coroutine-obj-$(CONFIG_POSIX) += coroutine-ucontext.o
+else
+coroutine-obj-$(CONFIG_POSIX) += coroutine-gthread.o
+endif
 coroutine-obj-$(CONFIG_WIN32) += coroutine-win32.o
 
 #######################################################################
diff --git a/configure b/configure
index 77194cf..1eed0cd 100755
--- a/configure
+++ b/configure
@@ -2541,6 +2541,20 @@ EOF
 fi
 
 ##########################################
+# check if we have makecontext
+
+ucontext_coroutine=no
+if test "$darwin" != "yes"; then
+  cat > $TMPC << EOF
+#include <ucontext.h>
+int main(void) { makecontext(0, 0, 0); }
+EOF
+  if compile_prog "" "" ; then
+      ucontext_coroutine=yes
+  fi
+fi
+
+##########################################
 # End of CC checks
 # After here, no more $cc or $ld runs
 
@@ -3015,6 +3029,10 @@ if test "$rbd" = "yes" ; then
   echo "CONFIG_RBD=y" >> $config_host_mak
 fi
 
+if test "$ucontext_coroutine" = "yes" ; then
+  echo "CONFIG_UCONTEXT_COROUTINE=y" >> $config_host_mak
+fi
+
 # USB host support
 case "$usb" in
 linux)
diff --git a/coroutine-gthread.c b/coroutine-gthread.c
new file mode 100644
index 0000000..f09877e
--- /dev/null
+++ b/coroutine-gthread.c
@@ -0,0 +1,131 @@
+/*
+ * GThread coroutine initialization code
+ *
+ * Copyright (C) 2006  Anthony Liguori <anthony at codemonkey.ws>
+ * Copyright (C) 2011  Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.0 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include "qemu-common.h"
+#include "qemu-coroutine-int.h"
+
+typedef struct {
+    Coroutine base;
+    GThread *thread;
+    bool runnable;
+    CoroutineAction action;
+} CoroutineGThread;
+
+static GCond *coroutine_cond;
+static GStaticMutex coroutine_lock = G_STATIC_MUTEX_INIT;
+static GStaticPrivate coroutine_key = G_STATIC_PRIVATE_INIT;
+
+static void __attribute__((constructor)) coroutine_init(void)
+{
+    if (!g_thread_supported()) {
+        g_thread_init(NULL);
+    }
+
+    coroutine_cond = g_cond_new();
+}
+
+static void coroutine_wait_runnable_locked(CoroutineGThread *co)
+{
+    while (!co->runnable) {
+        g_cond_wait(coroutine_cond, g_static_mutex_get_mutex(&coroutine_lock));
+    }
+}
+
+static void coroutine_wait_runnable(CoroutineGThread *co)
+{
+    g_static_mutex_lock(&coroutine_lock);
+    coroutine_wait_runnable_locked(co);
+    g_static_mutex_unlock(&coroutine_lock);
+}
+
+static gpointer coroutine_thread(gpointer opaque)
+{
+    CoroutineGThread *co = opaque;
+
+    g_static_private_set(&coroutine_key, co, NULL);
+    coroutine_wait_runnable(co);
+    co->base.entry(co->base.entry_arg);
+    qemu_coroutine_switch(&co->base, co->base.caller, COROUTINE_TERMINATE);
+    return NULL;
+}
+
+Coroutine *qemu_coroutine_new(void)
+{
+    CoroutineGThread *co;
+
+    co = qemu_mallocz(sizeof(*co));
+    co->thread = g_thread_create_full(coroutine_thread, co, 0, TRUE, TRUE,
+                                      G_THREAD_PRIORITY_NORMAL, NULL);
+    if (!co->thread) {
+        qemu_free(co);
+        return NULL;
+    }
+    return &co->base;
+}
+
+void qemu_coroutine_delete(Coroutine *co_)
+{
+    CoroutineGThread *co = DO_UPCAST(CoroutineGThread, base, co_);
+
+    g_thread_join(co->thread);
+    qemu_free(co);
+}
+
+CoroutineAction qemu_coroutine_switch(Coroutine *from_,
+                                      Coroutine *to_,
+                                      CoroutineAction action)
+{
+    CoroutineGThread *from = DO_UPCAST(CoroutineGThread, base, from_);
+    CoroutineGThread *to = DO_UPCAST(CoroutineGThread, base, to_);
+
+    g_static_mutex_lock(&coroutine_lock);
+    from->runnable = false;
+    from->action = action;
+    to->runnable = true;
+    to->action = action;
+    g_cond_broadcast(coroutine_cond);
+
+    if (action != COROUTINE_TERMINATE) {
+        coroutine_wait_runnable_locked(from);
+    }
+    g_static_mutex_unlock(&coroutine_lock);
+    return from->action;
+}
+
+Coroutine *qemu_coroutine_self(void)
+{
+    CoroutineGThread *co = g_static_private_get(&coroutine_key);
+
+    if (!co) {
+        co = qemu_mallocz(sizeof(*co));
+        co->runnable = true;
+        g_static_private_set(&coroutine_key, co, (GDestroyNotify)qemu_free);
+    }
+
+    return &co->base;
+}
+
+bool qemu_in_coroutine(void)
+{
+    CoroutineGThread *co = g_static_private_get(&coroutine_key);
+
+    return co && co->base.caller;
+}
commit 00dccaf1f848290d979a4b1e6248281ce1b32aaa
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Mon Jan 17 16:08:14 2011 +0000

    coroutine: introduce coroutines
    
    Asynchronous code is becoming very complex.  At the same time
    synchronous code is growing because it is convenient to write.
    Sometimes duplicate code paths are even added, one synchronous and the
    other asynchronous.  This patch introduces coroutines which allow code
    that looks synchronous but is asynchronous under the covers.
    
    A coroutine has its own stack and is therefore able to preserve state
    across blocking operations, which traditionally require callback
    functions and manual marshalling of parameters.
    
    Creating and starting a coroutine is easy:
    
      coroutine = qemu_coroutine_create(my_coroutine);
      qemu_coroutine_enter(coroutine, my_data);
    
    The coroutine then executes until it returns or yields:
    
      void coroutine_fn my_coroutine(void *opaque) {
          MyData *my_data = opaque;
    
          /* do some work */
    
          qemu_coroutine_yield();
    
          /* do some more work */
      }
    
    Yielding switches control back to the caller of qemu_coroutine_enter().
    This is typically used to switch back to the main thread's event loop
    after issuing an asynchronous I/O request.  The request callback will
    then invoke qemu_coroutine_enter() once more to switch back to the
    coroutine.
    
    Note that if coroutines are used only from threads which hold the global
    mutex they will never execute concurrently.  This makes programming with
    coroutines easier than with threads.  Race conditions cannot occur since
    only one coroutine may be active at any time.  Other coroutines can only
    run across yield.
    
    This coroutines implementation is based on the gtk-vnc implementation
    written by Anthony Liguori <anthony at codemonkey.ws> but it has been
    significantly rewritten by Kevin Wolf <kwolf at redhat.com> to use
    setjmp()/longjmp() instead of the more expensive swapcontext() and by
    Paolo Bonzini <pbonzini at redhat.com> for Windows Fibers support.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/Makefile.objs b/Makefile.objs
index 6991a9f..28e1762 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -11,6 +11,12 @@ oslib-obj-$(CONFIG_WIN32) += oslib-win32.o qemu-thread-win32.o
 oslib-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o
 
 #######################################################################
+# coroutines
+coroutine-obj-y = qemu-coroutine.o
+coroutine-obj-$(CONFIG_POSIX) += coroutine-ucontext.o
+coroutine-obj-$(CONFIG_WIN32) += coroutine-win32.o
+
+#######################################################################
 # block-obj-y is code used by both qemu system emulation and qemu-img
 
 block-obj-y = cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.o async.o
@@ -69,6 +75,7 @@ common-obj-y += readline.o console.o cursor.o qemu-error.o
 common-obj-y += $(oslib-obj-y)
 common-obj-$(CONFIG_WIN32) += os-win32.o
 common-obj-$(CONFIG_POSIX) += os-posix.o
+common-obj-y += $(coroutine-obj-y)
 
 common-obj-y += tcg-runtime.o host-utils.o
 common-obj-y += irq.o ioport.o input.o
diff --git a/coroutine-ucontext.c b/coroutine-ucontext.c
new file mode 100644
index 0000000..41c2379
--- /dev/null
+++ b/coroutine-ucontext.c
@@ -0,0 +1,230 @@
+/*
+ * ucontext coroutine initialization code
+ *
+ * Copyright (C) 2006  Anthony Liguori <anthony at codemonkey.ws>
+ * Copyright (C) 2011  Kevin Wolf <kwolf at redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.0 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* XXX Is there a nicer way to disable glibc's stack check for longjmp? */
+#ifdef _FORTIFY_SOURCE
+#undef _FORTIFY_SOURCE
+#endif
+#include <stdlib.h>
+#include <setjmp.h>
+#include <stdint.h>
+#include <pthread.h>
+#include <ucontext.h>
+#include "qemu-common.h"
+#include "qemu-coroutine-int.h"
+
+enum {
+    /* Maximum free pool size prevents holding too many freed coroutines */
+    POOL_MAX_SIZE = 64,
+};
+
+typedef struct {
+    Coroutine base;
+    void *stack;
+    jmp_buf env;
+} CoroutineUContext;
+
+/**
+ * Per-thread coroutine bookkeeping
+ */
+typedef struct {
+    /** Currently executing coroutine */
+    Coroutine *current;
+
+    /** Free list to speed up creation */
+    QLIST_HEAD(, Coroutine) pool;
+    unsigned int pool_size;
+
+    /** The default coroutine */
+    CoroutineUContext leader;
+} CoroutineThreadState;
+
+static pthread_key_t thread_state_key;
+
+/*
+ * va_args to makecontext() must be type 'int', so passing
+ * the pointer we need may require several int args. This
+ * union is a quick hack to let us do that
+ */
+union cc_arg {
+    void *p;
+    int i[2];
+};
+
+static CoroutineThreadState *coroutine_get_thread_state(void)
+{
+    CoroutineThreadState *s = pthread_getspecific(thread_state_key);
+
+    if (!s) {
+        s = qemu_mallocz(sizeof(*s));
+        s->current = &s->leader.base;
+        QLIST_INIT(&s->pool);
+        pthread_setspecific(thread_state_key, s);
+    }
+    return s;
+}
+
+static void qemu_coroutine_thread_cleanup(void *opaque)
+{
+    CoroutineThreadState *s = opaque;
+    Coroutine *co;
+    Coroutine *tmp;
+
+    QLIST_FOREACH_SAFE(co, &s->pool, pool_next, tmp) {
+        qemu_free(DO_UPCAST(CoroutineUContext, base, co)->stack);
+        qemu_free(co);
+    }
+    qemu_free(s);
+}
+
+static void __attribute__((constructor)) coroutine_init(void)
+{
+    int ret;
+
+    ret = pthread_key_create(&thread_state_key, qemu_coroutine_thread_cleanup);
+    if (ret != 0) {
+        fprintf(stderr, "unable to create leader key: %s\n", strerror(errno));
+        abort();
+    }
+}
+
+static void coroutine_trampoline(int i0, int i1)
+{
+    union cc_arg arg;
+    CoroutineUContext *self;
+    Coroutine *co;
+
+    arg.i[0] = i0;
+    arg.i[1] = i1;
+    self = arg.p;
+    co = &self->base;
+
+    /* Initialize longjmp environment and switch back the caller */
+    if (!setjmp(self->env)) {
+        longjmp(*(jmp_buf *)co->entry_arg, 1);
+    }
+
+    while (true) {
+        co->entry(co->entry_arg);
+        qemu_coroutine_switch(co, co->caller, COROUTINE_TERMINATE);
+    }
+}
+
+static Coroutine *coroutine_new(void)
+{
+    const size_t stack_size = 1 << 20;
+    CoroutineUContext *co;
+    ucontext_t old_uc, uc;
+    jmp_buf old_env;
+    union cc_arg arg;
+
+    /* The ucontext functions preserve signal masks which incurs a system call
+     * overhead.  setjmp()/longjmp() does not preserve signal masks but only
+     * works on the current stack.  Since we need a way to create and switch to
+     * a new stack, use the ucontext functions for that but setjmp()/longjmp()
+     * for everything else.
+     */
+
+    if (getcontext(&uc) == -1) {
+        abort();
+    }
+
+    co = qemu_mallocz(sizeof(*co));
+    co->stack = qemu_malloc(stack_size);
+    co->base.entry_arg = &old_env; /* stash away our jmp_buf */
+
+    uc.uc_link = &old_uc;
+    uc.uc_stack.ss_sp = co->stack;
+    uc.uc_stack.ss_size = stack_size;
+    uc.uc_stack.ss_flags = 0;
+
+    arg.p = co;
+
+    makecontext(&uc, (void (*)(void))coroutine_trampoline,
+                2, arg.i[0], arg.i[1]);
+
+    /* swapcontext() in, longjmp() back out */
+    if (!setjmp(old_env)) {
+        swapcontext(&old_uc, &uc);
+    }
+    return &co->base;
+}
+
+Coroutine *qemu_coroutine_new(void)
+{
+    CoroutineThreadState *s = coroutine_get_thread_state();
+    Coroutine *co;
+
+    co = QLIST_FIRST(&s->pool);
+    if (co) {
+        QLIST_REMOVE(co, pool_next);
+        s->pool_size--;
+    } else {
+        co = coroutine_new();
+    }
+    return co;
+}
+
+void qemu_coroutine_delete(Coroutine *co_)
+{
+    CoroutineThreadState *s = coroutine_get_thread_state();
+    CoroutineUContext *co = DO_UPCAST(CoroutineUContext, base, co_);
+
+    if (s->pool_size < POOL_MAX_SIZE) {
+        QLIST_INSERT_HEAD(&s->pool, &co->base, pool_next);
+        co->base.caller = NULL;
+        s->pool_size++;
+        return;
+    }
+
+    qemu_free(co->stack);
+    qemu_free(co);
+}
+
+CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
+                                      CoroutineAction action)
+{
+    CoroutineUContext *from = DO_UPCAST(CoroutineUContext, base, from_);
+    CoroutineUContext *to = DO_UPCAST(CoroutineUContext, base, to_);
+    CoroutineThreadState *s = coroutine_get_thread_state();
+    int ret;
+
+    s->current = to_;
+
+    ret = setjmp(from->env);
+    if (ret == 0) {
+        longjmp(to->env, action);
+    }
+    return ret;
+}
+
+Coroutine *qemu_coroutine_self(void)
+{
+    CoroutineThreadState *s = coroutine_get_thread_state();
+
+    return s->current;
+}
+
+bool qemu_in_coroutine(void)
+{
+    CoroutineThreadState *s = pthread_getspecific(thread_state_key);
+
+    return s && s->current->caller;
+}
diff --git a/coroutine-win32.c b/coroutine-win32.c
new file mode 100644
index 0000000..0e29448
--- /dev/null
+++ b/coroutine-win32.c
@@ -0,0 +1,92 @@
+/*
+ * Win32 coroutine initialization code
+ *
+ * Copyright (c) 2011 Kevin Wolf <kwolf at redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu-common.h"
+#include "qemu-coroutine-int.h"
+
+typedef struct
+{
+    Coroutine base;
+
+    LPVOID fiber;
+    CoroutineAction action;
+} CoroutineWin32;
+
+static __thread CoroutineWin32 leader;
+static __thread Coroutine *current;
+
+CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
+                                      CoroutineAction action)
+{
+    CoroutineWin32 *from = DO_UPCAST(CoroutineWin32, base, from_);
+    CoroutineWin32 *to = DO_UPCAST(CoroutineWin32, base, to_);
+
+    current = to_;
+
+    to->action = action;
+    SwitchToFiber(to->fiber);
+    return from->action;
+}
+
+static void CALLBACK coroutine_trampoline(void *co_)
+{
+    Coroutine *co = co_;
+
+    while (true) {
+        co->entry(co->entry_arg);
+        qemu_coroutine_switch(co, co->caller, COROUTINE_TERMINATE);
+    }
+}
+
+Coroutine *qemu_coroutine_new(void)
+{
+    const size_t stack_size = 1 << 20;
+    CoroutineWin32 *co;
+
+    co = qemu_mallocz(sizeof(*co));
+    co->fiber = CreateFiber(stack_size, coroutine_trampoline, &co->base);
+    return &co->base;
+}
+
+void qemu_coroutine_delete(Coroutine *co_)
+{
+    CoroutineWin32 *co = DO_UPCAST(CoroutineWin32, base, co_);
+
+    DeleteFiber(co->fiber);
+    qemu_free(co);
+}
+
+Coroutine *qemu_coroutine_self(void)
+{
+    if (!current) {
+        current = &leader.base;
+        leader.fiber = ConvertThreadToFiber(NULL);
+    }
+    return current;
+}
+
+bool qemu_in_coroutine(void)
+{
+    return current && current->caller;
+}
diff --git a/qemu-coroutine-int.h b/qemu-coroutine-int.h
new file mode 100644
index 0000000..64915c2
--- /dev/null
+++ b/qemu-coroutine-int.h
@@ -0,0 +1,48 @@
+/*
+ * Coroutine internals
+ *
+ * Copyright (c) 2011 Kevin Wolf <kwolf at redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QEMU_COROUTINE_INT_H
+#define QEMU_COROUTINE_INT_H
+
+#include "qemu-queue.h"
+#include "qemu-coroutine.h"
+
+typedef enum {
+    COROUTINE_YIELD = 1,
+    COROUTINE_TERMINATE = 2,
+} CoroutineAction;
+
+struct Coroutine {
+    CoroutineEntry *entry;
+    void *entry_arg;
+    Coroutine *caller;
+    QLIST_ENTRY(Coroutine) pool_next;
+};
+
+Coroutine *qemu_coroutine_new(void);
+void qemu_coroutine_delete(Coroutine *co);
+CoroutineAction qemu_coroutine_switch(Coroutine *from, Coroutine *to,
+                                      CoroutineAction action);
+
+#endif
diff --git a/qemu-coroutine.c b/qemu-coroutine.c
new file mode 100644
index 0000000..600be26
--- /dev/null
+++ b/qemu-coroutine.c
@@ -0,0 +1,75 @@
+/*
+ * QEMU coroutines
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Stefan Hajnoczi    <stefanha at linux.vnet.ibm.com>
+ *  Kevin Wolf         <kwolf at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "trace.h"
+#include "qemu-common.h"
+#include "qemu-coroutine.h"
+#include "qemu-coroutine-int.h"
+
+Coroutine *qemu_coroutine_create(CoroutineEntry *entry)
+{
+    Coroutine *co = qemu_coroutine_new();
+    co->entry = entry;
+    return co;
+}
+
+static void coroutine_swap(Coroutine *from, Coroutine *to)
+{
+    CoroutineAction ret;
+
+    ret = qemu_coroutine_switch(from, to, COROUTINE_YIELD);
+
+    switch (ret) {
+    case COROUTINE_YIELD:
+        return;
+    case COROUTINE_TERMINATE:
+        trace_qemu_coroutine_terminate(to);
+        qemu_coroutine_delete(to);
+        return;
+    default:
+        abort();
+    }
+}
+
+void qemu_coroutine_enter(Coroutine *co, void *opaque)
+{
+    Coroutine *self = qemu_coroutine_self();
+
+    trace_qemu_coroutine_enter(self, co, opaque);
+
+    if (co->caller) {
+        fprintf(stderr, "Co-routine re-entered recursively\n");
+        abort();
+    }
+
+    co->caller = self;
+    co->entry_arg = opaque;
+    coroutine_swap(self, co);
+}
+
+void coroutine_fn qemu_coroutine_yield(void)
+{
+    Coroutine *self = qemu_coroutine_self();
+    Coroutine *to = self->caller;
+
+    trace_qemu_coroutine_yield(self, to);
+
+    if (!to) {
+        fprintf(stderr, "Co-routine is yielding to no one\n");
+        abort();
+    }
+
+    self->caller = NULL;
+    coroutine_swap(self, to);
+}
diff --git a/qemu-coroutine.h b/qemu-coroutine.h
new file mode 100644
index 0000000..08255c7
--- /dev/null
+++ b/qemu-coroutine.h
@@ -0,0 +1,95 @@
+/*
+ * QEMU coroutine implementation
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Stefan Hajnoczi    <stefanha at linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_COROUTINE_H
+#define QEMU_COROUTINE_H
+
+#include <stdbool.h>
+
+/**
+ * Coroutines are a mechanism for stack switching and can be used for
+ * cooperative userspace threading.  These functions provide a simple but
+ * useful flavor of coroutines that is suitable for writing sequential code,
+ * rather than callbacks, for operations that need to give up control while
+ * waiting for events to complete.
+ *
+ * These functions are re-entrant and may be used outside the global mutex.
+ */
+
+/**
+ * Mark a function that executes in coroutine context
+ *
+ * Functions that execute in coroutine context cannot be called directly from
+ * normal functions.  In the future it would be nice to enable compiler or
+ * static checker support for catching such errors.  This annotation might make
+ * it possible and in the meantime it serves as documentation.
+ *
+ * For example:
+ *
+ *   static void coroutine_fn foo(void) {
+ *       ....
+ *   }
+ */
+#define coroutine_fn
+
+typedef struct Coroutine Coroutine;
+
+/**
+ * Coroutine entry point
+ *
+ * When the coroutine is entered for the first time, opaque is passed in as an
+ * argument.
+ *
+ * When this function returns, the coroutine is destroyed automatically and
+ * execution continues in the caller who last entered the coroutine.
+ */
+typedef void coroutine_fn CoroutineEntry(void *opaque);
+
+/**
+ * Create a new coroutine
+ *
+ * Use qemu_coroutine_enter() to actually transfer control to the coroutine.
+ */
+Coroutine *qemu_coroutine_create(CoroutineEntry *entry);
+
+/**
+ * Transfer control to a coroutine
+ *
+ * The opaque argument is passed as the argument to the entry point when
+ * entering the coroutine for the first time.  It is subsequently ignored.
+ */
+void qemu_coroutine_enter(Coroutine *coroutine, void *opaque);
+
+/**
+ * Transfer control back to a coroutine's caller
+ *
+ * This function does not return until the coroutine is re-entered using
+ * qemu_coroutine_enter().
+ */
+void coroutine_fn qemu_coroutine_yield(void);
+
+/**
+ * Get the currently executing coroutine
+ */
+Coroutine *coroutine_fn qemu_coroutine_self(void);
+
+/**
+ * Return whether or not currently inside a coroutine
+ *
+ * This can be used to write functions that work both when in coroutine context
+ * and when not in coroutine context.  Note that such functions cannot use the
+ * coroutine_fn annotation since they work outside coroutine context.
+ */
+bool qemu_in_coroutine(void);
+
+#endif /* QEMU_COROUTINE_H */
diff --git a/trace-events b/trace-events
index 713f042..136f775 100644
--- a/trace-events
+++ b/trace-events
@@ -425,3 +425,8 @@ disable qemu_put_ram_ptr(void* addr) "%p"
 
 # hw/xen_platform.c
 disable xen_platform_log(char *s) "xen platform: %s"
+
+# qemu-coroutine.c
+disable qemu_coroutine_enter(void *from, void *to, void *opaque) "from %p to %p opaque %p"
+disable qemu_coroutine_yield(void *from, void *to) "from %p to %p"
+disable qemu_coroutine_terminate(void *co) "self %p"
commit f6e8ffc22fe153ba981f2747e4c52ea7e55f6ecc
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Wed Jul 27 20:12:02 2011 +0200

    raw-posix: Always check paio_init result
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/raw-posix.c b/block/raw-posix.c
index 6dd7086..c5c9944 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -230,13 +230,15 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
         }
     }
 
+    /* We're falling back to POSIX AIO in some cases so init always */
+    if (paio_init() < 0) {
+        goto out_free_buf;
+    }
+
 #ifdef CONFIG_LINUX_AIO
     if ((bdrv_flags & (BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO)) ==
                       (BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO)) {
 
-        /* We're falling back to POSIX AIO in some cases */
-        paio_init();
-
         s->aio_ctx = laio_init();
         if (!s->aio_ctx) {
             goto out_free_buf;
@@ -245,9 +247,6 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
     } else
 #endif
     {
-        if (paio_init() < 0) {
-            goto out_free_buf;
-        }
 #ifdef CONFIG_LINUX_AIO
         s->use_aio = 0;
 #endif
commit c1ee7d56f3f2c8c5fb90452f4df72fa402f61527
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Wed Jul 27 20:12:01 2011 +0200

    raw-posix: Typo fix
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/raw-posix.c b/block/raw-posix.c
index 6672d31..6dd7086 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -587,7 +587,7 @@ static BlockDriverAIOCB *raw_aio_submit(BlockDriverState *bs,
 
     /*
      * If O_DIRECT is used the buffer needs to be aligned on a sector
-     * boundary.  Check if this is the case or telll the low-level
+     * boundary.  Check if this is the case or tell the low-level
      * driver that it needs to copy the buffer.
      */
     if (s->aligned_buf) {
commit 5bf3f8e4f71e46f80b76dc8a03cc0c37cad5cde0
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Wed Jul 27 20:12:00 2011 +0200

    block: Removed unused function bdrv_write_sync
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index 8859f9b..4c66b2c 100644
--- a/block.c
+++ b/block.c
@@ -1110,19 +1110,6 @@ int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset,
     return 0;
 }
 
-/*
- * Writes to the file and ensures that no writes are reordered across this
- * request (acts as a barrier)
- *
- * Returns 0 on success, -errno in error cases.
- */
-int bdrv_write_sync(BlockDriverState *bs, int64_t sector_num,
-    const uint8_t *buf, int nb_sectors)
-{
-    return bdrv_pwrite_sync(bs, BDRV_SECTOR_SIZE * sector_num,
-        buf, BDRV_SECTOR_SIZE * nb_sectors);
-}
-
 /**
  * Truncate file to 'offset' bytes (needed only for file protocols)
  */
diff --git a/block.h b/block.h
index 59cc410..e672bc6 100644
--- a/block.h
+++ b/block.h
@@ -85,8 +85,6 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
                 const void *buf, int count);
 int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset,
     const void *buf, int count);
-int bdrv_write_sync(BlockDriverState *bs, int64_t sector_num,
-    const uint8_t *buf, int nb_sectors);
 int bdrv_truncate(BlockDriverState *bs, int64_t offset);
 int64_t bdrv_getlength(BlockDriverState *bs);
 int64_t bdrv_get_allocated_file_size(BlockDriverState *bs);
commit f37bd73b76e7f1e300e6acfe1bb6d3b2bc63714b
Author: Hannes Reinecke <hare at suse.de>
Date:   Fri Jul 22 16:44:46 2011 +0200

    scsi-disk: Remove 'drive_kind'
    
    Instead of using its own definitions scsi-disk should
    be using the device type of the parent device.
    
    Signed-off-by: Hannes Reinecke <hare at suse.de>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-defs.h b/hw/scsi-defs.h
index f644860..27010b7 100644
--- a/hw/scsi-defs.h
+++ b/hw/scsi-defs.h
@@ -164,6 +164,7 @@
 
 #define TYPE_DISK           0x00
 #define TYPE_TAPE           0x01
+#define TYPE_PRINTER        0x02
 #define TYPE_PROCESSOR      0x03    /* HP scanners use this */
 #define TYPE_WORM           0x04    /* Treated as ROM by our system */
 #define TYPE_ROM            0x05
@@ -171,6 +172,9 @@
 #define TYPE_MOD            0x07    /* Magneto-optical disk -
 				     * - treated as TYPE_DISK */
 #define TYPE_MEDIUM_CHANGER 0x08
-#define TYPE_ENCLOSURE	    0x0d    /* Enclosure Services Device */
+#define TYPE_STORAGE_ARRAY  0x0c    /* Storage array device */
+#define TYPE_ENCLOSURE      0x0d    /* Enclosure Services Device */
+#define TYPE_RBC            0x0e    /* Simplified Direct-Access Device */
+#define TYPE_OSD            0x11    /* Object-storage Device */
 #define TYPE_NO_LUN         0x7f
 
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 03f244e..fa198f9 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -59,8 +59,6 @@ typedef struct SCSIDiskReq {
     uint32_t status;
 } SCSIDiskReq;
 
-typedef enum { SCSI_HD, SCSI_CD } SCSIDriveKind;
-
 struct SCSIDiskState
 {
     SCSIDevice qdev;
@@ -74,7 +72,6 @@ struct SCSIDiskState
     char *version;
     char *serial;
     SCSISense sense;
-    SCSIDriveKind drive_kind;
 };
 
 static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type);
@@ -382,7 +379,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
             return -1;
         }
 
-        if (s->drive_kind == SCSI_CD) {
+        if (s->qdev.type == TYPE_ROM) {
             outbuf[buflen++] = 5;
         } else {
             outbuf[buflen++] = 0;
@@ -401,7 +398,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
             if (s->serial)
                 outbuf[buflen++] = 0x80; // unit serial number
             outbuf[buflen++] = 0x83; // device identification
-            if (s->drive_kind == SCSI_HD) {
+            if (s->qdev.type == TYPE_DISK) {
                 outbuf[buflen++] = 0xb0; // block limits
                 outbuf[buflen++] = 0xb2; // thin provisioning
             }
@@ -460,7 +457,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
             unsigned int opt_io_size =
                     s->qdev.conf.opt_io_size / s->qdev.blocksize;
 
-            if (s->drive_kind == SCSI_CD) {
+            if (s->qdev.type == TYPE_ROM) {
                 DPRINTF("Inquiry (EVPD[%02X] not supported for CDROM\n",
                         page_code);
                 return -1;
@@ -530,12 +527,11 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
         return buflen;
     }
 
-    if (s->drive_kind == SCSI_CD) {
-        outbuf[0] = 5;
+    outbuf[0] = s->qdev.type & 0x1f;
+    if (s->qdev.type == TYPE_ROM) {
         outbuf[1] = 0x80;
         memcpy(&outbuf[16], "QEMU CD-ROM     ", 16);
     } else {
-        outbuf[0] = 0;
         outbuf[1] = s->removable ? 0x80 : 0;
         memcpy(&outbuf[16], "QEMU HARDDISK   ", 16);
     }
@@ -661,7 +657,7 @@ static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p,
         return p[1] + 2;
 
     case 0x2a: /* CD Capabilities and Mechanical Status page. */
-        if (s->drive_kind != SCSI_CD)
+        if (s->qdev.type != TYPE_ROM)
             return 0;
         p[0] = 0x2a;
         p[1] = 0x14;
@@ -877,7 +873,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
             goto illegal_request;
         break;
     case START_STOP:
-        if (s->drive_kind == SCSI_CD && (req->cmd.buf[4] & 2)) {
+        if (s->qdev.type == TYPE_ROM && (req->cmd.buf[4] & 2)) {
             /* load/eject medium */
             bdrv_eject(s->bs, !(req->cmd.buf[4] & 1));
         }
@@ -1183,7 +1179,7 @@ static void scsi_destroy(SCSIDevice *dev)
     blockdev_mark_auto_del(s->qdev.conf.bs);
 }
 
-static int scsi_initfn(SCSIDevice *dev, SCSIDriveKind kind)
+static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
 {
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
     DriveInfo *dinfo;
@@ -1193,9 +1189,8 @@ static int scsi_initfn(SCSIDevice *dev, SCSIDriveKind kind)
         return -1;
     }
     s->bs = s->qdev.conf.bs;
-    s->drive_kind = kind;
 
-    if (kind == SCSI_HD && !bdrv_is_inserted(s->bs)) {
+    if (scsi_type == TYPE_DISK && !bdrv_is_inserted(s->bs)) {
         error_report("Device needs media, but drive is empty");
         return -1;
     }
@@ -1217,44 +1212,47 @@ static int scsi_initfn(SCSIDevice *dev, SCSIDriveKind kind)
         return -1;
     }
 
-    if (kind == SCSI_CD) {
+    if (scsi_type == TYPE_ROM) {
         s->qdev.blocksize = 2048;
-    } else {
+    } else if (scsi_type == TYPE_DISK) {
         s->qdev.blocksize = s->qdev.conf.logical_block_size;
+    } else {
+        error_report("scsi-disk: Unhandled SCSI type %02x", scsi_type);
+        return -1;
     }
     s->cluster_size = s->qdev.blocksize / 512;
     s->bs->buffer_alignment = s->qdev.blocksize;
 
-    s->qdev.type = TYPE_DISK;
+    s->qdev.type = scsi_type;
     qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
-    bdrv_set_removable(s->bs, kind == SCSI_CD);
+    bdrv_set_removable(s->bs, scsi_type == TYPE_ROM);
     add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, ",0");
     return 0;
 }
 
 static int scsi_hd_initfn(SCSIDevice *dev)
 {
-    return scsi_initfn(dev, SCSI_HD);
+    return scsi_initfn(dev, TYPE_DISK);
 }
 
 static int scsi_cd_initfn(SCSIDevice *dev)
 {
-    return scsi_initfn(dev, SCSI_CD);
+    return scsi_initfn(dev, TYPE_ROM);
 }
 
 static int scsi_disk_initfn(SCSIDevice *dev)
 {
-    SCSIDriveKind kind;
     DriveInfo *dinfo;
+    uint8_t scsi_type;
 
     if (!dev->conf.bs) {
-        kind = SCSI_HD;         /* will die in scsi_initfn() */
+        scsi_type = TYPE_DISK;  /* will die in scsi_initfn() */
     } else {
         dinfo = drive_get_by_blockdev(dev->conf.bs);
-        kind = dinfo->media_cd ? SCSI_CD : SCSI_HD;
+        scsi_type = dinfo->media_cd ? TYPE_ROM : TYPE_DISK;
     }
 
-    return scsi_initfn(dev, kind);
+    return scsi_initfn(dev, scsi_type);
 }
 
 #define DEFINE_SCSI_DISK_PROPERTIES()                           \
commit 5e30a07d6d70d3073ff61e6db79d61c2b688502f
Author: Hannes Reinecke <hare at suse.de>
Date:   Fri Jul 22 16:51:15 2011 +0200

    scsi: Sanitize command definitions
    
    Sanitize SCSI command definitions.
    Add _10 suffix to READ_CAPACITY, WRITE_VERIFY, VERIFY, READ_LONG,
    WRITE_LONG, and WRITE_SAME.
    Add new command definitions for LOCATE_10, UNMAP, VARLENGTH_CDB,
    WRITE_FILEMARKS_16, EXTENDED_COPY, ATA_PASSTHROUGH, ACCESS_CONTROL_IN,
    ACCESS_CONTROL_OUT, COMPARE_AND_WRITE, VERIFY_16, SYNCHRONIZE_CACHE_16,
    LOCATE_16, ERASE_16, WRITE_LONG_16, LOAD_UNLOAD, VERIFY_12.
    Remove invalid definition of WRITE_LONG_2.
    
    Signed-off-by: Hannes Reinecke <hare at suse.de>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 52a6784..0b0344c 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -223,6 +223,7 @@ static int scsi_req_length(SCSIRequest *req, uint8_t *cmd)
 
     switch(cmd[0]) {
     case TEST_UNIT_READY:
+    case REWIND:
     case START_STOP:
     case SEEK_6:
     case WRITE_FILEMARKS:
@@ -231,24 +232,24 @@ static int scsi_req_length(SCSIRequest *req, uint8_t *cmd)
     case RELEASE:
     case ERASE:
     case ALLOW_MEDIUM_REMOVAL:
-    case VERIFY:
+    case VERIFY_10:
     case SEEK_10:
     case SYNCHRONIZE_CACHE:
     case LOCK_UNLOCK_CACHE:
     case LOAD_UNLOAD:
     case SET_CD_SPEED:
     case SET_LIMITS:
-    case WRITE_LONG:
+    case WRITE_LONG_10:
     case MOVE_MEDIUM:
     case UPDATE_BLOCK:
         req->cmd.xfer = 0;
         break;
     case MODE_SENSE:
         break;
-    case WRITE_SAME:
+    case WRITE_SAME_10:
         req->cmd.xfer = 1;
         break;
-    case READ_CAPACITY:
+    case READ_CAPACITY_10:
         req->cmd.xfer = 8;
         break;
     case READ_BLOCK_LIMITS:
@@ -264,7 +265,7 @@ static int scsi_req_length(SCSIRequest *req, uint8_t *cmd)
         req->cmd.xfer *= 8;
         break;
     case WRITE_10:
-    case WRITE_VERIFY:
+    case WRITE_VERIFY_10:
     case WRITE_6:
     case WRITE_12:
     case WRITE_VERIFY_12:
@@ -324,7 +325,7 @@ static void scsi_req_xfer_mode(SCSIRequest *req)
     switch (req->cmd.buf[0]) {
     case WRITE_6:
     case WRITE_10:
-    case WRITE_VERIFY:
+    case WRITE_VERIFY_10:
     case WRITE_12:
     case WRITE_VERIFY_12:
     case WRITE_16:
@@ -344,14 +345,13 @@ static void scsi_req_xfer_mode(SCSIRequest *req)
     case SEARCH_HIGH:
     case SEARCH_LOW:
     case UPDATE_BLOCK:
-    case WRITE_LONG:
-    case WRITE_SAME:
+    case WRITE_LONG_10:
+    case WRITE_SAME_10:
     case SEARCH_HIGH_12:
     case SEARCH_EQUAL_12:
     case SEARCH_LOW_12:
     case MEDIUM_SCAN:
     case SEND_VOLUME_TAG:
-    case WRITE_LONG_2:
     case PERSISTENT_RESERVE_OUT:
     case MAINTENANCE_OUT:
         req->cmd.mode = SCSI_XFER_TO_DEV;
@@ -515,6 +515,7 @@ static const char *scsi_command_name(uint8_t cmd)
 {
     static const char *names[] = {
         [ TEST_UNIT_READY          ] = "TEST_UNIT_READY",
+        [ REWIND                   ] = "REWIND",
         [ REQUEST_SENSE            ] = "REQUEST_SENSE",
         [ FORMAT_UNIT              ] = "FORMAT_UNIT",
         [ READ_BLOCK_LIMITS        ] = "READ_BLOCK_LIMITS",
@@ -539,13 +540,12 @@ static const char *scsi_command_name(uint8_t cmd)
         [ RECEIVE_DIAGNOSTIC       ] = "RECEIVE_DIAGNOSTIC",
         [ SEND_DIAGNOSTIC          ] = "SEND_DIAGNOSTIC",
         [ ALLOW_MEDIUM_REMOVAL     ] = "ALLOW_MEDIUM_REMOVAL",
-
-        [ READ_CAPACITY            ] = "READ_CAPACITY",
+        [ READ_CAPACITY_10         ] = "READ_CAPACITY_10",
         [ READ_10                  ] = "READ_10",
         [ WRITE_10                 ] = "WRITE_10",
         [ SEEK_10                  ] = "SEEK_10",
-        [ WRITE_VERIFY             ] = "WRITE_VERIFY",
-        [ VERIFY                   ] = "VERIFY",
+        [ WRITE_VERIFY_10          ] = "WRITE_VERIFY_10",
+        [ VERIFY_10                ] = "VERIFY_10",
         [ SEARCH_HIGH              ] = "SEARCH_HIGH",
         [ SEARCH_EQUAL             ] = "SEARCH_EQUAL",
         [ SEARCH_LOW               ] = "SEARCH_LOW",
@@ -561,11 +561,14 @@ static const char *scsi_command_name(uint8_t cmd)
         [ WRITE_BUFFER             ] = "WRITE_BUFFER",
         [ READ_BUFFER              ] = "READ_BUFFER",
         [ UPDATE_BLOCK             ] = "UPDATE_BLOCK",
-        [ READ_LONG                ] = "READ_LONG",
-        [ WRITE_LONG               ] = "WRITE_LONG",
+        [ READ_LONG_10             ] = "READ_LONG_10",
+        [ WRITE_LONG_10            ] = "WRITE_LONG_10",
         [ CHANGE_DEFINITION        ] = "CHANGE_DEFINITION",
-        [ WRITE_SAME               ] = "WRITE_SAME",
+        [ WRITE_SAME_10            ] = "WRITE_SAME_10",
+        [ UNMAP                    ] = "UNMAP",
         [ READ_TOC                 ] = "READ_TOC",
+        [ REPORT_DENSITY_SUPPORT   ] = "REPORT_DENSITY_SUPPORT",
+        [ GET_CONFIGURATION        ] = "GET_CONFIGURATION",
         [ LOG_SELECT               ] = "LOG_SELECT",
         [ LOG_SENSE                ] = "LOG_SENSE",
         [ MODE_SELECT_10           ] = "MODE_SELECT_10",
@@ -574,27 +577,39 @@ static const char *scsi_command_name(uint8_t cmd)
         [ MODE_SENSE_10            ] = "MODE_SENSE_10",
         [ PERSISTENT_RESERVE_IN    ] = "PERSISTENT_RESERVE_IN",
         [ PERSISTENT_RESERVE_OUT   ] = "PERSISTENT_RESERVE_OUT",
+        [ WRITE_FILEMARKS_16       ] = "WRITE_FILEMARKS_16",
+        [ EXTENDED_COPY            ] = "EXTENDED_COPY",
+        [ ATA_PASSTHROUGH          ] = "ATA_PASSTHROUGH",
+        [ ACCESS_CONTROL_IN        ] = "ACCESS_CONTROL_IN",
+        [ ACCESS_CONTROL_OUT       ] = "ACCESS_CONTROL_OUT",
+        [ READ_16                  ] = "READ_16",
+        [ COMPARE_AND_WRITE        ] = "COMPARE_AND_WRITE",
+        [ WRITE_16                 ] = "WRITE_16",
+        [ WRITE_VERIFY_16          ] = "WRITE_VERIFY_16",
+        [ VERIFY_16                ] = "VERIFY_16",
+        [ SYNCHRONIZE_CACHE_16     ] = "SYNCHRONIZE_CACHE_16",
+        [ LOCATE_16                ] = "LOCATE_16",
+        [ WRITE_SAME_16            ] = "WRITE_SAME_16",
+        [ ERASE_16                 ] = "ERASE_16",
+        [ SERVICE_ACTION_IN        ] = "SERVICE_ACTION_IN",
+        [ WRITE_LONG_16            ] = "WRITE_LONG_16",
+        [ REPORT_LUNS              ] = "REPORT_LUNS",
+        [ BLANK                    ] = "BLANK",
+        [ MAINTENANCE_IN           ] = "MAINTENANCE_IN",
+        [ MAINTENANCE_OUT          ] = "MAINTENANCE_OUT",
         [ MOVE_MEDIUM              ] = "MOVE_MEDIUM",
+        [ LOAD_UNLOAD              ] = "LOAD_UNLOAD",
         [ READ_12                  ] = "READ_12",
         [ WRITE_12                 ] = "WRITE_12",
         [ WRITE_VERIFY_12          ] = "WRITE_VERIFY_12",
+        [ VERIFY_12                ] = "VERIFY_12",
         [ SEARCH_HIGH_12           ] = "SEARCH_HIGH_12",
         [ SEARCH_EQUAL_12          ] = "SEARCH_EQUAL_12",
         [ SEARCH_LOW_12            ] = "SEARCH_LOW_12",
         [ READ_ELEMENT_STATUS      ] = "READ_ELEMENT_STATUS",
         [ SEND_VOLUME_TAG          ] = "SEND_VOLUME_TAG",
-        [ WRITE_LONG_2             ] = "WRITE_LONG_2",
-
-        [ REPORT_DENSITY_SUPPORT   ] = "REPORT_DENSITY_SUPPORT",
-        [ GET_CONFIGURATION        ] = "GET_CONFIGURATION",
-        [ READ_16                  ] = "READ_16",
-        [ WRITE_16                 ] = "WRITE_16",
-        [ WRITE_VERIFY_16          ] = "WRITE_VERIFY_16",
-        [ SERVICE_ACTION_IN        ] = "SERVICE_ACTION_IN",
-        [ REPORT_LUNS              ] = "REPORT_LUNS",
-        [ LOAD_UNLOAD              ] = "LOAD_UNLOAD",
+        [ READ_DEFECT_DATA_12      ] = "READ_DEFECT_DATA_12",
         [ SET_CD_SPEED             ] = "SET_CD_SPEED",
-        [ BLANK                    ] = "BLANK",
     };
 
     if (cmd >= ARRAY_SIZE(names) || names[cmd] == NULL)
diff --git a/hw/scsi-defs.h b/hw/scsi-defs.h
index 1f40c5c..f644860 100644
--- a/hw/scsi-defs.h
+++ b/hw/scsi-defs.h
@@ -25,6 +25,7 @@
  */
 
 #define TEST_UNIT_READY       0x00
+#define REWIND                0x01
 #define REQUEST_SENSE         0x03
 #define FORMAT_UNIT           0x04
 #define READ_BLOCK_LIMITS     0x05
@@ -47,13 +48,13 @@
 #define RECEIVE_DIAGNOSTIC    0x1c
 #define SEND_DIAGNOSTIC       0x1d
 #define ALLOW_MEDIUM_REMOVAL  0x1e
-
-#define READ_CAPACITY         0x25
+#define READ_CAPACITY_10      0x25
 #define READ_10               0x28
 #define WRITE_10              0x2a
 #define SEEK_10               0x2b
-#define WRITE_VERIFY          0x2e
-#define VERIFY                0x2f
+#define LOCATE_10             0x2b
+#define WRITE_VERIFY_10       0x2e
+#define VERIFY_10             0x2f
 #define SEARCH_HIGH           0x30
 #define SEARCH_EQUAL          0x31
 #define SEARCH_LOW            0x32
@@ -69,11 +70,14 @@
 #define WRITE_BUFFER          0x3b
 #define READ_BUFFER           0x3c
 #define UPDATE_BLOCK          0x3d
-#define READ_LONG             0x3e
-#define WRITE_LONG            0x3f
+#define READ_LONG_10          0x3e
+#define WRITE_LONG_10         0x3f
 #define CHANGE_DEFINITION     0x40
-#define WRITE_SAME            0x41
+#define WRITE_SAME_10         0x41
+#define UNMAP                 0x42
 #define READ_TOC              0x43
+#define REPORT_DENSITY_SUPPORT 0x44
+#define GET_CONFIGURATION     0x46
 #define LOG_SELECT            0x4c
 #define LOG_SENSE             0x4d
 #define MODE_SELECT_10        0x55
@@ -82,32 +86,40 @@
 #define MODE_SENSE_10         0x5a
 #define PERSISTENT_RESERVE_IN 0x5e
 #define PERSISTENT_RESERVE_OUT 0x5f
+#define VARLENGTH_CDB         0x7f
+#define WRITE_FILEMARKS_16    0x80
+#define EXTENDED_COPY         0x83
+#define ATA_PASSTHROUGH       0x85
+#define ACCESS_CONTROL_IN     0x86
+#define ACCESS_CONTROL_OUT    0x87
+#define READ_16               0x88
+#define COMPARE_AND_WRITE     0x89
+#define WRITE_16              0x8a
+#define WRITE_VERIFY_16       0x8e
+#define VERIFY_16             0x8f
+#define SYNCHRONIZE_CACHE_16  0x91
+#define LOCATE_16             0x92
 #define WRITE_SAME_16         0x93
+#define ERASE_16              0x93
+#define SERVICE_ACTION_IN     0x9e
+#define WRITE_LONG_16         0x9f
+#define REPORT_LUNS           0xa0
+#define BLANK                 0xa1
 #define MAINTENANCE_IN        0xa3
 #define MAINTENANCE_OUT       0xa4
 #define MOVE_MEDIUM           0xa5
+#define LOAD_UNLOAD           0xa6
 #define READ_12               0xa8
 #define WRITE_12              0xaa
 #define WRITE_VERIFY_12       0xae
+#define VERIFY_12             0xaf
 #define SEARCH_HIGH_12        0xb0
 #define SEARCH_EQUAL_12       0xb1
 #define SEARCH_LOW_12         0xb2
 #define READ_ELEMENT_STATUS   0xb8
 #define SEND_VOLUME_TAG       0xb6
-#define WRITE_LONG_2          0xea
-
-/* from hw/scsi-generic.c */
-#define REWIND 0x01
-#define REPORT_DENSITY_SUPPORT 0x44
-#define GET_CONFIGURATION 0x46
-#define READ_16 0x88
-#define WRITE_16 0x8a
-#define WRITE_VERIFY_16 0x8e
-#define SERVICE_ACTION_IN 0x9e
-#define REPORT_LUNS 0xa0
-#define LOAD_UNLOAD 0xa6
-#define SET_CD_SPEED 0xbb
-#define BLANK 0xa1
+#define READ_DEFECT_DATA_12   0xb7
+#define SET_CD_SPEED          0xbb
 
 /*
  *  SAM Status codes
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index abf0bd2..03f244e 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -885,7 +885,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
     case ALLOW_MEDIUM_REMOVAL:
         bdrv_set_locked(s->bs, req->cmd.buf[4] & 1);
         break;
-    case READ_CAPACITY:
+    case READ_CAPACITY_10:
         /* The normal LEN field for this command is zero.  */
         memset(outbuf, 0, 8);
         bdrv_get_geometry(s->bs, &nb_sectors);
@@ -970,7 +970,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
         outbuf[3] = 8;
         buflen = 16;
         break;
-    case VERIFY:
+    case VERIFY_10:
         break;
     default:
         scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_OPCODE));
@@ -1046,13 +1046,13 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
     case RELEASE_10:
     case START_STOP:
     case ALLOW_MEDIUM_REMOVAL:
-    case READ_CAPACITY:
+    case READ_CAPACITY_10:
     case SYNCHRONIZE_CACHE:
     case READ_TOC:
     case GET_CONFIGURATION:
     case SERVICE_ACTION_IN:
     case REPORT_LUNS:
-    case VERIFY:
+    case VERIFY_10:
         rc = scsi_disk_emulate_command(r, outbuf);
         if (rc < 0) {
             return 0;
@@ -1075,7 +1075,7 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
     case WRITE_10:
     case WRITE_12:
     case WRITE_16:
-    case WRITE_VERIFY:
+    case WRITE_VERIFY_10:
     case WRITE_VERIFY_12:
     case WRITE_VERIFY_16:
         len = r->req.cmd.xfer / s->qdev.blocksize;
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 63361b3..7b0026e 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -406,7 +406,7 @@ static int get_blocksize(BlockDriverState *bdrv)
 
     memset(cmd, 0, sizeof(cmd));
     memset(buf, 0, sizeof(buf));
-    cmd[0] = READ_CAPACITY;
+    cmd[0] = READ_CAPACITY_10;
 
     memset(&io_header, 0, sizeof(io_header));
     io_header.interface_id = 'S';
commit 8bd3e139c638d9742e12da33007a19c5204302af
Author: Hannes Reinecke <hare at suse.de>
Date:   Fri Jul 22 16:51:14 2011 +0200

    scsi: Remove REZERO_UNIT emulation
    
    REZERO_UNIT command is obsolete. Remove support for it.
    
    Signed-off-by: Hannes Reinecke <hare at suse.de>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index facc98d..52a6784 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -223,7 +223,6 @@ static int scsi_req_length(SCSIRequest *req, uint8_t *cmd)
 
     switch(cmd[0]) {
     case TEST_UNIT_READY:
-    case REZERO_UNIT:
     case START_STOP:
     case SEEK_6:
     case WRITE_FILEMARKS:
@@ -516,8 +515,6 @@ static const char *scsi_command_name(uint8_t cmd)
 {
     static const char *names[] = {
         [ TEST_UNIT_READY          ] = "TEST_UNIT_READY",
-        [ REZERO_UNIT              ] = "REZERO_UNIT",
-        /* REWIND and REZERO_UNIT use the same operation code */
         [ REQUEST_SENSE            ] = "REQUEST_SENSE",
         [ FORMAT_UNIT              ] = "FORMAT_UNIT",
         [ READ_BLOCK_LIMITS        ] = "READ_BLOCK_LIMITS",
diff --git a/hw/scsi-defs.h b/hw/scsi-defs.h
index 8513983..1f40c5c 100644
--- a/hw/scsi-defs.h
+++ b/hw/scsi-defs.h
@@ -25,7 +25,6 @@
  */
 
 #define TEST_UNIT_READY       0x00
-#define REZERO_UNIT           0x01
 #define REQUEST_SENSE         0x03
 #define FORMAT_UNIT           0x04
 #define READ_BLOCK_LIMITS     0x05
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 715f2cd..abf0bd2 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -972,12 +972,6 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, 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:
         scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_OPCODE));
         return -1;
@@ -1059,7 +1053,6 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
     case SERVICE_ACTION_IN:
     case REPORT_LUNS:
     case VERIFY:
-    case REZERO_UNIT:
         rc = scsi_disk_emulate_command(r, outbuf);
         if (rc < 0) {
             return 0;
commit 3790372c963dbc87d4efdf24f8b718c283798fa0
Author: Hannes Reinecke <hare at suse.de>
Date:   Fri Jul 22 16:51:13 2011 +0200

    scsi: Remove references to SET_WINDOW
    
    SET_WINDOW command is vendor-specific only.
    So we shouldn't try to emulate it.
    
    Signed-off-by: Hannes Reinecke <hare at suse.de>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 8b1a412..facc98d 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -350,7 +350,6 @@ static void scsi_req_xfer_mode(SCSIRequest *req)
     case SEARCH_HIGH_12:
     case SEARCH_EQUAL_12:
     case SEARCH_LOW_12:
-    case SET_WINDOW:
     case MEDIUM_SCAN:
     case SEND_VOLUME_TAG:
     case WRITE_LONG_2:
@@ -544,7 +543,6 @@ static const char *scsi_command_name(uint8_t cmd)
         [ SEND_DIAGNOSTIC          ] = "SEND_DIAGNOSTIC",
         [ ALLOW_MEDIUM_REMOVAL     ] = "ALLOW_MEDIUM_REMOVAL",
 
-        [ SET_WINDOW               ] = "SET_WINDOW",
         [ READ_CAPACITY            ] = "READ_CAPACITY",
         [ READ_10                  ] = "READ_10",
         [ WRITE_10                 ] = "WRITE_10",
diff --git a/hw/scsi-defs.h b/hw/scsi-defs.h
index 413cce0..8513983 100644
--- a/hw/scsi-defs.h
+++ b/hw/scsi-defs.h
@@ -49,7 +49,6 @@
 #define SEND_DIAGNOSTIC       0x1d
 #define ALLOW_MEDIUM_REMOVAL  0x1e
 
-#define SET_WINDOW            0x24
 #define READ_CAPACITY         0x25
 #define READ_10               0x28
 #define WRITE_10              0x2a
commit 5f71d32f0da4d1e578738f765b57fbfaf4bd3214
Author: Hannes Reinecke <hare at suse.de>
Date:   Fri Jul 22 16:51:12 2011 +0200

    scsi-disk: Codingstyle fixes
    
    Replace tabs with spaces.
    
    Signed-off-by: Hannes Reinecke <hare at suse.de>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index f42a5d1..715f2cd 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -526,7 +526,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
     memset(outbuf, 0, buflen);
 
     if (req->lun) {
-        outbuf[0] = 0x7f;	/* LUN not supported */
+        outbuf[0] = 0x7f;       /* LUN not supported */
         return buflen;
     }
 
@@ -836,7 +836,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
     case TEST_UNIT_READY:
         if (!bdrv_is_inserted(s->bs))
             goto not_ready;
-	break;
+        break;
     case REQUEST_SENSE:
         if (req->cmd.xfer < 4)
             goto illegal_request;
@@ -848,7 +848,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
         buflen = scsi_disk_emulate_inquiry(req, outbuf);
         if (buflen < 0)
             goto illegal_request;
-	break;
+        break;
     case MODE_SENSE:
     case MODE_SENSE_10:
         buflen = scsi_disk_emulate_mode_sense(req, outbuf);
@@ -881,14 +881,14 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
             /* load/eject medium */
             bdrv_eject(s->bs, !(req->cmd.buf[4] & 1));
         }
-	break;
+        break;
     case ALLOW_MEDIUM_REMOVAL:
         bdrv_set_locked(s->bs, req->cmd.buf[4] & 1);
-	break;
+        break;
     case READ_CAPACITY:
         /* The normal LEN field for this command is zero.  */
-	memset(outbuf, 0, 8);
-	bdrv_get_geometry(s->bs, &nb_sectors);
+        memset(outbuf, 0, 8);
+        bdrv_get_geometry(s->bs, &nb_sectors);
         if (!nb_sectors)
             goto not_ready;
         nb_sectors /= s->cluster_size;
@@ -908,7 +908,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
         outbuf[6] = s->cluster_size * 2;
         outbuf[7] = 0;
         buflen = 8;
-	break;
+        break;
     case SYNCHRONIZE_CACHE:
         ret = bdrv_flush(s->bs);
         if (ret < 0) {
commit efc8243d00ab4cf4fa05a9be93233cb883b7caa0
Author: Serge E. Hallyn <serge at hallyn.com>
Date:   Mon Jul 25 18:34:35 2011 +0000

    block/vpc.c: Detect too-large vpc file
    
    VHD files technically can be up to 2Tb, but virtual pc is limited
    to 127G.  Currently qemu-img refused to create vpc files > 127G,
    but it is failing to return error when converting from a non-vpc
    VHD file which is >127G.  It returns success, but creates a truncated
    converted image.  Also, qemu-img info claims the vpc file is 127G
    (and clean).
    
    This patch detects a too-large vpc file and returns -EFBIG.  Without
    this patch,
    
    =============================================================
    root at ip-10-38-123-242:~/qemu-fixed# qemu-img info /mnt/140g-dynamic.vhd
    image: /mnt/140g-dynamic.vhd
    file format: vpc
    virtual size: 127G (136899993600 bytes)
    disk size: 284K
    root at ip-10-38-123-242:~/qemu-fixed# qemu-img convert -f vpc -O raw /mnt/140g-dynamic.vhd /mnt/y
    root at ip-10-38-123-242:~/qemu-fixed# echo $?
    0
    root at ip-10-38-123-242:~/qemu-fixed# qemu-img info /mnt/y
    image: /mnt/y
    file format: raw
    virtual size: 127G (136899993600 bytes)
    disk size: 0
    =============================================================
    
    (The 140G image was truncated with no warning or error.)
    
    With the patch, I get:
    
    =============================================================
    root at ip-10-38-123-242:~/qemu-fixed# ./qemu-img info /mnt/140g-dynamic.vhd
    qemu-img: Could not open '/mnt/140g-dynamic.vhd': File too large
    root at ip-10-38-123-242:~/qemu-fixed# ./qemu-img convert -f vpc -O raw /mnt/140g-dynamic.vhd /mnt/y
    qemu-img: Could not open '/mnt/140g-dynamic.vhd': File too large
    qemu-img: Could not open '/mnt/140g-dynamic.vhd'
    =============================================================
    
    See https://bugs.launchpad.net/qemu/+bug/814222 for details.
    
    Signed-off-by: Serge Hallyn <serge.hallyn at canonical.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/vpc.c b/block/vpc.c
index 56865da..fdd5236 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -156,6 +156,7 @@ static int vpc_open(BlockDriverState *bs, int flags)
     struct vhd_dyndisk_header* dyndisk_header;
     uint8_t buf[HEADER_SIZE];
     uint32_t checksum;
+    int err = -1;
 
     if (bdrv_pread(bs->file, 0, s->footer_buf, HEADER_SIZE) != HEADER_SIZE)
         goto fail;
@@ -176,6 +177,11 @@ static int vpc_open(BlockDriverState *bs, int flags)
     bs->total_sectors = (int64_t)
         be16_to_cpu(footer->cyls) * footer->heads * footer->secs_per_cyl;
 
+    if (bs->total_sectors >= 65535 * 16 * 255) {
+        err = -EFBIG;
+        goto fail;
+    }
+
     if (bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), buf, HEADER_SIZE)
             != HEADER_SIZE)
         goto fail;
@@ -222,7 +228,7 @@ static int vpc_open(BlockDriverState *bs, int flags)
 
     return 0;
  fail:
-    return -1;
+    return err;
 }
 
 /*
commit 49aa46bb4b894ff8bdb0339ee2a5dd3fcfe93ecd
Author: Markus Armbruster <armbru at redhat.com>
Date:   Wed Jul 20 18:23:43 2011 +0200

    block: Don't let locked flag prevent medium load
    
    Commit aea2a33c made bdrv_eject() obey the locked flag.  Correct for
    medium eject (eject_flag set), incorrect for medium load (eject_flag
    clear).  See MMC-5 Table 341 "Actions for Lock/Unlock/Eject".
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index 7c25fe4..8859f9b 100644
--- a/block.c
+++ b/block.c
@@ -2771,7 +2771,7 @@ int bdrv_eject(BlockDriverState *bs, int eject_flag)
 {
     BlockDriver *drv = bs->drv;
 
-    if (bs->locked) {
+    if (eject_flag && bs->locked) {
         return -EBUSY;
     }
 
commit 822e1cd17e8fa3ae98d0481c20f042316ace3fbc
Author: Markus Armbruster <armbru at redhat.com>
Date:   Wed Jul 20 18:23:42 2011 +0200

    block: Make BlockDriver method bdrv_eject() return void
    
    Callees always return 0, except for FreeBSD's cdrom_eject(), which
    returns -ENOTSUP when the device is in a terminally wedged state.
    
    The only caller is bdrv_eject(), and it maps -ENOTSUP to 0 since
    commit 4be9762a.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index 81a8257..7c25fe4 100644
--- a/block.c
+++ b/block.c
@@ -2770,25 +2770,16 @@ int bdrv_media_changed(BlockDriverState *bs)
 int bdrv_eject(BlockDriverState *bs, int eject_flag)
 {
     BlockDriver *drv = bs->drv;
-    int ret;
 
     if (bs->locked) {
         return -EBUSY;
     }
 
-    if (!drv || !drv->bdrv_eject) {
-        ret = -ENOTSUP;
-    } else {
-        ret = drv->bdrv_eject(bs, eject_flag);
-    }
-    if (ret == -ENOTSUP) {
-        ret = 0;
+    if (drv && drv->bdrv_eject) {
+        drv->bdrv_eject(bs, eject_flag);
     }
-    if (ret >= 0) {
-        bs->tray_open = eject_flag;
-    }
-
-    return ret;
+    bs->tray_open = eject_flag;
+    return 0;
 }
 
 int bdrv_is_locked(BlockDriverState *bs)
diff --git a/block/raw-posix.c b/block/raw-posix.c
index 5241308..6672d31 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -1254,7 +1254,7 @@ static int floppy_media_changed(BlockDriverState *bs)
     return ret;
 }
 
-static int floppy_eject(BlockDriverState *bs, int eject_flag)
+static void floppy_eject(BlockDriverState *bs, int eject_flag)
 {
     BDRVRawState *s = bs->opaque;
     int fd;
@@ -1269,8 +1269,6 @@ static int floppy_eject(BlockDriverState *bs, int eject_flag)
             perror("FDEJECT");
         close(fd);
     }
-
-    return 0;
 }
 
 static BlockDriver bdrv_host_floppy = {
@@ -1348,7 +1346,7 @@ static int cdrom_is_inserted(BlockDriverState *bs)
     return 0;
 }
 
-static int cdrom_eject(BlockDriverState *bs, int eject_flag)
+static void cdrom_eject(BlockDriverState *bs, int eject_flag)
 {
     BDRVRawState *s = bs->opaque;
 
@@ -1359,8 +1357,6 @@ static int cdrom_eject(BlockDriverState *bs, int eject_flag)
         if (ioctl(s->fd, CDROMCLOSETRAY, NULL) < 0)
             perror("CDROMEJECT");
     }
-
-    return 0;
 }
 
 static void cdrom_set_locked(BlockDriverState *bs, int locked)
@@ -1462,12 +1458,12 @@ static int cdrom_is_inserted(BlockDriverState *bs)
     return raw_getlength(bs) > 0;
 }
 
-static int cdrom_eject(BlockDriverState *bs, int eject_flag)
+static void cdrom_eject(BlockDriverState *bs, int eject_flag)
 {
     BDRVRawState *s = bs->opaque;
 
     if (s->fd < 0)
-        return -ENOTSUP;
+        return;
 
     (void) ioctl(s->fd, CDIOCALLOW);
 
@@ -1479,9 +1475,7 @@ static int cdrom_eject(BlockDriverState *bs, int eject_flag)
             perror("CDIOCCLOSE");
     }
 
-    if (cdrom_reopen(bs) < 0)
-        return -ENOTSUP;
-    return 0;
+    cdrom_reopen(bs);
 }
 
 static void cdrom_set_locked(BlockDriverState *bs, int locked)
diff --git a/block/raw.c b/block/raw.c
index 1398a9c..cb6203e 100644
--- a/block/raw.c
+++ b/block/raw.c
@@ -75,9 +75,9 @@ static int raw_is_inserted(BlockDriverState *bs)
     return bdrv_is_inserted(bs->file);
 }
 
-static int raw_eject(BlockDriverState *bs, int eject_flag)
+static void raw_eject(BlockDriverState *bs, int eject_flag)
 {
-    return bdrv_eject(bs->file, eject_flag);
+    bdrv_eject(bs->file, eject_flag);
 }
 
 static void raw_set_locked(BlockDriverState *bs, int locked)
diff --git a/block_int.h b/block_int.h
index e0b638c..efefbee 100644
--- a/block_int.h
+++ b/block_int.h
@@ -112,7 +112,7 @@ struct BlockDriver {
     /* removable device specific */
     int (*bdrv_is_inserted)(BlockDriverState *bs);
     int (*bdrv_media_changed)(BlockDriverState *bs);
-    int (*bdrv_eject)(BlockDriverState *bs, int eject_flag);
+    void (*bdrv_eject)(BlockDriverState *bs, int eject_flag);
     void (*bdrv_set_locked)(BlockDriverState *bs, int locked);
 
     /* to control generic scsi devices */
commit 7bf37feddcfa527304cfdc02bd2db8912ee9bf8c
Author: Markus Armbruster <armbru at redhat.com>
Date:   Wed Jul 20 18:23:41 2011 +0200

    block: Make BlockDriver method bdrv_set_locked() return void
    
    The only caller is bdrv_set_locked(), and it ignores the value.
    
    Callees always return 0, except for FreeBSD's cdrom_set_locked(),
    which returns -ENOTSUP when the device is in a terminally wedged
    state.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/raw-posix.c b/block/raw-posix.c
index cd89c83..5241308 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -1363,7 +1363,7 @@ static int cdrom_eject(BlockDriverState *bs, int eject_flag)
     return 0;
 }
 
-static int cdrom_set_locked(BlockDriverState *bs, int locked)
+static void cdrom_set_locked(BlockDriverState *bs, int locked)
 {
     BDRVRawState *s = bs->opaque;
 
@@ -1374,8 +1374,6 @@ static int cdrom_set_locked(BlockDriverState *bs, int locked)
          */
         /* perror("CDROM_LOCKDOOR"); */
     }
-
-    return 0;
 }
 
 static BlockDriver bdrv_host_cdrom = {
@@ -1486,12 +1484,12 @@ static int cdrom_eject(BlockDriverState *bs, int eject_flag)
     return 0;
 }
 
-static int cdrom_set_locked(BlockDriverState *bs, int locked)
+static void cdrom_set_locked(BlockDriverState *bs, int locked)
 {
     BDRVRawState *s = bs->opaque;
 
     if (s->fd < 0)
-        return -ENOTSUP;
+        return;
     if (ioctl(s->fd, (locked ? CDIOCPREVENT : CDIOCALLOW)) < 0) {
         /*
          * Note: an error can happen if the distribution automatically
@@ -1499,8 +1497,6 @@ static int cdrom_set_locked(BlockDriverState *bs, int locked)
          */
         /* perror("CDROM_LOCKDOOR"); */
     }
-
-    return 0;
 }
 
 static BlockDriver bdrv_host_cdrom = {
diff --git a/block/raw.c b/block/raw.c
index b0f72d6..1398a9c 100644
--- a/block/raw.c
+++ b/block/raw.c
@@ -80,10 +80,9 @@ static int raw_eject(BlockDriverState *bs, int eject_flag)
     return bdrv_eject(bs->file, eject_flag);
 }
 
-static int raw_set_locked(BlockDriverState *bs, int locked)
+static void raw_set_locked(BlockDriverState *bs, int locked)
 {
     bdrv_set_locked(bs->file, locked);
-    return 0;
 }
 
 static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
diff --git a/block_int.h b/block_int.h
index efb6803..e0b638c 100644
--- a/block_int.h
+++ b/block_int.h
@@ -113,7 +113,7 @@ struct BlockDriver {
     int (*bdrv_is_inserted)(BlockDriverState *bs);
     int (*bdrv_media_changed)(BlockDriverState *bs);
     int (*bdrv_eject)(BlockDriverState *bs, int eject_flag);
-    int (*bdrv_set_locked)(BlockDriverState *bs, int locked);
+    void (*bdrv_set_locked)(BlockDriverState *bs, int locked);
 
     /* to control generic scsi devices */
     int (*bdrv_ioctl)(BlockDriverState *bs, unsigned long int req, void *buf);
commit 02266d547a6c7b10e1ac1574ec69b92f4e28f817
Author: Markus Armbruster <armbru at redhat.com>
Date:   Wed Jul 20 18:23:40 2011 +0200

    block/raw-win32: Drop disabled code for removable host devices
    
    It's been disabled since the start (commit 19cb3738, Aug 2006), and
    has been untouched except for spelling fixes and such.  I don't feel
    like dragging it along any further.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/raw-win32.c b/block/raw-win32.c
index 91067e7..e47cfe0 100644
--- a/block/raw-win32.c
+++ b/block/raw-win32.c
@@ -393,41 +393,6 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
     return 0;
 }
 
-#if 0
-/***********************************************/
-/* removable device additional commands */
-
-static int raw_is_inserted(BlockDriverState *bs)
-{
-    return 1;
-}
-
-static int raw_media_changed(BlockDriverState *bs)
-{
-    return -ENOTSUP;
-}
-
-static int raw_eject(BlockDriverState *bs, int eject_flag)
-{
-    DWORD ret_count;
-
-    if (s->type == FTYPE_FILE)
-        return -ENOTSUP;
-    if (eject_flag) {
-        DeviceIoControl(s->hfile, IOCTL_STORAGE_EJECT_MEDIA,
-                        NULL, 0, NULL, 0, &lpBytesReturned, NULL);
-    } else {
-        DeviceIoControl(s->hfile, IOCTL_STORAGE_LOAD_MEDIA,
-                        NULL, 0, NULL, 0, &lpBytesReturned, NULL);
-    }
-}
-
-static int raw_set_locked(BlockDriverState *bs, int locked)
-{
-    return -ENOTSUP;
-}
-#endif
-
 static int hdev_has_zero_init(BlockDriverState *bs)
 {
     return 0;
commit a19712b0dbe43016fb17ec48bfff2f360225fe97
Author: Markus Armbruster <armbru at redhat.com>
Date:   Wed Jul 20 18:23:36 2011 +0200

    block: Reset device model callbacks on detach
    
    BlockDriverState members change_cb and change_opaque are initially
    null.  The device model may set them, with bdrv_set_change_cb().  If
    the device model gets detached (hot unplug), they're left dangling.
    Only safe because device hot unplug automatically destroys the
    BlockDriverState.  But that's a questionable feature, best not to rely
    on it.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index 9549b9e..81a8257 100644
--- a/block.c
+++ b/block.c
@@ -730,6 +730,8 @@ void bdrv_detach(BlockDriverState *bs, DeviceState *qdev)
 {
     assert(bs->peer == qdev);
     bs->peer = NULL;
+    bs->change_cb = NULL;
+    bs->change_opaque = NULL;
 }
 
 DeviceState *bdrv_get_attached(BlockDriverState *bs)
commit ea8f942fe46dd10e0946f02ab9d698fb41e958f7
Author: Markus Armbruster <armbru at redhat.com>
Date:   Wed Jul 20 18:23:35 2011 +0200

    blockdev: Make eject fail for non-removable drives even with -f
    
    Ejecting hard disk platters can only end in tears.
    
    If you need to revoke access to an image, use drive_del, not eject -f.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/blockdev.c b/blockdev.c
index 0b8d3a4..a25367a 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -646,16 +646,13 @@ out:
 
 static int eject_device(Monitor *mon, BlockDriverState *bs, int force)
 {
-    if (!force) {
-        if (!bdrv_is_removable(bs)) {
-            qerror_report(QERR_DEVICE_NOT_REMOVABLE,
-                           bdrv_get_device_name(bs));
-            return -1;
-        }
-        if (bdrv_is_locked(bs)) {
-            qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
-            return -1;
-        }
+    if (!bdrv_is_removable(bs)) {
+        qerror_report(QERR_DEVICE_NOT_REMOVABLE, bdrv_get_device_name(bs));
+        return -1;
+    }
+    if (!force && bdrv_is_locked(bs)) {
+        qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
+        return -1;
     }
     bdrv_close(bs);
     return 0;
commit 43e86c8f5b6d9f6279e20dede4e1f7829bdc43b7
Author: Isaku Yamahata <yamahata at valinux.co.jp>
Date:   Fri Jul 29 10:01:43 2011 +0900

    pcie_host: verify mmcfg address range
    
    For a conventional pci device behind
    a pcie-to-pci bridge, pci_host handlers get confused by
    an out of bounds access in the range [256, 4K).
    
    Check for such an access and make it have no effect.
    
    Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
    Signed-off-by: Michael S. Tsirkin <mst at redhat.com>

diff --git a/hw/pcie_host.c b/hw/pcie_host.c
index f0b3d13..f9fea3d 100644
--- a/hw/pcie_host.c
+++ b/hw/pcie_host.c
@@ -56,23 +56,39 @@ static void pcie_mmcfg_data_write(PCIBus *s,
                                   uint32_t mmcfg_addr, uint32_t val, int len)
 {
     PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr);
+    uint32_t addr;
+    uint32_t limit;
 
     if (!pci_dev) {
         return;
     }
-    pci_host_config_write_common(pci_dev, PCIE_MMCFG_CONFOFFSET(mmcfg_addr),
-                                 pci_config_size(pci_dev), val, len);
+    addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr);
+    limit = pci_config_size(pci_dev);
+    if (limit <= addr) {
+        /* conventional pci device can be behind pcie-to-pci bridge.
+           256 <= addr < 4K has no effects. */
+        return;
+    }
+    pci_host_config_write_common(pci_dev, addr, limit, val, len);
 }
 
-static uint32_t pcie_mmcfg_data_read(PCIBus *s, uint32_t addr, int len)
+static uint32_t pcie_mmcfg_data_read(PCIBus *s, uint32_t mmcfg_addr, int len)
 {
-    PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, addr);
+    PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr);
+    uint32_t addr;
+    uint32_t limit;
 
     if (!pci_dev) {
         return ~0x0;
     }
-    return pci_host_config_read_common(pci_dev, PCIE_MMCFG_CONFOFFSET(addr),
-                                       pci_config_size(pci_dev), len);
+    addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr);
+    limit = pci_config_size(pci_dev);
+    if (limit <= addr) {
+        /* conventional pci device can be behind pcie-to-pci bridge.
+           256 <= addr < 4K has no effects. */
+        return ~0x0;
+    }
+    return pci_host_config_read_common(pci_dev, addr, limit, len);
 }
 
 static void pcie_mmcfg_data_writeb(void *opaque,
commit 845f85fa1597c72609bd10a37b9586b445c13d49
Author: Amit Shah <amit.shah at redhat.com>
Date:   Wed Jul 27 14:00:32 2011 +0530

    virtio: Plug memleak by freeing vdev
    
    virtio_common_init() allocates RAM for the vdev struct (and any
    additional memory, depending on the size passed to the function).  This
    memory wasn't being freed until now.
    
    Signed-off-by: Amit Shah <amit.shah at redhat.com>
    Signed-off-by: Michael S. Tsirkin <mst at redhat.com>

diff --git a/hw/virtio.c b/hw/virtio.c
index a8f4940..93dfb1e 100644
--- a/hw/virtio.c
+++ b/hw/virtio.c
@@ -834,6 +834,7 @@ void virtio_cleanup(VirtIODevice *vdev)
     if (vdev->config)
         qemu_free(vdev->config);
     qemu_free(vdev->vq);
+    qemu_free(vdev);
 }
 
 static void virtio_vmstate_change(void *opaque, int running, int reason)
commit b52dfd71f33b902e612b12f6cc89f3b61e4d3e22
Author: Amit Shah <amit.shah at redhat.com>
Date:   Wed Jul 27 14:00:31 2011 +0530

    virtio-net: don't use vdev after virtio_cleanup
    
    virtio_cleanup() will be changed by the following patch to remove the
    VirtIONet struct that gets allocated via virtio_common_init().  Ensure
    we don't dereference the structure after calling the cleanup function.
    
    Signed-off-by: Amit Shah <amit.shah at redhat.com>
    Signed-off-by: Michael S. Tsirkin <mst at redhat.com>

diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index 6997e02..09c665b 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -1073,6 +1073,6 @@ void virtio_net_exit(VirtIODevice *vdev)
         qemu_bh_delete(n->tx_bh);
     }
 
-    virtio_cleanup(&n->vdev);
     qemu_del_vlan_client(&n->nic->nc);
+    virtio_cleanup(&n->vdev);
 }
commit d92551f28eff7cb6572ed3147399e51f5f5dfc22
Author: Amit Shah <amit.shah at redhat.com>
Date:   Wed Jul 27 14:00:30 2011 +0530

    virtio-blk: Fix memleak on exit
    
    Calling virtio_cleanup() will free up memory allocated in
    virtio_common_init().
    
    Signed-off-by: Amit Shah <amit.shah at redhat.com>
    Signed-off-by: Michael S. Tsirkin <mst at redhat.com>

diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index 6471ac8..836dbc3 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -594,4 +594,5 @@ void virtio_blk_exit(VirtIODevice *vdev)
 {
     VirtIOBlock *s = to_virtio_blk(vdev);
     unregister_savevm(s->qdev, "virtio-blk", s);
+    virtio_cleanup(vdev);
 }
commit 1129714ff43bd947740d587956a655210e8b93ed
Author: Michael S. Tsirkin <mst at redhat.com>
Date:   Wed Jul 27 11:08:20 2011 +0300

    virtio-pci: use generic logic for command access
    
    In practice, guests don't generate config requests
    that cross a word boundary, so the logic to
    detect command word access is correct because
    PCI_COMMAND is 0x4. But depending on this is
    tricky, further, it will break with guests
    that do try to generate a misaligned access
    as we pass it to devices without splitting.
    
    Better to use the generic range_covers_byte for this.
    
    Signed-off-by: Michael S. Tsirkin <mst at redhat.com>

diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index d685243..4f770fe 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -27,6 +27,7 @@
 #include "kvm.h"
 #include "blockdev.h"
 #include "virtio-pci.h"
+#include "range.h"
 
 /* from Linux's linux/virtio_pci.h */
 
@@ -516,17 +517,16 @@ static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
 {
     VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
 
-    if (PCI_COMMAND == address) {
-        if (!(val & PCI_COMMAND_MASTER)) {
-            if (!(proxy->flags & VIRTIO_PCI_FLAG_BUS_MASTER_BUG)) {
-                virtio_pci_stop_ioeventfd(proxy);
-                virtio_set_status(proxy->vdev,
-                                  proxy->vdev->status & ~VIRTIO_CONFIG_S_DRIVER_OK);
-            }
-        }
+    pci_default_write_config(pci_dev, address, val, len);
+
+    if (range_covers_byte(address, len, PCI_COMMAND) &&
+        !(pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER) &&
+        !(proxy->flags & VIRTIO_PCI_FLAG_BUS_MASTER_BUG)) {
+        virtio_pci_stop_ioeventfd(proxy);
+        virtio_set_status(proxy->vdev,
+                          proxy->vdev->status & ~VIRTIO_CONFIG_S_DRIVER_OK);
     }
 
-    pci_default_write_config(pci_dev, address, val, len);
     msix_write_config(pci_dev, address, val, len);
 }
 
commit 42e4126b793d15ec40f3a84017e1d8afecda1b6d
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Fri Jul 22 11:05:01 2011 +0200

    pci: Common overflow prevention
    
    Introduce pci_config_read/write_common helpers to prevent passing
    accesses down the callback chain that go beyond the config space limits.
    Adjust length assertions as they are no longer correct (cutting may
    generate valid 3 byte accesses).
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Michael S. Tsirkin <mst at redhat.com>

diff --git a/hw/pci.c b/hw/pci.c
index b904a4e..ef94739 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -1108,8 +1108,7 @@ uint32_t pci_default_read_config(PCIDevice *d,
                                  uint32_t address, int len)
 {
     uint32_t val = 0;
-    assert(len == 1 || len == 2 || len == 4);
-    len = MIN(len, pci_config_size(d) - address);
+
     memcpy(&val, d->config + address, len);
     return le32_to_cpu(val);
 }
@@ -1117,9 +1116,8 @@ uint32_t pci_default_read_config(PCIDevice *d,
 void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
 {
     int i, was_irq_disabled = pci_irq_disabled(d);
-    uint32_t config_size = pci_config_size(d);
 
-    for (i = 0; i < l && addr + i < config_size; val >>= 8, ++i) {
+    for (i = 0; i < l; val >>= 8, ++i) {
         uint8_t wmask = d->wmask[addr + i];
         uint8_t w1cmask = d->w1cmask[addr + i];
         assert(!(wmask & w1cmask));
diff --git a/hw/pci_host.c b/hw/pci_host.c
index 728e2d4..2e8a29f 100644
--- a/hw/pci_host.c
+++ b/hw/pci_host.c
@@ -47,17 +47,33 @@ static inline PCIDevice *pci_dev_find_by_addr(PCIBus *bus, uint32_t addr)
     return pci_find_device(bus, bus_num, devfn);
 }
 
+void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr,
+                                  uint32_t limit, uint32_t val, uint32_t len)
+{
+    assert(len <= 4);
+    pci_dev->config_write(pci_dev, addr, val, MIN(len, limit - addr));
+}
+
+uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr,
+                                     uint32_t limit, uint32_t len)
+{
+    assert(len <= 4);
+    return pci_dev->config_read(pci_dev, addr, MIN(len, limit - addr));
+}
+
 void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len)
 {
     PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr);
     uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1);
 
-    if (!pci_dev)
+    if (!pci_dev) {
         return;
+    }
 
     PCI_DPRINTF("%s: %s: addr=%02" PRIx32 " val=%08" PRIx32 " len=%d\n",
                 __func__, pci_dev->name, config_addr, val, len);
-    pci_dev->config_write(pci_dev, config_addr, val, len);
+    pci_host_config_write_common(pci_dev, config_addr, PCI_CONFIG_SPACE_SIZE,
+                                 val, len);
 }
 
 uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len)
@@ -66,12 +82,12 @@ uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len)
     uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1);
     uint32_t val;
 
-    assert(len == 1 || len == 2 || len == 4);
     if (!pci_dev) {
         return ~0x0;
     }
 
-    val = pci_dev->config_read(pci_dev, config_addr, len);
+    val = pci_host_config_read_common(pci_dev, config_addr,
+                                      PCI_CONFIG_SPACE_SIZE, len);
     PCI_DPRINTF("%s: %s: addr=%02"PRIx32" val=%08"PRIx32" len=%d\n",
                 __func__, pci_dev->name, config_addr, val, len);
 
diff --git a/hw/pci_host.h b/hw/pci_host.h
index 0a58595..c8390ee 100644
--- a/hw/pci_host.h
+++ b/hw/pci_host.h
@@ -39,6 +39,12 @@ struct PCIHostState {
     PCIBus *bus;
 };
 
+/* common internal helpers for PCI/PCIe hosts, cut off overflows */
+void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr,
+                                  uint32_t limit, uint32_t val, uint32_t len);
+uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr,
+                                     uint32_t limit, uint32_t len);
+
 void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len);
 uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len);
 
diff --git a/hw/pcie_host.c b/hw/pcie_host.c
index b749865..f0b3d13 100644
--- a/hw/pcie_host.c
+++ b/hw/pcie_host.c
@@ -57,22 +57,22 @@ static void pcie_mmcfg_data_write(PCIBus *s,
 {
     PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, mmcfg_addr);
 
-    if (!pci_dev)
+    if (!pci_dev) {
         return;
-
-    pci_dev->config_write(pci_dev,
-                          PCIE_MMCFG_CONFOFFSET(mmcfg_addr), val, len);
+    }
+    pci_host_config_write_common(pci_dev, PCIE_MMCFG_CONFOFFSET(mmcfg_addr),
+                                 pci_config_size(pci_dev), val, len);
 }
 
 static uint32_t pcie_mmcfg_data_read(PCIBus *s, uint32_t addr, int len)
 {
     PCIDevice *pci_dev = pcie_dev_find_by_mmcfg_addr(s, addr);
 
-    assert(len == 1 || len == 2 || len == 4);
     if (!pci_dev) {
         return ~0x0;
     }
-    return pci_dev->config_read(pci_dev, PCIE_MMCFG_CONFOFFSET(addr), len);
+    return pci_host_config_read_common(pci_dev, PCIE_MMCFG_CONFOFFSET(addr),
+                                       pci_config_size(pci_dev), len);
 }
 
 static void pcie_mmcfg_data_writeb(void *opaque,
commit a492892cbee7ee3244fa63c993b55428b87fc093
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Fri Jul 22 00:51:21 2011 +0000

    target-arm: Don't print debug messages for various UNDEF cases
    
    Remove some stray printfs for cases which don't generally happen
    (some VFP UNDEF cases, reads and writes to unknown cp14 registers);
    we should simply generate an UNDEF when the instruction is executed.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/target-arm/translate.c b/target-arm/translate.c
index fcb41d1..75c0ad4 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -3288,12 +3288,10 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
                         gen_vfp_toul(dp, 32 - rm, 0);
                         break;
                     default: /* undefined */
-                        printf ("rn:%d\n", rn);
                         return 1;
                     }
                     break;
                 default: /* undefined */
-                    printf ("op:%d\n", op);
                     return 1;
                 }
 
@@ -6372,8 +6370,6 @@ static int disas_cp14_read(CPUState * env, DisasContext *s, uint32_t insn)
             return 0;
         }
     }
-    fprintf(stderr, "Unknown cp14 read op1:%d crn:%d crm:%d op2:%d\n",
-            op1, crn, crm, op2);
     return 1;
 }
 
@@ -6405,8 +6401,6 @@ static int disas_cp14_write(CPUState * env, DisasContext *s, uint32_t insn)
             return 0;
         }
     }
-    fprintf(stderr, "Unknown cp14 write op1:%d crn:%d crm:%d op2:%d\n",
-            op1, crn, crm, op2);
     return 1;
 }
 
commit 6e0c0ed185227c301f643281220603fcaf217b31
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Fri Jul 22 00:51:20 2011 +0000

    target-arm: UNDEF on a VCVTT/VCVTB UNPREDICTABLE to avoid TCG assert
    
    VCVTT/VCVTB with bit 8 set is UNPREDICTABLE; we choose to UNDEF.
    This avoids a TCG assert later when the VCVTT/VCVTB code tries to
    use a source register that wasn't ever set up.
    
    We pull the check for the presence of the half-precision extension
    up in to this common code as well.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/target-arm/translate.c b/target-arm/translate.c
index 7acb498..fcb41d1 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -3071,6 +3071,17 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
                     /* Source and destination the same.  */
                     gen_mov_F0_vreg(dp, rd);
                     break;
+                case 4:
+                case 5:
+                case 6:
+                case 7:
+                    /* VCVTB, VCVTT: only present with the halfprec extension,
+                     * UNPREDICTABLE if bit 8 is set (we choose to UNDEF)
+                     */
+                    if (dp || !arm_feature(env, ARM_FEATURE_VFP_FP16)) {
+                        return 1;
+                    }
+                    /* Otherwise fall through */
                 default:
                     /* One source operand.  */
                     gen_mov_F0_vreg(dp, rm);
@@ -3167,24 +3178,18 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
                         gen_vfp_sqrt(dp);
                         break;
                     case 4: /* vcvtb.f32.f16 */
-                        if (!arm_feature(env, ARM_FEATURE_VFP_FP16))
-                          return 1;
                         tmp = gen_vfp_mrs();
                         tcg_gen_ext16u_i32(tmp, tmp);
                         gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp, cpu_env);
                         tcg_temp_free_i32(tmp);
                         break;
                     case 5: /* vcvtt.f32.f16 */
-                        if (!arm_feature(env, ARM_FEATURE_VFP_FP16))
-                          return 1;
                         tmp = gen_vfp_mrs();
                         tcg_gen_shri_i32(tmp, tmp, 16);
                         gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp, cpu_env);
                         tcg_temp_free_i32(tmp);
                         break;
                     case 6: /* vcvtb.f16.f32 */
-                        if (!arm_feature(env, ARM_FEATURE_VFP_FP16))
-                          return 1;
                         tmp = tcg_temp_new_i32();
                         gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
                         gen_mov_F0_vreg(0, rd);
@@ -3195,8 +3200,6 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
                         gen_vfp_msr(tmp);
                         break;
                     case 7: /* vcvtt.f16.f32 */
-                        if (!arm_feature(env, ARM_FEATURE_VFP_FP16))
-                          return 1;
                         tmp = tcg_temp_new_i32();
                         gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
                         tcg_gen_shli_i32(tmp, tmp, 16);
commit 934814f1984346af3e95306648cf20195269b098
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Fri Jul 22 00:51:19 2011 +0000

    target-arm: Handle UNDEF and UNPREDICTABLE cases for VLDM, VSTM
    
    Handle the UNDEF and UNPREDICTABLE cases for VLDM and VSTM. In
    particular, we now generate an undef exception for overlarge imm8
    values rather than generating 1000+ TCG ops and hitting an assertion.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/target-arm/translate.c b/target-arm/translate.c
index c7961b8..7acb498 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -3397,17 +3397,18 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
                 VFP_DREG_D(rd, insn);
             else
                 rd = VFP_SREG_D(insn);
-            if (s->thumb && rn == 15) {
-                addr = tcg_temp_new_i32();
-                tcg_gen_movi_i32(addr, s->pc & ~2);
-            } else {
-                addr = load_reg(s, rn);
-            }
             if ((insn & 0x01200000) == 0x01000000) {
                 /* Single load/store */
                 offset = (insn & 0xff) << 2;
                 if ((insn & (1 << 23)) == 0)
                     offset = -offset;
+                if (s->thumb && rn == 15) {
+                    /* This is actually UNPREDICTABLE */
+                    addr = tcg_temp_new_i32();
+                    tcg_gen_movi_i32(addr, s->pc & ~2);
+                } else {
+                    addr = load_reg(s, rn);
+                }
                 tcg_gen_addi_i32(addr, addr, offset);
                 if (insn & (1 << 20)) {
                     gen_vfp_ld(s, dp, addr);
@@ -3419,11 +3420,34 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
                 tcg_temp_free_i32(addr);
             } else {
                 /* load/store multiple */
+                int w = insn & (1 << 21);
                 if (dp)
                     n = (insn >> 1) & 0x7f;
                 else
                     n = insn & 0xff;
 
+                if (w && !(((insn >> 23) ^ (insn >> 24)) & 1)) {
+                    /* P == U , W == 1  => UNDEF */
+                    return 1;
+                }
+                if (n == 0 || (rd + n) > 32 || (dp && n > 16)) {
+                    /* UNPREDICTABLE cases for bad immediates: we choose to
+                     * UNDEF to avoid generating huge numbers of TCG ops
+                     */
+                    return 1;
+                }
+                if (rn == 15 && w) {
+                    /* writeback to PC is UNPREDICTABLE, we choose to UNDEF */
+                    return 1;
+                }
+
+                if (s->thumb && rn == 15) {
+                    /* This is actually UNPREDICTABLE */
+                    addr = tcg_temp_new_i32();
+                    tcg_gen_movi_i32(addr, s->pc & ~2);
+                } else {
+                    addr = load_reg(s, rn);
+                }
                 if (insn & (1 << 24)) /* pre-decrement */
                     tcg_gen_addi_i32(addr, addr, -((insn & 0xff) << 2));
 
@@ -3443,7 +3467,7 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
                     }
                     tcg_gen_addi_i32(addr, addr, offset);
                 }
-                if (insn & (1 << 21)) {
+                if (w) {
                     /* writeback */
                     if (insn & (1 << 24))
                         offset = -offset * n;
commit 87f19eb2a5a3ffda5db4ab3bc0c326f2fcd3bcce
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Thu Jul 21 07:01:51 2011 +0000

    target-arm: Support v6 barriers in linux-user mode
    
    ARMv6 implemented various operations as special cases of cp15 accesses
    which are true instructions in v7; this includes barriers (DMB, DSB, ISB).
    Catch this special case at translate time, so that it works in linux-user
    mode (which doesn't provide a functional get_cp15 helper) as well as
    system mode.
    
    Includes minor cleanup of the existing cases (single switch statement,
    and doing the "OK in user mode?" test explicitly rather than hiding it in
    cp15_user_ok()).
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/target-arm/translate.c b/target-arm/translate.c
index 34d5e6e..c7961b8 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -2498,12 +2498,6 @@ static int cp15_user_ok(CPUState *env, uint32_t insn)
         if (op == 2 || (op == 3 && (insn & ARM_CP_RW_BIT)))
             return 1;
     }
-    if (cpn == 7) {
-        /* ISB, DSB, DMB.  */
-        if ((cpm == 5 && op == 4)
-                || (cpm == 10 && (op == 4 || op == 5)))
-            return 1;
-    }
     return 0;
 }
 
@@ -2579,39 +2573,60 @@ static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn)
         /* cdp */
         return 1;
     }
-    if (IS_USER(s) && !cp15_user_ok(env, insn)) {
-        return 1;
-    }
-
-    /* Pre-v7 versions of the architecture implemented WFI via coprocessor
-     * instructions rather than a separate instruction.
+    /* We special case a number of cp15 instructions which were used
+     * for things which are real instructions in ARMv7. This allows
+     * them to work in linux-user mode which doesn't provide functional
+     * get_cp15/set_cp15 helpers, and is more efficient anyway.
      */
-    if ((insn & 0x0fff0fff) == 0x0e070f90) {
+    switch ((insn & 0x0fff0fff)) {
+    case 0x0e070f90:
         /* 0,c7,c0,4: Standard v6 WFI (also used in some pre-v6 cores).
          * In v7, this must NOP.
          */
+        if (IS_USER(s)) {
+            return 1;
+        }
         if (!arm_feature(env, ARM_FEATURE_V7)) {
             /* Wait for interrupt.  */
             gen_set_pc_im(s->pc);
             s->is_jmp = DISAS_WFI;
         }
         return 0;
-    }
-
-    if ((insn & 0x0fff0fff) == 0x0e070f58) {
+    case 0x0e070f58:
         /* 0,c7,c8,2: Not all pre-v6 cores implemented this WFI,
          * so this is slightly over-broad.
          */
-        if (!arm_feature(env, ARM_FEATURE_V6)) {
+        if (!IS_USER(s) && !arm_feature(env, ARM_FEATURE_V6)) {
             /* Wait for interrupt.  */
             gen_set_pc_im(s->pc);
             s->is_jmp = DISAS_WFI;
             return 0;
         }
-        /* Otherwise fall through to handle via helper function.
+        /* Otherwise continue to handle via helper function.
          * In particular, on v7 and some v6 cores this is one of
          * the VA-PA registers.
          */
+        break;
+    case 0x0e070f3d:
+        /* 0,c7,c13,1: prefetch-by-MVA in v6, NOP in v7 */
+        if (arm_feature(env, ARM_FEATURE_V6)) {
+            return IS_USER(s) ? 1 : 0;
+        }
+        break;
+    case 0x0e070f95: /* 0,c7,c5,4 : ISB */
+    case 0x0e070f9a: /* 0,c7,c10,4: DSB */
+    case 0x0e070fba: /* 0,c7,c10,5: DMB */
+        /* Barriers in both v6 and v7 */
+        if (arm_feature(env, ARM_FEATURE_V6)) {
+            return 0;
+        }
+        break;
+    default:
+        break;
+    }
+
+    if (IS_USER(s) && !cp15_user_ok(env, insn)) {
+        return 1;
     }
 
     rd = (insn >> 12) & 0xf;
commit 906879a98fa31232f494fece3c5cb3c2baaf8c3c
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Wed Jul 20 10:32:55 2011 +0000

    target-arm: Mark 1136r1 as a v6K core
    
    The 1136r1 is actually a v6K core (unlike the 1136r0); mark it as such,
    thus enabling the TLS registers, NOP hints, CLREX, half and byte wide
    exclusive load/stores, etc.
    
    The VA-to-PA translation registers are not present on 1136r1, so
    introduce a new feature flag for them, which is enabled on 1176,
    11MPCore and all v7 cores.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Reviewed-by: Jamie Iles <jamie at jamieiles.com>

diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 8da3ff4..c28f767 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -374,6 +374,7 @@ enum arm_features {
     ARM_FEATURE_V4T,
     ARM_FEATURE_V5,
     ARM_FEATURE_STRONGARM,
+    ARM_FEATURE_VAPA, /* cp15 VA to PA lookups */
 };
 
 static inline int arm_feature(CPUARMState *env, int feature)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 3465776..b4f6994 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -76,13 +76,24 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c0_cachetype = 0x1dd20d2;
         env->cp15.c1_sys = 0x00090078;
         break;
-    case ARM_CPUID_ARM1136_R2:
     case ARM_CPUID_ARM1136:
+        /* This is the 1136 r1, which is a v6K core */
+        set_feature(env, ARM_FEATURE_V6K);
+        /* Fall through */
+    case ARM_CPUID_ARM1136_R2:
+        /* What qemu calls "arm1136_r2" is actually the 1136 r0p2, ie an
+         * older core than plain "arm1136". In particular this does not
+         * have the v6K features.
+         */
         set_feature(env, ARM_FEATURE_V4T);
         set_feature(env, ARM_FEATURE_V5);
         set_feature(env, ARM_FEATURE_V6);
         set_feature(env, ARM_FEATURE_VFP);
         set_feature(env, ARM_FEATURE_AUXCR);
+        /* These ID register values are correct for 1136 but may be wrong
+         * for 1136_r2 (in particular r0p2 does not actually implement most
+         * of the ID registers).
+         */
         env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b4;
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
         env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000;
@@ -98,6 +109,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         set_feature(env, ARM_FEATURE_V6K);
         set_feature(env, ARM_FEATURE_VFP);
         set_feature(env, ARM_FEATURE_AUXCR);
+        set_feature(env, ARM_FEATURE_VAPA);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b5;
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
         env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000;
@@ -113,6 +125,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         set_feature(env, ARM_FEATURE_V6K);
         set_feature(env, ARM_FEATURE_VFP);
         set_feature(env, ARM_FEATURE_AUXCR);
+        set_feature(env, ARM_FEATURE_VAPA);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b4;
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
         env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000;
@@ -243,6 +256,11 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         cpu_abort(env, "Bad CPU ID: %x\n", id);
         break;
     }
+
+    /* Some features automatically imply others: */
+    if (arm_feature(env, ARM_FEATURE_V7)) {
+        set_feature(env, ARM_FEATURE_VAPA);
+    }
 }
 
 void cpu_reset(CPUARMState *env)
@@ -1524,7 +1542,7 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val)
             goto bad_reg;
         }
         /* No cache, so nothing to do except VA->PA translations. */
-        if (arm_feature(env, ARM_FEATURE_V6K)) {
+        if (arm_feature(env, ARM_FEATURE_VAPA)) {
             switch (crm) {
             case 4:
                 if (arm_feature(env, ARM_FEATURE_V7)) {
commit 7807eed932dbb88fa320ddba99bff45ba96319c6
Author: Jamie Iles <jamie at jamieiles.com>
Date:   Wed Jul 20 10:32:54 2011 +0000

    target-arm: support for ARM1176JZF-s cores
    
    Add support for v6K ARM1176JZF-S.  This core includes the VA<->PA
    translation capability and security extensions.
    
    Signed-off-by: Jamie Iles <jamie at jamieiles.com>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index adef427..8da3ff4 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -420,6 +420,7 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
 #define ARM_CPUID_PXA270_C5   0x69054117
 #define ARM_CPUID_ARM1136     0x4117b363
 #define ARM_CPUID_ARM1136_R2  0x4107b362
+#define ARM_CPUID_ARM1176     0x410fb767
 #define ARM_CPUID_ARM11MPCORE 0x410fb022
 #define ARM_CPUID_CORTEXA8    0x410fc080
 #define ARM_CPUID_CORTEXA9    0x410fc090
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 4b03197..3465776 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -35,6 +35,12 @@ static uint32_t arm1136_cp15_c0_c1[8] =
 static uint32_t arm1136_cp15_c0_c2[8] =
 { 0x00140011, 0x12002111, 0x11231111, 0x01102131, 0x141, 0, 0, 0 };
 
+static uint32_t arm1176_cp15_c0_c1[8] =
+{ 0x111, 0x11, 0x33, 0, 0x01130003, 0x10030302, 0x01222100, 0 };
+
+static uint32_t arm1176_cp15_c0_c2[8] =
+{ 0x0140011, 0x12002111, 0x11231121, 0x01102131, 0x01141, 0, 0, 0 };
+
 static uint32_t cpu_arm_find_by_name(const char *name);
 
 static inline void set_feature(CPUARMState *env, int feature)
@@ -85,6 +91,21 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c0_cachetype = 0x1dd20d2;
         env->cp15.c1_sys = 0x00050078;
         break;
+    case ARM_CPUID_ARM1176:
+        set_feature(env, ARM_FEATURE_V4T);
+        set_feature(env, ARM_FEATURE_V5);
+        set_feature(env, ARM_FEATURE_V6);
+        set_feature(env, ARM_FEATURE_V6K);
+        set_feature(env, ARM_FEATURE_VFP);
+        set_feature(env, ARM_FEATURE_AUXCR);
+        env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b5;
+        env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
+        env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000;
+        memcpy(env->cp15.c0_c1, arm1176_cp15_c0_c1, 8 * sizeof(uint32_t));
+        memcpy(env->cp15.c0_c2, arm1176_cp15_c0_c2, 8 * sizeof(uint32_t));
+        env->cp15.c0_cachetype = 0x1dd20d2;
+        env->cp15.c1_sys = 0x00050078;
+        break;
     case ARM_CPUID_ARM11MPCORE:
         set_feature(env, ARM_FEATURE_V4T);
         set_feature(env, ARM_FEATURE_V5);
@@ -380,6 +401,7 @@ static const struct arm_cpu_t arm_cpu_names[] = {
     { ARM_CPUID_ARM1026, "arm1026"},
     { ARM_CPUID_ARM1136, "arm1136"},
     { ARM_CPUID_ARM1136_R2, "arm1136-r2"},
+    { ARM_CPUID_ARM1176, "arm1176"},
     { ARM_CPUID_ARM11MPCORE, "arm11mpcore"},
     { ARM_CPUID_CORTEXM3, "cortex-m3"},
     { ARM_CPUID_CORTEXA8, "cortex-a8"},
@@ -1848,6 +1870,7 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
                 return 1;
             case ARM_CPUID_ARM1136:
             case ARM_CPUID_ARM1136_R2:
+            case ARM_CPUID_ARM1176:
                 return 7;
             case ARM_CPUID_ARM11MPCORE:
                 return 1;
commit 0ab06d8347bd825090e220167da017d67112e846
Author: Jamie Iles <jamie at jamieiles.com>
Date:   Thu Jun 23 01:12:59 2011 +0000

    target-arm: make VMSAv7 remapping and AP dependent on V6K
    
    The VMSAv7 remapping and access permissions were introduced in ARMv6K
    and not ARMv7.
    
    Signed-off-by: Jamie Iles <jamie at jamieiles.com>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/target-arm/helper.c b/target-arm/helper.c
index ae4f334..4b03197 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -948,7 +948,7 @@ static inline int check_ap(CPUState *env, int ap, int domain, int access_type,
   case 6:
       return prot_ro;
   case 7:
-      if (!arm_feature (env, ARM_FEATURE_V7))
+      if (!arm_feature (env, ARM_FEATURE_V6K))
           return 0;
       return prot_ro;
   default:
commit 670acc9bf21474b2a4456a3cd13323e48e35820d
Merge: 136a0b5... 7006b9c...
Author: malc <av1474 at comtv.ru>
Date:   Sat Jul 23 00:50:37 2011 +0400

    Merge branch 'master' of git://git.qemu.org/qemu

commit 85dde9a90b9d26273ef531d344b2cdfee9a6683d
Author: Markus Armbruster <armbru at redhat.com>
Date:   Thu Jun 16 18:45:37 2011 +0200

    Fix netdev name lookup in -device, device_add, netdev_del
    
    qemu_find_netdev() looks up members of non_vlan_clients by name.  It
    happily returns the first match.  Trouble is the names need not be
    unique.
    
    non_vlan_clients contains host parts (netdevs) and guest parts (NICs).
    
    Netdevs have unique names: a netdev's name is a (mandatory)
    qemu_netdev_opts ID, and these are unique.
    
    NIC names are not unique.  If a NIC has a qdev ID (which is unique),
    that's its name.  Else, we make up a name.  The made-up names are
    unique, but they can clash with qdev IDs.  Even if NICs had unique
    names, they could still clash with netdev names.
    
    Callers of qemu_find_netdev():
    
    * net_init_nic() wants a netdev.  It happens to work because it runs
      before NICs get added to non_vlan_clients.
    
    * do_netdev_del() wants a netdev.  If it gets a NIC, it complains and
      fails.  Bug: a netdev with the same name that comes later in
      non_vlan_clients can't be deleted:
    
        $ qemu-system-x86_64 -nodefaults -vnc :0 -S -monitor stdio -netdev user,id=hostnet0 -device virtio-net-pci,netdev=hostnet0,id=virtio1
        [...]
        (qemu) netdev_add user,id=virtio1
        (qemu) info network
        Devices not on any VLAN:
          hostnet0: net=10.0.2.0, restricted=n peer=virtio1
          virtio1: model=virtio-net-pci,macaddr=52:54:00:12:34:56 peer=hostnet0
          virtio1: net=10.0.2.0, restricted=n
        (qemu) netdev_del virtio1
        Device 'virtio1' not found
    
    * parse_netdev() wants a netdev.  If it gets a NIC, it gets confused.
      With the test setup above:
    
        (qemu) device_add virtio-net-pci,netdev=virtio1
        Property 'virtio-net-pci.netdev' can't take value 'virtio1', it's in use
    
      You can even connect two NICs to each other:
    
        $ qemu-system-x86_64 -nodefaults -vnc :0 -S -monitor stdio -device virtio-net-pci,id=virtio1 -device e1000,netdev=virtio1
        [...]
        Devices not on any VLAN:
          virtio1: model=virtio-net-pci,macaddr=52:54:00:12:34:56 peer=e1000.0
          e1000.0: model=e1000,macaddr=52:54:00:12:34:57 peer=virtio1
        (qemu) q
        Segmentation fault (core dumped)
    
    * do_set_link() works fine for both netdevs and NICs.  Whether it
      really makes sense for netdevs is debatable, but that's outside this
      patch's scope.
    
    Change qemu_find_netdev() to return only netdevs.  This fixes the
    netdev_del and device_add/-device bugs demonstrated above.
    
    To avoid changing set_link, make do_set_link() search non_vlan_clients
    by hand instead of calling qemu_find_netdev().
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Michael S. Tsirkin <mst at redhat.com>

diff --git a/net.c b/net.c
index 55c73c5..e329c69 100644
--- a/net.c
+++ b/net.c
@@ -658,6 +658,8 @@ VLANClientState *qemu_find_netdev(const char *id)
     VLANClientState *vc;
 
     QTAILQ_FOREACH(vc, &non_vlan_clients, next) {
+        if (vc->info->type == NET_CLIENT_TYPE_NIC)
+            continue;
         if (!strcmp(vc->name, id)) {
             return vc;
         }
@@ -1217,7 +1219,7 @@ int do_netdev_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
     VLANClientState *vc;
 
     vc = qemu_find_netdev(id);
-    if (!vc || vc->info->type == NET_CLIENT_TYPE_NIC) {
+    if (!vc) {
         qerror_report(QERR_DEVICE_NOT_FOUND, id);
         return -1;
     }
@@ -1262,7 +1264,11 @@ int do_set_link(Monitor *mon, const QDict *qdict, QObject **ret_data)
             }
         }
     }
-    vc = qemu_find_netdev(name);
+    QTAILQ_FOREACH(vc, &non_vlan_clients, next) {
+        if (!strcmp(vc->name, name)) {
+            goto done;
+        }
+    }
 done:
 
     if (!vc) {
commit 53e51d85ef1fdd295c8f09792b8e7490c148f4b3
Author: Markus Armbruster <armbru at redhat.com>
Date:   Thu Jun 16 18:45:36 2011 +0200

    Fix automatically assigned network names for netdev
    
    If a network client doesn't have a name, we make one up, with
    assign_name().  assign_name() creates a name MODEL.NUM, where MODEL is
    the client's model, and NUM is the number of MODELs that already
    exist.
    
    Bug: it misses clients that are not on a VLAN, i.e. netdevs and the
    NICs using them:
    
        $ qemu-system-x86_64 -nodefaults -vnc :0 -S -monitor stdio -netdev user,id=hostnet0 -net nic,netdev=hostnet0 -netdev user,id=hostnet1 -net nic,netdev=hostnet1
        QEMU 0.14.50 monitor - type 'help' for more information
        (qemu) info network
        Devices not on any VLAN:
          hostnet0: net=10.0.2.0, restricted=n peer=e1000.0
          hostnet1: net=10.0.2.0, restricted=n peer=e1000.0
          e1000.0: model=e1000,macaddr=52:54:00:12:34:56 peer=hostnet0
          e1000.0: model=e1000,macaddr=52:54:00:12:34:57 peer=hostnet1
    
    Fix that.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Michael S. Tsirkin <mst at redhat.com>

diff --git a/net.c b/net.c
index 66123ad..55c73c5 100644
--- a/net.c
+++ b/net.c
@@ -150,12 +150,11 @@ void qemu_macaddr_default_if_unset(MACAddr *macaddr)
 static char *assign_name(VLANClientState *vc1, const char *model)
 {
     VLANState *vlan;
+    VLANClientState *vc;
     char buf[256];
     int id = 0;
 
     QTAILQ_FOREACH(vlan, &vlans, next) {
-        VLANClientState *vc;
-
         QTAILQ_FOREACH(vc, &vlan->clients, next) {
             if (vc != vc1 && strcmp(vc->model, model) == 0) {
                 id++;
@@ -163,6 +162,12 @@ static char *assign_name(VLANClientState *vc1, const char *model)
         }
     }
 
+    QTAILQ_FOREACH(vc, &non_vlan_clients, next) {
+        if (vc != vc1 && strcmp(vc->model, model) == 0) {
+            id++;
+        }
+    }
+
     snprintf(buf, sizeof(buf), "%s.%d", model, id);
 
     return qemu_strdup(buf);
commit 136a0b5a66d9bdf4e2167964db2af9dbed967c85
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Jun 26 22:23:54 2011 +0300

    TCG/PPC: use stack for TCG temps
    
    Use stack instead of temp_buf array in CPUState for TCG temps.
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
    Signed-off-by: malc <av1474 at comtv.ru>

diff --git a/tcg/ppc/tcg-target.c b/tcg/ppc/tcg-target.c
index 0cd8873..58c8621 100644
--- a/tcg/ppc/tcg-target.c
+++ b/tcg/ppc/tcg-target.c
@@ -907,9 +907,14 @@ static void tcg_target_qemu_prologue (TCGContext *s)
         + LINKAGE_AREA_SIZE
         + TCG_STATIC_CALL_ARGS_SIZE
         + ARRAY_SIZE (tcg_target_callee_save_regs) * 4
+        + CPU_TEMP_BUF_NLONGS * sizeof(long)
         ;
     frame_size = (frame_size + 15) & ~15;
 
+    tcg_set_frame(s, TCG_REG_CALL_STACK, frame_size
+                  - CPU_TEMP_BUF_NLONGS * sizeof(long),
+                  CPU_TEMP_BUF_NLONGS * sizeof(long));
+
 #ifdef _CALL_AIX
     {
         uint32_t addr;
@@ -1914,6 +1919,4 @@ static void tcg_target_init(TCGContext *s)
 #endif
 
     tcg_add_target_add_op_defs(ppc_op_defs);
-    tcg_set_frame(s, TCG_AREG0, offsetof(CPUState, temp_buf),
-                  CPU_TEMP_BUF_NLONGS * sizeof(long));
 }
diff --git a/tcg/ppc64/tcg-target.c b/tcg/ppc64/tcg-target.c
index 065c710..02a6cb2 100644
--- a/tcg/ppc64/tcg-target.c
+++ b/tcg/ppc64/tcg-target.c
@@ -875,9 +875,14 @@ static void tcg_target_qemu_prologue (TCGContext *s)
         + 8                     /* TOC save area */
         + TCG_STATIC_CALL_ARGS_SIZE
         + ARRAY_SIZE (tcg_target_callee_save_regs) * 8
+        + CPU_TEMP_BUF_NLONGS * sizeof(long)
         ;
     frame_size = (frame_size + 15) & ~15;
 
+    tcg_set_frame(s, TCG_REG_CALL_STACK, frame_size
+                  - CPU_TEMP_BUF_NLONGS * sizeof(long),
+                  CPU_TEMP_BUF_NLONGS * sizeof(long));
+
 #ifndef __APPLE__
     /* First emit adhoc function descriptor */
     addr = (uint64_t) s->code_ptr + 24;
@@ -1691,6 +1696,4 @@ static void tcg_target_init (TCGContext *s)
     tcg_regset_set_reg (s->reserved_regs, TCG_REG_R13);
 
     tcg_add_target_add_op_defs (ppc_op_defs);
-    tcg_set_frame(s, TCG_AREG0, offsetof(CPUState, temp_buf),
-                  CPU_TEMP_BUF_NLONGS * sizeof(long));
 }


More information about the Spice-commits mailing list