[Spice-commits] 227 commits - Makefile Makefile.objs Makefile.target QMP/qmp-events.txt arm-semi.c audio/alsaaudio.c audio/noaudio.c audio/ossaudio.c block.c block.h block/qcow2-cluster.c block/qcow2-snapshot.c block/qcow2.c block/qed-check.c block/qed-cluster.c block/qed-gencb.c block/qed-l2-cache.c block/qed-table.c block/qed.c block/qed.h block/raw-posix.c block/raw.c block/rbd.c block/rbd_types.h block_int.h blockdev.c blockdev.h bsd-user/bsdload.c bsd-user/qemu.h bswap.h configure console.h cpu-common.h cpu-exec.c cpus.c cutils.c default-configs/arm-softmmu.mak default-configs/i386-softmmu.mak default-configs/mips-softmmu.mak default-configs/mips64-softmmu.mak default-configs/mips64el-softmmu.mak default-configs/mipsel-softmmu.mak default-configs/pci.mak default-configs/ppc-softmmu.mak default-configs/ppc64-softmmu.mak default-configs/ppcemb-softmmu.mak default-configs/sh4-softmmu.mak default-configs/sh4eb-softmmu.mak default-configs/sparc64-softmmu.mak default-configs/x86_64-s oftmmu.mak docs/specs exec-all.h exec.c fpu/softfloat-native.c fpu/softfloat-native.h fpu/softfloat-specialize.h fpu/softfloat.c fpu/softfloat.h hmp-commands.hx hw/apb_pci.c hw/apic.c hw/arm_gic.c hw/arm_sysctl.c hw/arm_timer.c hw/armv7m.c hw/axis_dev88.c hw/bonito.c hw/cirrus_vga.c hw/cs4231.c hw/cs4231a.c hw/cuda.c hw/dec_pci.c hw/dp8393x.c hw/ds1225y.c hw/e1000.c hw/eccmemctl.c hw/eepro100.c hw/empty_slot.c hw/escc.c hw/esp.c hw/etraxfs_dma.c hw/etraxfs_eth.c hw/etraxfs_pic.c hw/etraxfs_ser.c hw/etraxfs_timer.c hw/fdc.c hw/file-op-9p.h hw/fw_cfg.c hw/fw_cfg.h hw/g364fb.c hw/grackle_pci.c hw/gt64xxx.c hw/gus.c hw/heathrow_pic.c hw/hpet.c hw/hw.h hw/ide hw/integratorcp.c hw/intel-hda.c hw/ioapic.c hw/isa-bus.c hw/isa.h hw/isa_mmio.c hw/ivshmem.c hw/jazz_led.c hw/lan9118.c hw/lance.c hw/loader.c hw/loader.h hw/lsi53c895a.c hw/m48t59.c hw/mac_dbdma.c hw/mac_nvram.c hw/marvell_88w8618_audio.c hw/mc146818rtc.c hw/mcf5206.c hw/mcf5208.c hw/mcf_fec.c hw/mcf_intc.c hw/mcf_uart.c h w/mips_jazz.c hw/mips_malta.c hw/mips_mipssim.c hw/mips_r4k.c hw/mpcore.c hw/msix.c hw/mst_fpga.c hw/multiboot.c hw/musicpal.c hw/ne2000-isa.c hw/ne2000.c hw/nseries.c hw/omap.h hw/omap1.c hw/omap2.c hw/omap_dma.c hw/omap_dss.c hw/omap_gpio.c hw/omap_gpmc.c hw/omap_i2c.c hw/omap_intc.c hw/omap_l4.c hw/omap_lcdc.c hw/omap_mmc.c hw/omap_sdrc.c hw/omap_sx1.c hw/omap_uart.c hw/onenand.c hw/openpic.c hw/palm.c hw/parallel.c hw/pc.c hw/pc_piix.c hw/pci.c hw/pci.h hw/pci_host.c hw/pci_host.h hw/pci_ids.h hw/pcie.c hw/pcie_aer.c hw/pcie_host.c hw/pckbd.c hw/pcnet-pci.c hw/pcnet.c hw/pflash_cfi01.c hw/pflash_cfi02.c hw/piix_pci.c hw/pl011.c hw/pl022.c hw/pl031.c hw/pl050.c hw/pl061.c hw/pl080.c hw/pl110.c hw/pl181.c hw/pl190.c hw/ppc405_boards.c hw/ppc405_uc.c hw/ppc440.c hw/ppc4xx_pci.c hw/ppc_newworld.c hw/ppc_oldworld.c hw/ppc_prep.c hw/ppce500_mpc8544ds.c hw/ppce500_pci.c hw/prep_pci.c hw/pxa2xx.c hw/pxa2xx_dma.c hw/pxa2xx_gpio.c hw/pxa2xx_keypad.c hw/pxa2xx_lcd.c hw/pxa2xx_mmci. c hw/pxa2xx_pcmcia.c hw/pxa2xx_pic.c hw/pxa2xx_timer.c hw/qdev.c hw/qdev.h hw/qxl-logger.c hw/qxl-render.c hw/qxl.c hw/qxl.h hw/r2d.c hw/rc4030.c hw/realview.c hw/realview_gic.c hw/rtl8139.c hw/s390-virtio-bus.h hw/s390-virtio.c hw/sb16.c hw/sbi.c hw/scsi-bus.c hw/scsi-defs.h hw/scsi-disk.c hw/serial.c hw/sh7750.c hw/sh_intc.c hw/sh_pci.c hw/sh_serial.c hw/sh_timer.c hw/slavio_intctl.c hw/slavio_misc.c hw/slavio_timer.c hw/sm501.c hw/smc91c111.c hw/sparc32_dma.c hw/spitz.c hw/stellaris.c hw/stellaris_enet.c hw/sun4c_intctl.c hw/sun4m.c hw/sun4m_iommu.c hw/sun4u.c hw/syborg_fb.c hw/syborg_interrupt.c hw/syborg_keyboard.c hw/syborg_pointer.c hw/syborg_rtc.c hw/syborg_serial.c hw/syborg_timer.c hw/syborg_virtio.c hw/sysbus.c hw/sysbus.h hw/tc6393xb.c hw/tcx.c hw/tusb6010.c hw/unin_pci.c hw/usb-bus.c hw/usb-hub.c hw/usb-musb.c hw/usb-net.c hw/usb-ohci.c hw/usb-uhci.c hw/usb.h hw/versatile_pci.c hw/versatilepb.c hw/vga-isa-mm.c hw/vga.c hw/vga_int.h hw/virtio-9p-debug.c hw/virtio -9p-local.c hw/virtio-9p-xattr.c hw/virtio-9p.c hw/virtio-blk.c hw/virtio-net.c hw/virtio-pci.c hw/vmware_vga.c hw/wdt_i6300esb.c hw/wdt_ib700.c hw/xen_disk.c hw/xilinx_ethlite.c hw/xilinx_intc.c hw/xilinx_timer.c hw/xilinx_uartlite.c hw/zaurus.c linux-user/arm linux-user/ioctls.h linux-user/linuxload.c linux-user/main.c linux-user/qemu.h linux-user/strace.list linux-user/syscall.c linux-user/syscall_defs.h linux-user/syscall_types.h make_device_config.sh migration.c monitor.c monitor.h net.c net.h net/socket.c net/tap-bsd.c oslib-posix.c pc-bios/vgabios-qxl.bin qemu-common.h qemu-config.c qemu-doc.texi qemu-img.c qemu-io.c qemu-malloc.c qemu-nbd.c qemu-option.c qemu-options.hx qemu-os-posix.h qemu-tech.texi qemu-timer-common.c qmp-commands.hx rwhandler.c rwhandler.h savevm.c slirp/bootp.c sysemu.h target-alpha/op_helper.c target-arm/helper.c target-arm/neon_helper.c target-arm/translate.c target-cris/translate.c target-i386/cpu.h target-i386/helper.c target-m68k/helper.c ta rget-microblaze/op_helper.c target-microblaze/translate.c target-mips/cpu.h target-mips/exec.h target-mips/helper.h target-mips/op_helper.c target-mips/translate.c target-ppc/exec.h target-ppc/op_helper.c target-ppc/translate.c target-s390x/kvm.c target-s390x/translate.c target-sh4/cpu.h target-sh4/helper.c target-sparc/cpu.h target-sparc/helper.c target-sparc/helper.h target-sparc/op_helper.c target-sparc/translate.c tcg/README tcg/arm tcg/ia64 tcg/mips trace-events ui/qemu-spice.h ui/spice-core.c ui/vnc.c ui/vnc.h usb-bsd.c vl.c

Gerd Hoffmann kraxel at kemper.freedesktop.org
Mon Jan 10 05:24:44 PST 2011


 Makefile                             |    2 
 Makefile.objs                        |   10 
 Makefile.target                      |    8 
 QMP/qmp-events.txt                   |   64 +
 arm-semi.c                           |   79 +
 audio/alsaaudio.c                    |   34 
 audio/noaudio.c                      |    5 
 audio/ossaudio.c                     |   20 
 block.c                              |  231 ++++-
 block.h                              |    5 
 block/qcow2-cluster.c                |    6 
 block/qcow2-snapshot.c               |    6 
 block/qcow2.c                        |  248 +++--
 block/qed-check.c                    |  210 ++++
 block/qed-cluster.c                  |  154 +++
 block/qed-gencb.c                    |   32 
 block/qed-l2-cache.c                 |  173 +++
 block/qed-table.c                    |  319 +++++++
 block/qed.c                          | 1349 +++++++++++++++++++++++++++++
 block/qed.h                          |  301 ++++++
 block/raw-posix.c                    |   45 
 block/raw.c                          |    6 
 block/rbd.c                          | 1059 +++++++++++++++++++++++
 block/rbd_types.h                    |   71 +
 block_int.h                          |   11 
 blockdev.c                           |   68 +
 blockdev.h                           |    1 
 bsd-user/bsdload.c                   |    2 
 bsd-user/qemu.h                      |    1 
 bswap.h                              |   15 
 configure                            |   96 ++
 console.h                            |    3 
 cpu-common.h                         |    8 
 cpu-exec.c                           |    6 
 cpus.c                               |    2 
 cutils.c                             |   17 
 default-configs/arm-softmmu.mak      |    1 
 default-configs/i386-softmmu.mak     |    3 
 default-configs/mips-softmmu.mak     |    3 
 default-configs/mips64-softmmu.mak   |    3 
 default-configs/mips64el-softmmu.mak |    3 
 default-configs/mipsel-softmmu.mak   |    3 
 default-configs/pci.mak              |    4 
 default-configs/ppc-softmmu.mak      |    3 
 default-configs/ppc64-softmmu.mak    |    3 
 default-configs/ppcemb-softmmu.mak   |    3 
 default-configs/sh4-softmmu.mak      |    1 
 default-configs/sh4eb-softmmu.mak    |    1 
 default-configs/sparc64-softmmu.mak  |    3 
 default-configs/x86_64-softmmu.mak   |    3 
 docs/specs/qed_spec.txt              |  130 ++
 exec-all.h                           |    8 
 exec.c                               |  145 ++-
 fpu/softfloat-native.c               |    6 
 fpu/softfloat-native.h               |    6 
 fpu/softfloat-specialize.h           |  400 ++++++--
 fpu/softfloat.c                      |  240 +++++
 fpu/softfloat.h                      |   59 +
 hmp-commands.hx                      |   75 +
 hw/apb_pci.c                         |    9 
 hw/apic.c                            |    5 
 hw/arm_gic.c                         |    3 
 hw/arm_sysctl.c                      |    3 
 hw/arm_timer.c                       |    5 
 hw/armv7m.c                          |    2 
 hw/axis_dev88.c                      |    6 
 hw/bonito.c                          |   19 
 hw/cirrus_vga.c                      |  187 +---
 hw/cs4231.c                          |    3 
 hw/cs4231a.c                         |    1 
 hw/cuda.c                            |    3 
 hw/dec_pci.c                         |    6 
 hw/dp8393x.c                         |    3 
 hw/ds1225y.c                         |    6 
 hw/e1000.c                           |   15 
 hw/eccmemctl.c                       |    6 
 hw/eepro100.c                        |    6 
 hw/empty_slot.c                      |    3 
 hw/escc.c                            |    3 
 hw/esp.c                             |    3 
 hw/etraxfs_dma.c                     |    2 
 hw/etraxfs_eth.c                     |    3 
 hw/etraxfs_pic.c                     |    3 
 hw/etraxfs_ser.c                     |    3 
 hw/etraxfs_timer.c                   |    3 
 hw/fdc.c                             |   18 
 hw/file-op-9p.h                      |    2 
 hw/fw_cfg.c                          |   36 
 hw/fw_cfg.h                          |    4 
 hw/g364fb.c                          |    3 
 hw/grackle_pci.c                     |    6 
 hw/gt64xxx.c                         |    9 
 hw/gus.c                             |    4 
 hw/heathrow_pic.c                    |    5 
 hw/hpet.c                            |    3 
 hw/hw.h                              |   14 
 hw/ide/ahci.c                        | 1524 +++++++++++++++++++++++++++++++++
 hw/ide/cmd646.c                      |   18 
 hw/ide/core.c                        | 1116 ++++++++++--------------
 hw/ide/internal.h                    |   76 -
 hw/ide/isa.c                         |    5 
 hw/ide/macio.c                       |    3 
 hw/ide/mmio.c                        |    6 
 hw/ide/pci.c                         |  280 ++++++
 hw/ide/pci.h                         |   30 
 hw/ide/piix.c                        |   34 
 hw/ide/qdev.c                        |   22 
 hw/ide/via.c                         |   34 
 hw/integratorcp.c                    |    9 
 hw/intel-hda.c                       |    3 
 hw/ioapic.c                          |    3 
 hw/isa-bus.c                         |   53 +
 hw/isa.h                             |    6 
 hw/isa_mmio.c                        |  100 --
 hw/ivshmem.c                         |    2 
 hw/jazz_led.c                        |    3 
 hw/lan9118.c                         |    3 
 hw/lance.c                           |    4 
 hw/loader.c                          |   32 
 hw/loader.h                          |    8 
 hw/lsi53c895a.c                      |    6 
 hw/m48t59.c                          |    4 
 hw/mac_dbdma.c                       |    6 
 hw/mac_nvram.c                       |    3 
 hw/marvell_88w8618_audio.c           |    3 
 hw/mc146818rtc.c                     |    1 
 hw/mcf5206.c                         |    3 
 hw/mcf5208.c                         |    6 
 hw/mcf_fec.c                         |    3 
 hw/mcf_intc.c                        |    3 
 hw/mcf_uart.c                        |    3 
 hw/mips_jazz.c                       |   13 
 hw/mips_malta.c                      |    3 
 hw/mips_mipssim.c                    |    6 
 hw/mips_r4k.c                        |    9 
 hw/mpcore.c                          |    3 
 hw/msix.c                            |    3 
 hw/mst_fpga.c                        |    2 
 hw/multiboot.c                       |    3 
 hw/musicpal.c                        |   24 
 hw/ne2000-isa.c                      |    3 
 hw/ne2000.c                          |    5 
 hw/nseries.c                         |    4 
 hw/omap.h                            |    3 
 hw/omap1.c                           |   42 
 hw/omap2.c                           |    4 
 hw/omap_dma.c                        |    4 
 hw/omap_dss.c                        |    2 
 hw/omap_gpio.c                       |    2 
 hw/omap_gpmc.c                       |    2 
 hw/omap_i2c.c                        |    2 
 hw/omap_intc.c                       |    4 
 hw/omap_l4.c                         |    5 
 hw/omap_lcdc.c                       |    2 
 hw/omap_mmc.c                        |    2 
 hw/omap_sdrc.c                       |    2 
 hw/omap_sx1.c                        |   15 
 hw/omap_uart.c                       |    2 
 hw/onenand.c                         |    2 
 hw/openpic.c                         |   29 
 hw/palm.c                            |   18 
 hw/parallel.c                        |    8 
 hw/pc.c                              |  104 ++
 hw/pc_piix.c                         |   20 
 hw/pci.c                             |  134 ++
 hw/pci.h                             |    8 
 hw/pci_host.c                        |  103 --
 hw/pci_host.h                        |    6 
 hw/pci_ids.h                         |    1 
 hw/pcie.c                            |    8 
 hw/pcie_aer.c                        |  111 +-
 hw/pcie_host.c                       |    3 
 hw/pckbd.c                           |   23 
 hw/pcnet-pci.c                       |    5 
 hw/pcnet.c                           |    4 
 hw/pflash_cfi01.c                    |    6 
 hw/pflash_cfi02.c                    |    4 
 hw/piix_pci.c                        |    1 
 hw/pl011.c                           |    3 
 hw/pl022.c                           |    3 
 hw/pl031.c                           |    3 
 hw/pl050.c                           |    3 
 hw/pl061.c                           |    3 
 hw/pl080.c                           |    3 
 hw/pl110.c                           |    3 
 hw/pl181.c                           |    4 
 hw/pl190.c                           |    3 
 hw/ppc405_boards.c                   |    6 
 hw/ppc405_uc.c                       |   11 
 hw/ppc440.c                          |    2 
 hw/ppc4xx_pci.c                      |   19 
 hw/ppc_newworld.c                    |    5 
 hw/ppc_oldworld.c                    |    2 
 hw/ppc_prep.c                        |   40 
 hw/ppce500_mpc8544ds.c               |    2 
 hw/ppce500_pci.c                     |    9 
 hw/prep_pci.c                        |    3 
 hw/pxa2xx.c                          |   25 
 hw/pxa2xx_dma.c                      |    2 
 hw/pxa2xx_gpio.c                     |    2 
 hw/pxa2xx_keypad.c                   |    2 
 hw/pxa2xx_lcd.c                      |    2 
 hw/pxa2xx_mmci.c                     |    2 
 hw/pxa2xx_pcmcia.c                   |    6 
 hw/pxa2xx_pic.c                      |    2 
 hw/pxa2xx_timer.c                    |    2 
 hw/qdev.c                            |   41 
 hw/qdev.h                            |   14 
 hw/qxl-logger.c                      |  248 +++++
 hw/qxl-render.c                      |  226 ++++
 hw/qxl.c                             | 1587 +++++++++++++++++++++++++++++++++++
 hw/qxl.h                             |  112 ++
 hw/r2d.c                             |    3 
 hw/rc4030.c                          |    6 
 hw/realview.c                        |    3 
 hw/realview_gic.c                    |    3 
 hw/rtl8139.c                         |   19 
 hw/s390-virtio-bus.h                 |    2 
 hw/s390-virtio.c                     |    1 
 hw/sb16.c                            |    4 
 hw/sbi.c                             |    3 
 hw/scsi-bus.c                        |   23 
 hw/scsi-defs.h                       |    1 
 hw/scsi-disk.c                       |   55 +
 hw/serial.c                          |    7 
 hw/sh7750.c                          |    8 
 hw/sh_intc.c                         |    3 
 hw/sh_pci.c                          |    7 
 hw/sh_serial.c                       |    3 
 hw/sh_timer.c                        |    3 
 hw/slavio_intctl.c                   |    6 
 hw/slavio_misc.c                     |   24 
 hw/slavio_timer.c                    |    3 
 hw/sm501.c                           |    9 
 hw/smc91c111.c                       |    3 
 hw/sparc32_dma.c                     |   23 
 hw/spitz.c                           |    2 
 hw/stellaris.c                       |   12 
 hw/stellaris_enet.c                  |    3 
 hw/sun4c_intctl.c                    |    3 
 hw/sun4m.c                           |   16 
 hw/sun4m_iommu.c                     |    3 
 hw/sun4u.c                           |    4 
 hw/syborg_fb.c                       |    3 
 hw/syborg_interrupt.c                |    3 
 hw/syborg_keyboard.c                 |    3 
 hw/syborg_pointer.c                  |    3 
 hw/syborg_rtc.c                      |    3 
 hw/syborg_serial.c                   |    3 
 hw/syborg_timer.c                    |    3 
 hw/syborg_virtio.c                   |    3 
 hw/sysbus.c                          |   30 
 hw/sysbus.h                          |    4 
 hw/tc6393xb.c                        |    2 
 hw/tcx.c                             |    5 
 hw/tusb6010.c                        |    2 
 hw/unin_pci.c                        |   26 
 hw/usb-bus.c                         |   45 
 hw/usb-hub.c                         |    3 
 hw/usb-musb.c                        |    2 
 hw/usb-net.c                         |    3 
 hw/usb-ohci.c                        |   12 
 hw/usb-uhci.c                        |    2 
 hw/usb.h                             |    3 
 hw/versatile_pci.c                   |   21 
 hw/versatilepb.c                     |    3 
 hw/vga-isa-mm.c                      |    6 
 hw/vga.c                             |   33 
 hw/vga_int.h                         |    2 
 hw/virtio-9p-debug.c                 |    4 
 hw/virtio-9p-local.c                 |   12 
 hw/virtio-9p-xattr.c                 |    3 
 hw/virtio-9p.c                       |   11 
 hw/virtio-blk.c                      |    2 
 hw/virtio-net.c                      |   71 +
 hw/virtio-pci.c                      |    1 
 hw/vmware_vga.c                      |    2 
 hw/wdt_i6300esb.c                    |   43 
 hw/wdt_ib700.c                       |   22 
 hw/xen_disk.c                        |   17 
 hw/xilinx_ethlite.c                  |    2 
 hw/xilinx_intc.c                     |    2 
 hw/xilinx_timer.c                    |    3 
 hw/xilinx_uartlite.c                 |    3 
 hw/zaurus.c                          |    2 
 linux-user/arm/nwfpe/fpa11_cprt.c    |   14 
 linux-user/ioctls.h                  |    4 
 linux-user/linuxload.c               |    2 
 linux-user/main.c                    |    2 
 linux-user/qemu.h                    |    1 
 linux-user/strace.list               |    6 
 linux-user/syscall.c                 |  129 ++
 linux-user/syscall_defs.h            |    1 
 linux-user/syscall_types.h           |   16 
 make_device_config.sh                |    2 
 migration.c                          |    2 
 monitor.c                            |  554 ++++++++++--
 monitor.h                            |    3 
 net.c                                |    4 
 net.h                                |    4 
 net/socket.c                         |   53 -
 net/tap-bsd.c                        |    8 
 oslib-posix.c                        |   48 +
 pc-bios/vgabios-qxl.bin              |binary
 qemu-common.h                        |   10 
 qemu-config.c                        |   17 
 qemu-doc.texi                        |   30 
 qemu-img.c                           |  437 ++++-----
 qemu-io.c                            |  102 ++
 qemu-malloc.c                        |    5 
 qemu-nbd.c                           |    2 
 qemu-option.c                        |   13 
 qemu-options.hx                      |   17 
 qemu-os-posix.h                      |   12 
 qemu-tech.texi                       |    4 
 qemu-timer-common.c                  |    3 
 qmp-commands.hx                      |  131 ++
 rwhandler.c                          |    4 
 rwhandler.h                          |    2 
 savevm.c                             |    4 
 slirp/bootp.c                        |   32 
 sysemu.h                             |   14 
 target-alpha/op_helper.c             |    2 
 target-arm/helper.c                  |   90 +
 target-arm/neon_helper.c             |   21 
 target-arm/translate.c               |  261 +++--
 target-cris/translate.c              |   48 -
 target-i386/cpu.h                    |    8 
 target-i386/helper.c                 |    4 
 target-m68k/helper.c                 |    6 
 target-microblaze/op_helper.c        |    2 
 target-microblaze/translate.c        |   28 
 target-mips/cpu.h                    |    8 
 target-mips/exec.h                   |   18 
 target-mips/helper.h                 |    8 
 target-mips/op_helper.c              |   36 
 target-mips/translate.c              |    8 
 target-ppc/exec.h                    |    3 
 target-ppc/op_helper.c               |  121 --
 target-ppc/translate.c               |   39 
 target-s390x/kvm.c                   |    2 
 target-s390x/translate.c             |    2 
 target-sh4/cpu.h                     |    2 
 target-sh4/helper.c                  |   84 +
 target-sparc/cpu.h                   |    2 
 target-sparc/helper.c                |   88 -
 target-sparc/helper.h                |    2 
 target-sparc/op_helper.c             |   74 +
 target-sparc/translate.c             |   12 
 tcg/README                           |   10 
 tcg/arm/tcg-target.c                 |   69 -
 tcg/ia64/tcg-target.c                |    2 
 tcg/mips/tcg-target.c                |    2 
 trace-events                         |   21 
 ui/qemu-spice.h                      |    8 
 ui/spice-core.c                      |  261 +++++
 ui/vnc.c                             |   44 
 ui/vnc.h                             |    1 
 usb-bsd.c                            |   71 -
 vl.c                                 |  122 ++
 360 files changed, 13774 insertions(+), 2973 deletions(-)

New commits:
commit 8aaf42ed0f203da63860b0a3ab3ff2bdfe9b4cb0
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Thu Jan 6 22:43:13 2011 +0100

    slirp: fix unaligned access in bootp code
    
    Slirp code tries to be smart an avoid data copy by using pointer to
    the data. This solution leads to unaligned access, in this case
    preq_addr, which is a 32-bit long structure. There is no real point
    of avoiding data copy in a such case, as the value itself is smaller
    or the same size as a pointer.
    
    The patch replaces pointers to the preq_addr structure by the strcture
    itself, and use the address 0.0.0.0 if no address has been requested
    (this is not a valid address in such a request). It compares it with
    htonl(0L) for correctness reasons, in case a code checker look for such
    mistakes. It also uses memcpy() for copying the data, which takes care
    of alignement issues.
    
    This fixes an unaligned access on IA64 host while requesting a DHCP
    address.
    
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/slirp/bootp.c b/slirp/bootp.c
index 41460ff..0905c6d 100644
--- a/slirp/bootp.c
+++ b/slirp/bootp.c
@@ -92,13 +92,13 @@ static BOOTPClient *find_addr(Slirp *slirp, struct in_addr *paddr,
 }
 
 static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type,
-                        const struct in_addr **preq_addr)
+                        struct in_addr *preq_addr)
 {
     const uint8_t *p, *p_end;
     int len, tag;
 
     *pmsg_type = 0;
-    *preq_addr = NULL;
+    preq_addr->s_addr = htonl(0L);
 
     p = bp->bp_vend;
     p_end = p + DHCP_OPT_LEN;
@@ -124,8 +124,9 @@ static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type,
                     *pmsg_type = p[0];
                 break;
             case RFC2132_REQ_ADDR:
-                if (len >= 4)
-                    *preq_addr = (struct in_addr *)p;
+                if (len >= 4) {
+                    memcpy(&(preq_addr->s_addr), p, 4);
+                }
                 break;
             default:
                 break;
@@ -133,8 +134,9 @@ static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type,
             p += len;
         }
     }
-    if (*pmsg_type == DHCPREQUEST && !*preq_addr && bp->bp_ciaddr.s_addr) {
-        *preq_addr = &bp->bp_ciaddr;
+    if (*pmsg_type == DHCPREQUEST && preq_addr->s_addr == htonl(0L) &&
+        bp->bp_ciaddr.s_addr) {
+        memcpy(&(preq_addr->s_addr), &bp->bp_ciaddr, 4);
     }
 }
 
@@ -144,15 +146,15 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
     struct mbuf *m;
     struct bootp_t *rbp;
     struct sockaddr_in saddr, daddr;
-    const struct in_addr *preq_addr;
+    struct in_addr preq_addr;
     int dhcp_msg_type, val;
     uint8_t *q;
 
     /* extract exact DHCP msg type */
     dhcp_decode(bp, &dhcp_msg_type, &preq_addr);
     DPRINTF("bootp packet op=%d msgtype=%d", bp->bp_op, dhcp_msg_type);
-    if (preq_addr)
-        DPRINTF(" req_addr=%08x\n", ntohl(preq_addr->s_addr));
+    if (preq_addr.s_addr != htonl(0L))
+        DPRINTF(" req_addr=%08x\n", ntohl(preq_addr.s_addr));
     else
         DPRINTF("\n");
 
@@ -175,10 +177,10 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
     memset(rbp, 0, sizeof(struct bootp_t));
 
     if (dhcp_msg_type == DHCPDISCOVER) {
-        if (preq_addr) {
-            bc = request_addr(slirp, preq_addr, slirp->client_ethaddr);
+        if (preq_addr.s_addr != htonl(0L)) {
+            bc = request_addr(slirp, &preq_addr, slirp->client_ethaddr);
             if (bc) {
-                daddr.sin_addr = *preq_addr;
+                daddr.sin_addr = preq_addr;
             }
         }
         if (!bc) {
@@ -190,10 +192,10 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
             }
         }
         memcpy(bc->macaddr, slirp->client_ethaddr, 6);
-    } else if (preq_addr) {
-        bc = request_addr(slirp, preq_addr, slirp->client_ethaddr);
+    } else if (preq_addr.s_addr != htonl(0L)) {
+        bc = request_addr(slirp, &preq_addr, slirp->client_ethaddr);
         if (bc) {
-            daddr.sin_addr = *preq_addr;
+            daddr.sin_addr = preq_addr;
             memcpy(bc->macaddr, slirp->client_ethaddr, 6);
         } else {
             daddr.sin_addr.s_addr = 0;
commit 102c29769fa7cd564053ea41735395f428b6f197
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Thu Jan 6 22:43:13 2011 +0100

    bswap.h: add cpu_to_be64wu()
    
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/bswap.h b/bswap.h
index 20caae6..82a7951 100644
--- a/bswap.h
+++ b/bswap.h
@@ -144,6 +144,7 @@ CPU_CONVERT(le, 64, uint64_t)
 
 #define cpu_to_be16wu(p, v) cpu_to_be16w(p, v)
 #define cpu_to_be32wu(p, v) cpu_to_be32w(p, v)
+#define cpu_to_be64wu(p, v) cpu_to_be64w(p, v)
 
 #else
 
@@ -201,6 +202,20 @@ static inline void cpu_to_be32wu(uint32_t *p, uint32_t v)
     p1[3] = v & 0xff;
 }
 
+static inline void cpu_to_be64wu(uint64_t *p, uint64_t v)
+{
+    uint8_t *p1 = (uint8_t *)p;
+
+    p1[0] = v >> 56;
+    p1[1] = v >> 48;
+    p1[2] = v >> 40;
+    p1[3] = v >> 32;
+    p1[4] = v >> 24;
+    p1[5] = v >> 16;
+    p1[6] = v >> 8;
+    p1[7] = v & 0xff;
+}
+
 #endif
 
 #ifdef HOST_WORDS_BIGENDIAN
commit 0f11f25a001f6adca18689192182d415ff3dbb7c
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Thu Jan 6 22:43:13 2011 +0100

    tcg/arm: improve constant loading
    
    Improve constant loading in two ways:
    - On all ARM versions, it's possible to load 0xffffff00 = -0x100 using
      the mvn rd, #0. Fix the conditions.
    - On <= ARMv6 versions, where movw and movt are not available, load the
      constants using mov and orr with rotations depending on the constant
      to load. This is very useful for example to load constants where the
      low byte is 0. This reduce the generated code size by about 7%.
    
    Also fix the coding style at the same time.
    
    Cc: Andrzej Zaborowski <balrog at zabor.org>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c
index 08c44c1..1eb5605 100644
--- a/tcg/arm/tcg-target.c
+++ b/tcg/arm/tcg-target.c
@@ -406,35 +406,38 @@ static inline void tcg_out_dat_imm(TCGContext *s,
 }
 
 static inline void tcg_out_movi32(TCGContext *s,
-                int cond, int rd, int32_t arg)
+                int cond, int rd, uint32_t arg)
 {
     /* TODO: This is very suboptimal, we can easily have a constant
      * pool somewhere after all the instructions.  */
-
-    if (arg < 0 && arg > -0x100)
-        return tcg_out_dat_imm(s, cond, ARITH_MVN, rd, 0, (~arg) & 0xff);
-
-    if (use_armv7_instructions) {
+    if ((int)arg < 0 && (int)arg >= -0x100) {
+        tcg_out_dat_imm(s, cond, ARITH_MVN, rd, 0, (~arg) & 0xff);
+    } else if (use_armv7_instructions) {
         /* use movw/movt */
         /* movw */
         tcg_out32(s, (cond << 28) | 0x03000000 | (rd << 12)
                   | ((arg << 4) & 0x000f0000) | (arg & 0xfff));
-        if (arg & 0xffff0000)
+        if (arg & 0xffff0000) {
             /* movt */
             tcg_out32(s, (cond << 28) | 0x03400000 | (rd << 12)
                       | ((arg >> 12) & 0x000f0000) | ((arg >> 16) & 0xfff));
-    } else {
-        tcg_out_dat_imm(s, cond, ARITH_MOV, rd, 0, arg & 0xff);
-        if (arg & 0x0000ff00)
-            tcg_out_dat_imm(s, cond, ARITH_ORR, rd, rd,
-                            ((arg >>  8) & 0xff) | 0xc00);
-        if (arg & 0x00ff0000)
-            tcg_out_dat_imm(s, cond, ARITH_ORR, rd, rd,
-                            ((arg >> 16) & 0xff) | 0x800);
-        if (arg & 0xff000000)
-            tcg_out_dat_imm(s, cond, ARITH_ORR, rd, rd,
-                            ((arg >> 24) & 0xff) | 0x400);
         }
+    } else {
+        int opc = ARITH_MOV;
+        int rn = 0;
+
+        do {
+            int i, rot;
+
+            i = ctz32(arg) & ~1;
+            rot = ((32 - i) << 7) & 0xf00;
+            tcg_out_dat_imm(s, cond, opc, rd, rn, ((arg >> i) & 0xff) | rot);
+            arg &= ~(0xff << i);
+
+            opc = ARITH_ORR;
+            rn = rd;
+        } while (arg);
+    }
 }
 
 static inline void tcg_out_mul32(TCGContext *s,
commit a3e28aa5c748958e5719451aaff88a4d78e09a80
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Mon Jan 10 01:39:49 2011 +0100

    tcg/ia64: remove an unnecessary stop bit
    
    Spotted by Richard Henderson.
    
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c
index 3ddf434..e2e44f7 100644
--- a/tcg/ia64/tcg-target.c
+++ b/tcg/ia64/tcg-target.c
@@ -1329,7 +1329,7 @@ static inline void tcg_out_bswap32(TCGContext *s, TCGArg ret, TCGArg arg)
 
 static inline void tcg_out_bswap64(TCGContext *s, TCGArg ret, TCGArg arg)
 {
-    tcg_out_bundle(s, mII,
+    tcg_out_bundle(s, miI,
                    tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
                    tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
                    tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3, ret, arg, 0xb));
commit 829a49274f6741c0f3d3a2ba4698baf381a7e264
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Sun Jan 9 23:53:45 2011 +0100

    target-sh4: improve TLB
    
    SH4 is using 16-bit instructions which means most of the constants are
    loaded through a constant pool at the end of the subroutine. The same
    memory page is therefore accessed in exec and read mode.
    
    With the current implementation, a QEMU TLB entry is set to read or
    read/write mode after an UTLB search and to exec mode after an ITLB
    search, which causes a lot of TLB exceptions to switch from read or
    read/write to exec and vice versa.
    
    This patch optimizes that by already setting the QEMU TLB entry in read
    or read/write mode when an UTLB entry is copied into ITLB (during an
    ITLB miss). This improve the emulation speed by about 14%.
    
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/target-sh4/helper.c b/target-sh4/helper.c
index 863886b..2343366 100644
--- a/target-sh4/helper.c
+++ b/target-sh4/helper.c
@@ -280,35 +280,40 @@ static void increment_urc(CPUState * env)
     env->mmucr = (env->mmucr & 0xffff03ff) | (urc << 10);
 }
 
-/* Find itlb entry - update itlb from utlb if necessary and asked for
+/* Copy and utlb entry into itlb
+   Return entry
+*/
+static int copy_utlb_entry_itlb(CPUState *env, int utlb)
+{
+    int itlb;
+
+    tlb_t * ientry;
+    itlb = itlb_replacement(env);
+    ientry = &env->itlb[itlb];
+    if (ientry->v) {
+        tlb_flush_page(env, ientry->vpn << 10);
+    }
+    *ientry = env->utlb[utlb];
+    update_itlb_use(env, itlb);
+    return itlb;
+}
+
+/* Find itlb entry
    Return entry, MMU_ITLB_MISS, MMU_ITLB_MULTIPLE or MMU_DTLB_MULTIPLE
-   Update the itlb from utlb if update is not 0
 */
 static int find_itlb_entry(CPUState * env, target_ulong address,
-                           int use_asid, int update)
+                           int use_asid)
 {
-    int e, n;
+    int e;
 
     e = find_tlb_entry(env, address, env->itlb, ITLB_SIZE, use_asid);
-    if (e == MMU_DTLB_MULTIPLE)
+    if (e == MMU_DTLB_MULTIPLE) {
 	e = MMU_ITLB_MULTIPLE;
-    else if (e == MMU_DTLB_MISS && update) {
-	e = find_tlb_entry(env, address, env->utlb, UTLB_SIZE, use_asid);
-	if (e >= 0) {
-	    tlb_t * ientry;
-	    n = itlb_replacement(env);
-	    ientry = &env->itlb[n];
-	    if (ientry->v) {
-                tlb_flush_page(env, ientry->vpn << 10);
-	    }
-	    *ientry = env->utlb[e];
-	    e = n;
-	} else if (e == MMU_DTLB_MISS)
-	    e = MMU_ITLB_MISS;
-    } else if (e == MMU_DTLB_MISS)
+    } else if (e == MMU_DTLB_MISS) {
 	e = MMU_ITLB_MISS;
-    if (e >= 0)
+    } else if (e >= 0) {
 	update_itlb_use(env, e);
+    }
     return e;
 }
 
@@ -340,13 +345,31 @@ static int get_mmu_address(CPUState * env, target_ulong * physical,
     use_asid = (env->mmucr & MMUCR_SV) == 0 || (env->sr & SR_MD) == 0;
 
     if (rw == 2) {
-	n = find_itlb_entry(env, address, use_asid, 1);
+        n = find_itlb_entry(env, address, use_asid);
 	if (n >= 0) {
 	    matching = &env->itlb[n];
 	    if (!(env->sr & SR_MD) && !(matching->pr & 2))
 		n = MMU_ITLB_VIOLATION;
 	    else
 		*prot = PAGE_EXEC;
+        } else {
+            n = find_utlb_entry(env, address, use_asid);
+            if (n >= 0) {
+                n = copy_utlb_entry_itlb(env, n);
+                matching = &env->itlb[n];
+                if (!(env->sr & SR_MD) && !(matching->pr & 2)) {
+                      n = MMU_ITLB_VIOLATION;
+                } else {
+                    *prot = PAGE_READ | PAGE_EXEC;
+                    if ((matching->pr & 1) && matching->d) {
+                        *prot |= PAGE_WRITE;
+                    }
+                }
+            } else if (n == MMU_DTLB_MULTIPLE) {
+                n = MMU_ITLB_MULTIPLE;
+            } else if (n == MMU_DTLB_MISS) {
+                n = MMU_ITLB_MISS;
+            }
 	}
     } else {
 	n = find_utlb_entry(env, address, use_asid);
commit c0f809c46aa271f29a9e6268cdeda1f21301a8ef
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Sun Jan 9 23:53:45 2011 +0100

    target-sh4: implement writes to mmaped ITLB
    
    Some Linux kernels seems to implement ITLB/UTLB flushing through by
    writing all TLB entries through the memory mapped interface instead
    of writing one to MMUCR.TI.
    
    Implement memory mapped ITLB write interface so that such kernels can
    boot. This fixes https://bugs.launchpad.net/bugs/700774 .
    
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/hw/sh7750.c b/hw/sh7750.c
index 9e54ad1..36b702f 100644
--- a/hw/sh7750.c
+++ b/hw/sh7750.c
@@ -670,6 +670,8 @@ static void sh7750_mmct_writel(void *opaque, target_phys_addr_t addr,
         /* do nothing */
 	break;
     case MM_ITLB_ADDR:
+        cpu_sh4_write_mmaped_itlb_addr(s->cpu, addr, mem_value);
+        break;
     case MM_ITLB_DATA:
         /* XXXXX */
         abort();
diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h
index e197766..8ccf25c 100644
--- a/target-sh4/cpu.h
+++ b/target-sh4/cpu.h
@@ -172,6 +172,8 @@ void do_interrupt(CPUSH4State * env);
 void sh4_cpu_list(FILE *f, fprintf_function cpu_fprintf);
 #if !defined(CONFIG_USER_ONLY)
 void cpu_sh4_invalidate_tlb(CPUSH4State *s);
+void cpu_sh4_write_mmaped_itlb_addr(CPUSH4State *s, target_phys_addr_t addr,
+				    uint32_t mem_value);
 void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t addr,
 				    uint32_t mem_value);
 #endif
diff --git a/target-sh4/helper.c b/target-sh4/helper.c
index 9e70352..863886b 100644
--- a/target-sh4/helper.c
+++ b/target-sh4/helper.c
@@ -544,6 +544,25 @@ void cpu_load_tlb(CPUSH4State * env)
     tlb_flush(s, 1);
 }
 
+void cpu_sh4_write_mmaped_itlb_addr(CPUSH4State *s, target_phys_addr_t addr,
+				    uint32_t mem_value)
+{
+    uint32_t vpn = (mem_value & 0xfffffc00) >> 10;
+    uint8_t v = (uint8_t)((mem_value & 0x00000100) >> 8);
+    uint8_t asid = (uint8_t)(mem_value & 0x000000ff);
+
+    int index = (addr & 0x00003f00) >> 8;
+    tlb_t * entry = &s->itlb[index];
+    if (entry->v) {
+        /* Overwriting valid entry in itlb. */
+        target_ulong address = entry->vpn << 10;
+        tlb_flush_page(s, address);
+    }
+    entry->asid = asid;
+    entry->vpn = vpn;
+    entry->v = v;
+}
+
 void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t addr,
 				    uint32_t mem_value)
 {
commit 759c90ba3d4f8dcb748d7719f7ea82b181ffd590
Author: Mike Frysinger <vapier at gentoo.org>
Date:   Sun Jan 9 03:45:45 2011 -0500

    tcg: fix typo in readme
    
    Signed-off-by: Mike Frysinger <vapier at gentoo.org>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/tcg/README b/tcg/README
index a2b69dd..a18a87f 100644
--- a/tcg/README
+++ b/tcg/README
@@ -364,7 +364,7 @@ formed from two 32-bit arguments.  The result is a 32-bit value.
 
 ********* QEMU specific operations
 
-* tb_exit t0
+* exit_tb t0
 
 Exit the current TB and return the value t0 (word type).
 
commit aa95e3a57fe4c9485c7540ab64c6d4883e4cd01d
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Fri Jan 7 21:34:50 2011 +0100

    tcg/README: Spelling fixes
    
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/tcg/README b/tcg/README
index 68d27ff..a2b69dd 100644
--- a/tcg/README
+++ b/tcg/README
@@ -75,11 +75,11 @@ destroyed, but local temporaries and globals are preserved.
 * Helpers:
 
 Using the tcg_gen_helper_x_y it is possible to call any function
-taking i32, i64 or pointer types. By default, before calling an helper,
+taking i32, i64 or pointer types. By default, before calling a helper,
 all globals are stored at their canonical location and it is assumed
-that the function can modify them. This can be overriden by the
+that the function can modify them. This can be overridden by the
 TCG_CALL_CONST function modifier. By default, the helper is allowed to
-modify the CPU state or raise an exception. This can be overriden by
+modify the CPU state or raise an exception. This can be overridden by
 the TCG_CALL_PURE function modifier, in which case the call to the
 function is removed if the return value is not used.
 
@@ -488,7 +488,7 @@ register.
   the speed of the translation.
 
 - Don't hesitate to use helpers for complicated or seldom used target
-  intructions. There is little performance advantage in using TCG to
+  instructions. There is little performance advantage in using TCG to
   implement target instructions taking more than about twenty TCG
   instructions.
 
commit e8dc09382289fee771999e135c05e8938900c410
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Fri Jan 7 21:31:39 2011 +0100

    qemu-tech: Spelling fixes
    
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/qemu-tech.texi b/qemu-tech.texi
index 2e2a081..138e3ce 100644
--- a/qemu-tech.texi
+++ b/qemu-tech.texi
@@ -516,7 +516,7 @@ timers, especially together with the use of bottom halves (BHs).
 @section Hardware interrupts
 
 In order to be faster, QEMU does not check at every basic block if an
-hardware interrupt is pending. Instead, the user must asynchrously
+hardware interrupt is pending. Instead, the user must asynchronously
 call a specific function to tell that an interrupt is pending. This
 function resets the chaining of the currently executing basic
 block. It ensures that the execution will return soon in the main loop
@@ -548,7 +548,7 @@ Linux kernel does. The @code{sigreturn()} system call is emulated to return
 from the virtual signal handler.
 
 Some signals (such as SIGALRM) directly come from the host. Other
-signals are synthetized from the virtual CPU exceptions such as SIGFPE
+signals are synthesized from the virtual CPU exceptions such as SIGFPE
 when a division by zero is done (see @code{main.c:cpu_loop()}).
 
 The blocked signal mask is still handled by the host Linux kernel so
commit 40c5c6cd2bb2b6cc2e15fbd071dab956811f3266
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Fri Jan 7 18:59:16 2011 +0100

    qemu-doc: Spelling fixes
    
    neccessary -> necessary
    Keberos -> Kerberos
    emuilated -> emulated
    transciever -> transceiver
    emulaton -> emulation
    inital -> initial
    MingGW -> MinGW
    
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/qemu-doc.texi b/qemu-doc.texi
index a1e6130..45190f6 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -1049,7 +1049,7 @@ qemu [...OPTIONS...] -vnc :1,tls,x509,sasl -monitor stdio
 
 The GNU TLS packages provides a command called @code{certtool} which can
 be used to generate certificates and keys in PEM format. At a minimum it
-is neccessary to setup a certificate authority, and issue certificates to
+is necessary to setup a certificate authority, and issue certificates to
 each server. If using certificates for authentication, then each client
 will also need to be issued a certificate. The recommendation is for the
 server to keep its certificates in either @code{/etc/pki/qemu} or for
@@ -1192,7 +1192,7 @@ keytab: /etc/qemu/krb5.tab
 For this to work the administrator of your KDC must generate a Kerberos
 principal for the server, with a name of  'qemu/somehost.example.com@@EXAMPLE.COM'
 replacing 'somehost.example.com' with the fully qualified host name of the
-machine running QEMU, and 'EXAMPLE.COM' with the Keberos Realm.
+machine running QEMU, and 'EXAMPLE.COM' with the Kerberos Realm.
 
 Other configurations will be left as an exercise for the reader. It should
 be noted that only Digest-MD5 and GSSAPI provides a SSF layer for data
@@ -1774,7 +1774,7 @@ enabled in the kernel, and expect 512M RAM.  Kernels for The PBX-A9 board
 should have CONFIG_SPARSEMEM enabled, CONFIG_REALVIEW_HIGH_PHYS_OFFSET
 disabled and expect 1024M RAM.
 
-The following devices are emuilated:
+The following devices are emulated:
 
 @itemize @minus
 @item
@@ -1874,7 +1874,7 @@ Secure Digital card connected to OMAP MMC/SD host
 @item
 Three OMAP on-chip UARTs and on-chip STI debugging console
 @item
-A Bluetooth(R) transciever and HCI connected to an UART
+A Bluetooth(R) transceiver and HCI connected to an UART
 @item
 Mentor Graphics "Inventra" dual-role USB controller embedded in a TI
 TUSB6010 chip - only USB host mode is supported
@@ -1936,7 +1936,7 @@ MV88W8618 audio controller, WM8750 CODEC and mixer
 @end itemize
 
 The Siemens SX1 models v1 and v2 (default) basic emulation.
-The emulaton includes the following elements:
+The emulation includes the following elements:
 
 @itemize @minus
 @item
@@ -2192,7 +2192,7 @@ Set the x86 stack size in bytes (default=524288)
 Select CPU model (-cpu ? for list and additional feature selection)
 @item -ignore-environment
 Start with an empty environment. Without this option,
-the inital environment is a copy of the caller's environment.
+the initial environment is a copy of the caller's environment.
 @item -E @var{var}=@var{value}
 Set environment @var{var} to @var{value}.
 @item -U @var{var}
@@ -2422,7 +2422,7 @@ Set the library root path (default=/)
 Set the stack size in bytes (default=524288)
 @item -ignore-environment
 Start with an empty environment. Without this option,
-the inital environment is a copy of the caller's environment.
+the initial environment is a copy of the caller's environment.
 @item -E @var{var}=@var{value}
 Set environment @var{var} to @var{value}.
 @item -U @var{var}
@@ -2495,7 +2495,7 @@ correct SDL directory when invoked.
 
 @item Install the MinGW version of zlib and make sure
 @file{zlib.h} and @file{libz.dll.a} are in
-MingGW's default header and linker search paths.
+MinGW's default header and linker search paths.
 
 @item Extract the current version of QEMU.
 
@@ -2530,7 +2530,7 @@ the QEMU configuration script.
 
 @item Install the MinGW version of zlib and make sure
 @file{zlib.h} and @file{libz.dll.a} are in
-MingGW's default header and linker search paths.
+MinGW's default header and linker search paths.
 
 @item
 Configure QEMU for Windows cross compilation:
@@ -2539,7 +2539,7 @@ PATH=/usr/i686-pc-mingw32/sys-root/mingw/bin:$PATH ./configure --cross-prefix='i
 @end example
 The example assumes @file{sdl-config} is installed under @file{/usr/i686-pc-mingw32/sys-root/mingw/bin} and
 MinGW cross compilation tools have names like @file{i686-pc-mingw32-gcc} and @file{i686-pc-mingw32-strip}.
-We set the @code{PATH} environment variable to ensure the MingW version of @file{sdl-config} is used and
+We set the @code{PATH} environment variable to ensure the MinGW version of @file{sdl-config} is used and
 use --cross-prefix to specify the name of the cross compiler.
 You can also use --prefix to set the Win32 install path which defaults to @file{c:/Program Files/Qemu}.
 
commit 2d983446ff853490f63eeefeabd7e352843cf856
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Fri Jan 7 18:59:15 2011 +0100

    qemu-doc: Add missing blanks
    
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/qemu-doc.texi b/qemu-doc.texi
index 744ba73..a1e6130 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -203,7 +203,7 @@ Intel 82801AA AC97 Audio compatible sound card
 @item
 Intel HD Audio Controller and HDA codec
 @item
-Adlib(OPL2) - Yamaha YM3812 compatible chip
+Adlib (OPL2) - Yamaha YM3812 compatible chip
 @item
 Gravis Ultrasound GF1 sound card
 @item
@@ -223,7 +223,7 @@ VGA BIOS.
 
 QEMU uses YM3812 emulation by Tatsuyuki Satoh.
 
-QEMU uses GUS emulation(GUSEMU32 @url{http://www.deinmeister.de/gusemu/})
+QEMU uses GUS emulation (GUSEMU32 @url{http://www.deinmeister.de/gusemu/})
 by Tibor "TS" Schütz.
 
 Not that, by default, GUS shares IRQ(7) with parallel ports and so
commit 576fd0a1cb07f6ee325f70d69ae3a4e2f0b283fc
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Fri Jan 7 18:59:14 2011 +0100

    qemu-doc: Add missing menu entry
    
    Each @section should have a menu entry and a @node entry.
    
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/qemu-doc.texi b/qemu-doc.texi
index 21d8a82..744ba73 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -162,6 +162,7 @@ TODO (no longer available)
 * pcsys_monitor::      QEMU Monitor
 * disk_images::        Disk Images
 * pcsys_network::      Network emulation
+* pcsys_other_devs::   Other Devices
 * direct_linux_boot::  Direct Linux Boot
 * pcsys_usb::          USB emulation
 * vnc_security::       VNC security
@@ -715,6 +716,7 @@ Using the @option{-net socket} option, it is possible to make VLANs
 that span several QEMU instances. See @ref{sec_invocation} to have a
 basic example.
 
+ at node pcsys_other_devs
 @section Other Devices
 
 @subsection Inter-VM Shared Memory device
commit 0d6753e5b3115c09313114afcdf554c34670359a
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Fri Jan 7 18:59:13 2011 +0100

    qemu-doc: Clean whitespace
    
    Remove blanks at line endings.
    
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/qemu-doc.texi b/qemu-doc.texi
index 7ce8999..21d8a82 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -832,7 +832,7 @@ Standard USB keyboard.  Will override the PS/2 keyboard (if present).
 Serial converter. This emulates an FTDI FT232BM chip connected to host character
 device @var{dev}. The available character devices are the same as for the
 @code{-serial} option. The @code{vendorid} and @code{productid} options can be
-used to override the default 0403:6001. For instance, 
+used to override the default 0403:6001. For instance,
 @example
 usb_add serial:productid=FA00:tcp:192.168.0.2:4444
 @end example
@@ -2201,7 +2201,7 @@ the address region required by guest applications is reserved on the host.
 This option is currently only supported on some hosts.
 @item -R size
 Pre-allocate a guest virtual address space of the given size (in bytes).
-"G", "M", and "k" suffixes may be used when specifying the size.  
+"G", "M", and "k" suffixes may be used when specifying the size.
 @end table
 
 Debug options:
commit 1a20a032ccbb5800bfdfc75accfcff2ac67f5bcb
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Jan 9 14:43:33 2011 +0000

    usb-bsd: fix a file descriptor leak
    
    Fix a file descriptor leak reported by cppcheck:
    [/src/qemu/usb-bsd.c:392]: (error) Resource leak: bfd
    [/src/qemu/usb-bsd.c:388]: (error) Resource leak: dfd
    
    Rearrange the code to avoid descriptor leaks. Also add braces as
    needed.
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/usb-bsd.c b/usb-bsd.c
index 48567a3..abcb60c 100644
--- a/usb-bsd.c
+++ b/usb-bsd.c
@@ -306,14 +306,15 @@ USBDevice *usb_host_device_open(const char *devname)
 {
     struct usb_device_info bus_info, dev_info;
     USBDevice *d = NULL;
-    USBHostDevice *dev;
+    USBHostDevice *dev, *ret = NULL;
     char ctlpath[PATH_MAX + 1];
     char buspath[PATH_MAX + 1];
     int bfd, dfd, bus, address, i;
     int ugendebug = UGEN_DEBUG_LEVEL;
 
-    if (usb_host_find_device(&bus, &address, devname) < 0)
-        return NULL;
+    if (usb_host_find_device(&bus, &address, devname) < 0) {
+        goto fail;
+    }
 
     snprintf(buspath, PATH_MAX, "/dev/usb%d", bus);
 
@@ -323,7 +324,7 @@ USBDevice *usb_host_device_open(const char *devname)
         printf("usb_host_device_open: failed to open usb bus - %s\n",
                strerror(errno));
 #endif
-        return NULL;
+        goto fail;
     }
 
     bus_info.udi_addr = address;
@@ -332,7 +333,7 @@ USBDevice *usb_host_device_open(const char *devname)
         printf("usb_host_device_open: failed to grab bus information - %s\n",
                strerror(errno));
 #endif
-        return NULL;
+        goto fail_bfd;
     }
 
 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
@@ -350,46 +351,52 @@ USBDevice *usb_host_device_open(const char *devname)
                    ctlpath, strerror(errno));
 #endif
         }
+        goto fail_dfd;
     }
 
-    if (dfd >= 0) {
-        if (ioctl(dfd, USB_GET_DEVICEINFO, &dev_info) < 0) {
+    if (ioctl(dfd, USB_GET_DEVICEINFO, &dev_info) < 0) {
 #ifdef DEBUG
-            printf("usb_host_device_open: failed to grab device info - %s\n",
-                   strerror(errno));
+        printf("usb_host_device_open: failed to grab device info - %s\n",
+               strerror(errno));
 #endif
-            goto fail;
-        }
+        goto fail_dfd;
+    }
 
-        d = usb_create(NULL /* FIXME */, "usb-host");
-        dev = DO_UPCAST(USBHostDevice, dev, d);
+    d = usb_create(NULL /* FIXME */, "usb-host");
+    dev = DO_UPCAST(USBHostDevice, dev, d);
 
-        if (dev_info.udi_speed == 1)
-            dev->dev.speed = USB_SPEED_LOW - 1;
-        else
-            dev->dev.speed = USB_SPEED_FULL - 1;
+    if (dev_info.udi_speed == 1) {
+        dev->dev.speed = USB_SPEED_LOW - 1;
+    } else {
+        dev->dev.speed = USB_SPEED_FULL - 1;
+    }
 
-        if (strncmp(dev_info.udi_product, "product", 7) != 0)
-            pstrcpy(dev->dev.product_desc, sizeof(dev->dev.product_desc),
-                    dev_info.udi_product);
-        else
-            snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc),
-                     "host:%s", devname);
+    if (strncmp(dev_info.udi_product, "product", 7) != 0) {
+        pstrcpy(dev->dev.product_desc, sizeof(dev->dev.product_desc),
+                dev_info.udi_product);
+    } else {
+        snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc),
+                 "host:%s", devname);
+    }
 
-        pstrcpy(dev->devpath, sizeof(dev->devpath), "/dev/");
-        pstrcat(dev->devpath, sizeof(dev->devpath), dev_info.udi_devnames[0]);
+    pstrcpy(dev->devpath, sizeof(dev->devpath), "/dev/");
+    pstrcat(dev->devpath, sizeof(dev->devpath), dev_info.udi_devnames[0]);
 
-        /* Mark the endpoints as not yet open */
-        for (i = 0; i < USB_MAX_ENDPOINTS; i++)
-           dev->ep_fd[i] = -1;
+    /* Mark the endpoints as not yet open */
+    for (i = 0; i < USB_MAX_ENDPOINTS; i++) {
+        dev->ep_fd[i] = -1;
+    }
 
-        ioctl(dfd, USB_SETDEBUG, &ugendebug);
+    ioctl(dfd, USB_SETDEBUG, &ugendebug);
 
-        return (USBDevice *)dev;
-    }
+    ret = (USBDevice *)dev;
 
+fail_dfd:
+    close(dfd);
+fail_bfd:
+    close(bfd);
 fail:
-    return NULL;
+    return ret;
 }
 
 static struct USBDeviceInfo usb_host_dev_info = {
commit d66bddd7a4535cca3fc9e98c3195a7411779693c
Author: Michael Walle <michael at walle.cc>
Date:   Sat Jan 8 17:53:30 2011 +0100

    alsaaudio: add endianness support for VoiceIn
    
    Signed-off-by: Michael Walle <michael at walle.cc>
    Signed-off-by: malc <av1474 at comtv.ru>

diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index 0741203..727b9f8 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -318,7 +318,7 @@ static int alsa_write (SWVoiceOut *sw, void *buf, int len)
     return audio_pcm_sw_write (sw, buf, len);
 }
 
-static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt)
+static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt, int endianness)
 {
     switch (fmt) {
     case AUD_FMT_S8:
@@ -328,16 +328,36 @@ static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt)
         return SND_PCM_FORMAT_U8;
 
     case AUD_FMT_S16:
-        return SND_PCM_FORMAT_S16_LE;
+        if (endianness) {
+            return SND_PCM_FORMAT_S16_BE;
+        }
+        else {
+            return SND_PCM_FORMAT_S16_LE;
+        }
 
     case AUD_FMT_U16:
-        return SND_PCM_FORMAT_U16_LE;
+        if (endianness) {
+            return SND_PCM_FORMAT_U16_BE;
+        }
+        else {
+            return SND_PCM_FORMAT_U16_LE;
+        }
 
     case AUD_FMT_S32:
-        return SND_PCM_FORMAT_S32_LE;
+        if (endianness) {
+            return SND_PCM_FORMAT_S32_BE;
+        }
+        else {
+            return SND_PCM_FORMAT_S32_LE;
+        }
 
     case AUD_FMT_U32:
-        return SND_PCM_FORMAT_U32_LE;
+        if (endianness) {
+            return SND_PCM_FORMAT_U32_BE;
+        }
+        else {
+            return SND_PCM_FORMAT_U32_LE;
+        }
 
     default:
         dolog ("Internal logic error: Bad audio format %d\n", fmt);
@@ -809,7 +829,7 @@ static int alsa_init_out (HWVoiceOut *hw, struct audsettings *as)
     snd_pcm_t *handle;
     struct audsettings obt_as;
 
-    req.fmt = aud_to_alsafmt (as->fmt);
+    req.fmt = aud_to_alsafmt (as->fmt, as->endianness);
     req.freq = as->freq;
     req.nchannels = as->nchannels;
     req.period_size = conf.period_size_out;
@@ -918,7 +938,7 @@ static int alsa_init_in (HWVoiceIn *hw, struct audsettings *as)
     snd_pcm_t *handle;
     struct audsettings obt_as;
 
-    req.fmt = aud_to_alsafmt (as->fmt);
+    req.fmt = aud_to_alsafmt (as->fmt, as->endianness);
     req.freq = as->freq;
     req.nchannels = as->nchannels;
     req.period_size = conf.period_size_in;
commit b6c9c9401c2f9eaf3ef93770c258d819ede7e11a
Author: Michael Walle <michael at walle.cc>
Date:   Sat Jan 8 17:53:29 2011 +0100

    ossaudio: add endianness support for VoiceIn
    
    Signed-off-by: Michael Walle <michael at walle.cc>
    Signed-off-by: malc <av1474 at comtv.ru>

diff --git a/audio/ossaudio.c b/audio/ossaudio.c
index 42bffae..d7a55e5 100644
--- a/audio/ossaudio.c
+++ b/audio/ossaudio.c
@@ -161,7 +161,7 @@ static int oss_write (SWVoiceOut *sw, void *buf, int len)
     return audio_pcm_sw_write (sw, buf, len);
 }
 
-static int aud_to_ossfmt (audfmt_e fmt)
+static int aud_to_ossfmt (audfmt_e fmt, int endianness)
 {
     switch (fmt) {
     case AUD_FMT_S8:
@@ -171,10 +171,20 @@ static int aud_to_ossfmt (audfmt_e fmt)
         return AFMT_U8;
 
     case AUD_FMT_S16:
-        return AFMT_S16_LE;
+        if (endianness) {
+            return AFMT_S16_BE;
+        }
+        else {
+            return AFMT_S16_LE;
+        }
 
     case AUD_FMT_U16:
-        return AFMT_U16_LE;
+        if (endianness) {
+            return AFMT_U16_BE;
+        }
+        else {
+            return AFMT_U16_LE;
+        }
 
     default:
         dolog ("Internal logic error: Bad audio format %d\n", fmt);
@@ -516,7 +526,7 @@ static int oss_init_out (HWVoiceOut *hw, struct audsettings *as)
 
     oss->fd = -1;
 
-    req.fmt = aud_to_ossfmt (as->fmt);
+    req.fmt = aud_to_ossfmt (as->fmt, as->endianness);
     req.freq = as->freq;
     req.nchannels = as->nchannels;
     req.fragsize = conf.fragsize;
@@ -682,7 +692,7 @@ static int oss_init_in (HWVoiceIn *hw, struct audsettings *as)
 
     oss->fd = -1;
 
-    req.fmt = aud_to_ossfmt (as->fmt);
+    req.fmt = aud_to_ossfmt (as->fmt, as->endianness);
     req.freq = as->freq;
     req.nchannels = as->nchannels;
     req.fragsize = conf.fragsize;
commit d43ffce14023df871d6065eb864d1f41eb441f37
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Thu Jan 6 22:43:14 2011 +0100

    tcg/mips: fix branch target change during code retranslation
    
    TCG on MIPS was trying to avoid changing the branch offset, but didn't
    due to a stupid typo. Fix it.
    
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c
index 2af7a2e..4e92a50 100644
--- a/tcg/mips/tcg-target.c
+++ b/tcg/mips/tcg-target.c
@@ -352,7 +352,7 @@ static inline void tcg_out_opc_imm(TCGContext *s, int opc, int rt, int rs, int i
 static inline void tcg_out_opc_br(TCGContext *s, int opc, int rt, int rs)
 {
     /* We need to keep the offset unchanged for retranslation */
-    uint16_t offset = (uint16_t)(*(uint32_t *) &s->code_ptr);
+    uint16_t offset = (uint16_t)(*(uint32_t *) s->code_ptr);
 
     tcg_out_opc_imm(s, opc, rt, rs, offset);
 }
commit 9a3abc21a61f95799c1f301b0b480a98a29fa0ff
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Thu Jan 6 22:43:13 2011 +0100

    tcg/arm: fix qemu_st64 for big endian targets
    
    Due to a typo, qemu_st64 doesn't properly byteswap the 32-bit low word of
    a 64 bit word before saving it. This patch fixes that.
    
    Acked-by: Andrzej Zaborowski <balrogg at gmail.com>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c
index 9def2e5..08c44c1 100644
--- a/tcg/arm/tcg-target.c
+++ b/tcg/arm/tcg-target.c
@@ -1248,7 +1248,7 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
             tcg_out_bswap32(s, COND_EQ, TCG_REG_R0, data_reg2);
             tcg_out_st32_rwb(s, COND_EQ, TCG_REG_R0, TCG_REG_R1, addr_reg);
             tcg_out_bswap32(s, COND_EQ, TCG_REG_R0, data_reg);
-            tcg_out_st32_12(s, COND_EQ, data_reg, TCG_REG_R1, 4);
+            tcg_out_st32_12(s, COND_EQ, TCG_REG_R0, TCG_REG_R1, 4);
         } else {
             tcg_out_st32_rwb(s, COND_EQ, data_reg, TCG_REG_R1, addr_reg);
             tcg_out_st32_12(s, COND_EQ, data_reg2, TCG_REG_R1, 4);
commit c69806ab82760a2e5ca880d41e8786276c838152
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Thu Jan 6 22:43:13 2011 +0100

    tcg/arm: fix branch target change during code retranslation
    
    QEMU uses code retranslation to restore the CPU state when an exception
    happens. For it to work the retranslation must not modify the generated
    code. This is what is currently implemented in ARM TCG.
    
    However on CPU that don't have icache/dcache/memory synchronised like
    ARM, this requirement is stronger and code retranslation must not modify
    the generated code "atomically", as the cache line might be flushed
    at any moment (interrupt, exception, task switching), even if not
    triggered by QEMU. The probability for this to happen is very low, and
    depends on cache size and associativiy, machine load, interrupts, so the
    symptoms are might happen randomly.
    
    This requirement is currently not followed in tcg/arm, for the
    load/store code, which basically has the following structure:
      1) tlb access code is written
      2) conditional fast path code is written
      3) branch is written with a temporary target
      4) slow path code is written
      5) branch target is updated
    The cache lines corresponding to the retranslated code is not flushed
    after code retranslation as the generated code is supposed to be the
    same. However if the cache line corresponding to the branch instruction
    is flushed between step 3 and 5, and is not flushed again before the
    code is executed again, the branch target is wrong. In the guest, the
    symptoms are MMU page fault at a random addresses, which leads to
    kernel page fault or segmentation faults.
    
    The patch fixes this issue by avoiding writing the branch target until
    it is known, that is by writing only the branch instruction first, and
    later only the offset.
    
    This fixes booting linux guests on ARM hosts (tested: arm, i386, mips,
    mipsel, sh4, sparc).
    
    Acked-by: Edgar E. Iglesias <edgar.iglesias at gmail.com>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c
index a3af5b2..9def2e5 100644
--- a/tcg/arm/tcg-target.c
+++ b/tcg/arm/tcg-target.c
@@ -113,12 +113,25 @@ static const int tcg_target_call_oarg_regs[2] = {
     TCG_REG_R0, TCG_REG_R1
 };
 
+static inline void reloc_abs32(void *code_ptr, tcg_target_long target)
+{
+    *(uint32_t *) code_ptr = target;
+}
+
+static inline void reloc_pc24(void *code_ptr, tcg_target_long target)
+{
+    uint32_t offset = ((target - ((tcg_target_long) code_ptr + 8)) >> 2);
+
+    *(uint32_t *) code_ptr = ((*(uint32_t *) code_ptr) & ~0xffffff)
+                             | (offset & 0xffffff);
+}
+
 static void patch_reloc(uint8_t *code_ptr, int type,
                 tcg_target_long value, tcg_target_long addend)
 {
     switch (type) {
     case R_ARM_ABS32:
-        *(uint32_t *) code_ptr = value;
+        reloc_abs32(code_ptr, value);
         break;
 
     case R_ARM_CALL:
@@ -127,8 +140,7 @@ static void patch_reloc(uint8_t *code_ptr, int type,
         tcg_abort();
 
     case R_ARM_PC24:
-        *(uint32_t *) code_ptr = ((*(uint32_t *) code_ptr) & 0xff000000) |
-                (((value - ((tcg_target_long) code_ptr + 8)) >> 2) & 0xffffff);
+        reloc_pc24(code_ptr, value);
         break;
     }
 }
@@ -1031,7 +1043,7 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
     }
 
     label_ptr = (void *) s->code_ptr;
-    tcg_out_b(s, COND_EQ, 8);
+    tcg_out_b_noaddr(s, COND_EQ);
 
     /* TODO: move this code to where the constants pool will be */
     if (addr_reg != TCG_REG_R0) {
@@ -1076,7 +1088,7 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
         break;
     }
 
-    *label_ptr += ((void *) s->code_ptr - (void *) label_ptr - 8) >> 2;
+    reloc_pc24(label_ptr, (tcg_target_long)s->code_ptr);
 #else /* !CONFIG_SOFTMMU */
     if (GUEST_BASE) {
         uint32_t offset = GUEST_BASE;
@@ -1245,7 +1257,7 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
     }
 
     label_ptr = (void *) s->code_ptr;
-    tcg_out_b(s, COND_EQ, 8);
+    tcg_out_b_noaddr(s, COND_EQ);
 
     /* TODO: move this code to where the constants pool will be */
     tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
@@ -1317,7 +1329,7 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
     if (opc == 3)
         tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R13, TCG_REG_R13, 0x10);
 
-    *label_ptr += ((void *) s->code_ptr - (void *) label_ptr - 8) >> 2;
+    reloc_pc24(label_ptr, (tcg_target_long)s->code_ptr);
 #else /* !CONFIG_SOFTMMU */
     if (GUEST_BASE) {
         uint32_t offset = GUEST_BASE;
@@ -1399,7 +1411,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
             /* Direct jump method */
 #if defined(USE_DIRECT_JUMP)
             s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
-            tcg_out_b(s, COND_AL, 8);
+            tcg_out_b_noaddr(s, COND_AL);
 #else
             tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_PC, -4);
             s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
commit 497aebb99e0700ba30b9b8d1e86f3452dcb18b28
Merge: cb752a6... 67af42a...
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Sat Jan 8 16:25:48 2011 +0100

    Merge branch 'linux-user-for-upstream' of git://gitorious.org/qemu-maemo/qemu
    
    * 'linux-user-for-upstream' of git://gitorious.org/qemu-maemo/qemu:
      Remove dead code for ARM semihosting commandline handling
      Fix commandline handling for ARM semihosted executables
      linux-user: Fix incorrect NaN detection in ARM nwfpe emulation
      softfloat: Implement floatx80_is_any_nan() and float128_is_any_nan()
      linux-user: Implement FS_IOC_FIEMAP ioctl
      linux-user: Support ioctls whose parameter size is not constant
      linux-user: Implement sync_file_range{,2} syscalls

commit 67af42ac5a6227d61a8ef4ba7289ada9418f2fb8
Author: Wolfgang Schildbach <wschi at dolby.com>
Date:   Mon Dec 6 15:06:06 2010 +0000

    Remove dead code for ARM semihosting commandline handling
    
    There are some bits in the code which were used to store the commandline for
    the semihosting call. These bits are now write-only and can be removed.
    
    Signed-off-by: Wolfgang Schildbach <wschi at dolby.com>
    Reviewed-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Riku Voipio <riku.voipio at iki.fi>

diff --git a/bsd-user/bsdload.c b/bsd-user/bsdload.c
index 14a93bf..6d9bb6f 100644
--- a/bsd-user/bsdload.c
+++ b/bsd-user/bsdload.c
@@ -176,8 +176,6 @@ int loader_exec(const char * filename, char ** argv, char ** envp,
 
     retval = prepare_binprm(&bprm);
 
-    infop->host_argv = argv;
-
     if(retval>=0) {
         if (bprm.buf[0] == 0x7f
                 && bprm.buf[1] == 'E'
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index 9763616..e343894 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -50,7 +50,6 @@ struct image_info {
     abi_ulong entry;
     abi_ulong code_offset;
     abi_ulong data_offset;
-    char      **host_argv;
     int       personality;
 };
 
diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c
index 9ee27c3..ac8c486 100644
--- a/linux-user/linuxload.c
+++ b/linux-user/linuxload.c
@@ -174,8 +174,6 @@ int loader_exec(const char * filename, char ** argv, char ** envp,
 
     retval = prepare_binprm(bprm);
 
-    infop->host_argv = argv;
-
     if(retval>=0) {
         if (bprm->buf[0] == 0x7f
                 && bprm->buf[1] == 'E'
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index e66a02b..32de241 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -50,7 +50,6 @@ struct image_info {
         abi_ulong       saved_auxv;
         abi_ulong       arg_start;
         abi_ulong       arg_end;
-        char            **host_argv;
 	int		personality;
 };
 
commit 2e8785acc601f72dd10ce19929c455689fc2649d
Author: Wolfgang Schildbach <wschi at dolby.com>
Date:   Mon Dec 6 15:06:05 2010 +0000

    Fix commandline handling for ARM semihosted executables
    
    Use the copy of the command line that loader_build_argptr() sets up in guest
    memory as the command line to return from the ARM SYS_GET_CMDLINE semihosting
    call. Previously we were using a pointer to memory which had already been
    freed before the guest program started.
    
    This fixes https://bugs.launchpad.net/qemu/+bug/673613 .
    
    Signed-off-by: Wolfgang Schildbach <wschi at dolby.com>
    Reviewed-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Riku Voipio <riku.voipio at iki.fi>

diff --git a/arm-semi.c b/arm-semi.c
index 0687b03..1d5179b 100644
--- a/arm-semi.c
+++ b/arm-semi.c
@@ -373,45 +373,64 @@ uint32_t do_arm_semihosting(CPUState *env)
 #ifdef CONFIG_USER_ONLY
         /* Build a commandline from the original argv.  */
         {
-            char **arg = ts->info->host_argv;
-            int len = ARG(1);
-            /* lock the buffer on the ARM side */
-            char *cmdline_buffer = (char*)lock_user(VERIFY_WRITE, ARG(0), len, 0);
+            char *arm_cmdline_buffer;
+            const char *host_cmdline_buffer;
 
-            if (!cmdline_buffer)
-                /* FIXME - should this error code be -TARGET_EFAULT ? */
-                return (uint32_t)-1;
+            unsigned int i;
+            unsigned int arm_cmdline_len = ARG(1);
+            unsigned int host_cmdline_len =
+                ts->info->arg_end-ts->info->arg_start;
+
+            if (!arm_cmdline_len || host_cmdline_len > arm_cmdline_len) {
+                return -1; /* not enough space to store command line */
+            }
 
-            s = cmdline_buffer;
-            while (*arg && len > 2) {
-                int n = strlen(*arg);
+            if (!host_cmdline_len) {
+                /* We special-case the "empty command line" case (argc==0).
+                   Just provide the terminating 0. */
+                arm_cmdline_buffer = lock_user(VERIFY_WRITE, ARG(0), 1, 0);
+                arm_cmdline_buffer[0] = 0;
+                unlock_user(arm_cmdline_buffer, ARG(0), 1);
 
-                if (s != cmdline_buffer) {
-                    *(s++) = ' ';
-                    len--;
-                }
-                if (n >= len)
-                    n = len - 1;
-                memcpy(s, *arg, n);
-                s += n;
-                len -= n;
-                arg++;
+                /* Adjust the commandline length argument. */
+                SET_ARG(1, 0);
+                return 0;
             }
-            /* Null terminate the string.  */
-            *s = 0;
-            len = s - cmdline_buffer;
 
-            /* Unlock the buffer on the ARM side.  */
-            unlock_user(cmdline_buffer, ARG(0), len);
+            /* lock the buffers on the ARM side */
+            arm_cmdline_buffer =
+                lock_user(VERIFY_WRITE, ARG(0), host_cmdline_len, 0);
+            host_cmdline_buffer =
+                lock_user(VERIFY_READ, ts->info->arg_start,
+                                       host_cmdline_len, 1);
 
-            /* Adjust the commandline length argument.  */
-            SET_ARG(1, len);
+            if (arm_cmdline_buffer && host_cmdline_buffer)
+            {
+                /* the last argument is zero-terminated;
+                   no need for additional termination */
+                memcpy(arm_cmdline_buffer, host_cmdline_buffer,
+                       host_cmdline_len);
 
-            /* Return success if commandline fit into buffer.  */
-            return *arg ? -1 : 0;
+                /* separate arguments by white spaces */
+                for (i = 0; i < host_cmdline_len-1; i++) {
+                    if (arm_cmdline_buffer[i] == 0) {
+                        arm_cmdline_buffer[i] = ' ';
+                    }
+                }
+
+                /* Adjust the commandline length argument. */
+                SET_ARG(1, host_cmdline_len-1);
+            }
+
+            /* Unlock the buffers on the ARM side.  */
+            unlock_user(arm_cmdline_buffer, ARG(0), host_cmdline_len);
+            unlock_user((void*)host_cmdline_buffer, ts->info->arg_start, 0);
+
+            /* Return success if we could return a commandline.  */
+            return (arm_cmdline_buffer && host_cmdline_buffer) ? 0 : -1;
         }
 #else
-      return -1;
+        return -1;
 #endif
     case SYS_HEAPINFO:
         {
commit 3ebe80c2993205ad6ad7ee0e800068f08932775c
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Thu Jan 6 18:34:44 2011 +0000

    linux-user: Fix incorrect NaN detection in ARM nwfpe emulation
    
    The code in the linux-user ARM nwfpe emulation was incorrectly
    checking only for quiet NaNs when it should have been checking
    for any kind of NaN. This is probably because the code in
    question was taken from the Linux kernel, whose copy of the
    softfloat library had been modified so that float*_is_nan()
    returned true for all NaNs, not just quiet ones. The qemu
    equivalent function is float*_is_any_nan(), so use that.
    NB that this code is really obsolete since nobody uses FPE
    for actual arithmetic now; this is just cleanup following
    the recent renaming of the NaN related functions.
    
    Acked-by: Aurelien Jarno <aurelien at aurel32.net>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Riku Voipio <riku.voipio at iki.fi>

diff --git a/linux-user/arm/nwfpe/fpa11_cprt.c b/linux-user/arm/nwfpe/fpa11_cprt.c
index 0e61b58..be54e95 100644
--- a/linux-user/arm/nwfpe/fpa11_cprt.c
+++ b/linux-user/arm/nwfpe/fpa11_cprt.c
@@ -199,21 +199,21 @@ static unsigned int PerformComparison(const unsigned int opcode)
    {
       case typeSingle:
         //printk("single.\n");
-	if (float32_is_quiet_nan(fpa11->fpreg[Fn].fSingle))
+	if (float32_is_any_nan(fpa11->fpreg[Fn].fSingle))
 	   goto unordered;
         rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
       break;
 
       case typeDouble:
         //printk("double.\n");
-	if (float64_is_quiet_nan(fpa11->fpreg[Fn].fDouble))
+	if (float64_is_any_nan(fpa11->fpreg[Fn].fDouble))
 	   goto unordered;
         rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status);
       break;
 
       case typeExtended:
         //printk("extended.\n");
-	if (floatx80_is_quiet_nan(fpa11->fpreg[Fn].fExtended))
+	if (floatx80_is_any_nan(fpa11->fpreg[Fn].fExtended))
 	   goto unordered;
         rFn = fpa11->fpreg[Fn].fExtended;
       break;
@@ -225,7 +225,7 @@ static unsigned int PerformComparison(const unsigned int opcode)
    {
      //printk("Fm is a constant: #%d.\n",Fm);
      rFm = getExtendedConstant(Fm);
-     if (floatx80_is_quiet_nan(rFm))
+     if (floatx80_is_any_nan(rFm))
         goto unordered;
    }
    else
@@ -235,21 +235,21 @@ static unsigned int PerformComparison(const unsigned int opcode)
       {
          case typeSingle:
            //printk("single.\n");
-	   if (float32_is_quiet_nan(fpa11->fpreg[Fm].fSingle))
+	   if (float32_is_any_nan(fpa11->fpreg[Fm].fSingle))
 	      goto unordered;
            rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status);
          break;
 
          case typeDouble:
            //printk("double.\n");
-	   if (float64_is_quiet_nan(fpa11->fpreg[Fm].fDouble))
+	   if (float64_is_any_nan(fpa11->fpreg[Fm].fDouble))
 	      goto unordered;
            rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status);
          break;
 
          case typeExtended:
            //printk("extended.\n");
-	   if (floatx80_is_quiet_nan(fpa11->fpreg[Fm].fExtended))
+	   if (floatx80_is_any_nan(fpa11->fpreg[Fm].fExtended))
 	      goto unordered;
            rFm = fpa11->fpreg[Fm].fExtended;
          break;
commit 2bed652fc596dee09f27dd7ab20528cf5eaf9203
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Thu Jan 6 18:34:43 2011 +0000

    softfloat: Implement floatx80_is_any_nan() and float128_is_any_nan()
    
    Implement versions of float*_is_any_nan() for the floatx80 and
    float128 types.
    
    Acked-by: Aurelien Jarno <aurelien at aurel32.net>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Riku Voipio <riku.voipio at iki.fi>

diff --git a/fpu/softfloat.h b/fpu/softfloat.h
index 15052cc..a6d0f16 100644
--- a/fpu/softfloat.h
+++ b/fpu/softfloat.h
@@ -489,6 +489,11 @@ INLINE int floatx80_is_zero(floatx80 a)
     return (a.high & 0x7fff) == 0 && a.low == 0;
 }
 
+INLINE int floatx80_is_any_nan(floatx80 a)
+{
+    return ((a.high & 0x7fff) == 0x7fff) && (a.low<<1);
+}
+
 #endif
 
 #ifdef FLOAT128
@@ -556,6 +561,12 @@ INLINE int float128_is_zero(float128 a)
     return (a.high & 0x7fffffffffffffffLL) == 0 && a.low == 0;
 }
 
+INLINE int float128_is_any_nan(float128 a)
+{
+    return ((a.high >> 48) & 0x7fff) == 0x7fff &&
+        ((a.low != 0) || ((a.high & 0xffffffffffffLL) != 0));
+}
+
 #endif
 
 #else /* CONFIG_SOFTFLOAT */
commit 285da2b9a83353703d07e141fdb447e82944146c
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Thu Jan 6 15:04:18 2011 +0000

    linux-user: Implement FS_IOC_FIEMAP ioctl
    
    Implement the FS_IOC_FIEMAP ioctl using the new support for
    custom handling of ioctls; this is needed because the struct
    that is passed includes a variable-length array.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Riku Voipio <riku.voipio at iki.fi>

diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
index 769e1bc..538e257 100644
--- a/linux-user/ioctls.h
+++ b/linux-user/ioctls.h
@@ -76,6 +76,10 @@
 #ifdef FIGETBSZ
      IOCTL(FIGETBSZ, IOC_R, MK_PTR(TYPE_LONG))
 #endif
+#ifdef FS_IOC_FIEMAP
+     IOCTL_SPECIAL(FS_IOC_FIEMAP, IOC_W | IOC_R, do_ioctl_fs_ioc_fiemap,
+                   MK_PTR(MK_STRUCT(STRUCT_fiemap)))
+#endif
 
   IOCTL(SIOCATMARK, 0, TYPE_NULL)
   IOCTL(SIOCADDRT, IOC_W, MK_PTR(MK_STRUCT(STRUCT_rtentry)))
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 970efe3..f10e17a 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -83,6 +83,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
 #include <linux/kd.h>
 #include <linux/mtio.h>
 #include <linux/fs.h>
+#include <linux/fiemap.h>
 #include <linux/fb.h>
 #include <linux/vt.h>
 #include "linux_loop.h"
@@ -2985,6 +2986,93 @@ struct IOCTLEntry {
 
 #define MAX_STRUCT_SIZE 4096
 
+/* So fiemap access checks don't overflow on 32 bit systems.
+ * This is very slightly smaller than the limit imposed by
+ * the underlying kernel.
+ */
+#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap))  \
+                            / sizeof(struct fiemap_extent))
+
+static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
+                                       int fd, abi_long cmd, abi_long arg)
+{
+    /* The parameter for this ioctl is a struct fiemap followed
+     * by an array of struct fiemap_extent whose size is set
+     * in fiemap->fm_extent_count. The array is filled in by the
+     * ioctl.
+     */
+    int target_size_in, target_size_out;
+    struct fiemap *fm;
+    const argtype *arg_type = ie->arg_type;
+    const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
+    void *argptr, *p;
+    abi_long ret;
+    int i, extent_size = thunk_type_size(extent_arg_type, 0);
+    uint32_t outbufsz;
+    int free_fm = 0;
+
+    assert(arg_type[0] == TYPE_PTR);
+    assert(ie->access == IOC_RW);
+    arg_type++;
+    target_size_in = thunk_type_size(arg_type, 0);
+    argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
+    if (!argptr) {
+        return -TARGET_EFAULT;
+    }
+    thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
+    unlock_user(argptr, arg, 0);
+    fm = (struct fiemap *)buf_temp;
+    if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
+        return -TARGET_EINVAL;
+    }
+
+    outbufsz = sizeof (*fm) +
+        (sizeof(struct fiemap_extent) * fm->fm_extent_count);
+
+    if (outbufsz > MAX_STRUCT_SIZE) {
+        /* We can't fit all the extents into the fixed size buffer.
+         * Allocate one that is large enough and use it instead.
+         */
+        fm = malloc(outbufsz);
+        if (!fm) {
+            return -TARGET_ENOMEM;
+        }
+        memcpy(fm, buf_temp, sizeof(struct fiemap));
+        free_fm = 1;
+    }
+    ret = get_errno(ioctl(fd, ie->host_cmd, fm));
+    if (!is_error(ret)) {
+        target_size_out = target_size_in;
+        /* An extent_count of 0 means we were only counting the extents
+         * so there are no structs to copy
+         */
+        if (fm->fm_extent_count != 0) {
+            target_size_out += fm->fm_mapped_extents * extent_size;
+        }
+        argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
+        if (!argptr) {
+            ret = -TARGET_EFAULT;
+        } else {
+            /* Convert the struct fiemap */
+            thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
+            if (fm->fm_extent_count != 0) {
+                p = argptr + target_size_in;
+                /* ...and then all the struct fiemap_extents */
+                for (i = 0; i < fm->fm_mapped_extents; i++) {
+                    thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
+                                  THUNK_TARGET);
+                    p += extent_size;
+                }
+            }
+            unlock_user(argptr, arg, target_size_out);
+        }
+    }
+    if (free_fm) {
+        free(fm);
+    }
+    return ret;
+}
+
 static IOCTLEntry ioctl_entries[] = {
 #define IOCTL(cmd, access, ...) \
     { TARGET_ ## cmd, cmd, #cmd, access, 0, {  __VA_ARGS__ } },
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 20c93d0..d02a9bf 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -783,6 +783,7 @@ struct target_pollfd {
 #define TARGET_BLKGETSIZE64 TARGET_IOR(0x12,114,sizeof(uint64_t)) /* return device size in bytes (u64 *arg) */
 #define TARGET_FIBMAP     TARGET_IO(0x00,1)  /* bmap access */
 #define TARGET_FIGETBSZ   TARGET_IO(0x00,2)  /* get the block size used for bmap */
+#define TARGET_FS_IOC_FIEMAP TARGET_IOWR('f',11,struct fiemap)
 
 /* cdrom commands */
 #define TARGET_CDROMPAUSE		0x5301 /* Pause Audio Operation */
diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h
index 340dbd3..0e67cd8 100644
--- a/linux-user/syscall_types.h
+++ b/linux-user/syscall_types.h
@@ -165,3 +165,19 @@ STRUCT(vt_stat,
        TYPE_SHORT, /* v_active */
        TYPE_SHORT, /* v_signal */
        TYPE_SHORT) /* v_state */
+
+STRUCT(fiemap_extent,
+       TYPE_ULONGLONG, /* fe_logical */
+       TYPE_ULONGLONG, /* fe_physical */
+       TYPE_ULONGLONG, /* fe_length */
+       MK_ARRAY(TYPE_ULONGLONG, 2), /* fe_reserved64[2] */
+       TYPE_INT, /* fe_flags */
+       MK_ARRAY(TYPE_INT, 3)) /* fe_reserved[3] */
+
+STRUCT(fiemap,
+       TYPE_ULONGLONG, /* fm_start */
+       TYPE_ULONGLONG, /* fm_length */
+       TYPE_INT, /* fm_flags */
+       TYPE_INT, /* fm_mapped_extents */
+       TYPE_INT, /* fm_extent_count */
+       TYPE_INT) /* fm_reserved */
commit d2ef05bb44e044e30f779ed9c4882c3c8299350d
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Thu Jan 6 15:04:17 2011 +0000

    linux-user: Support ioctls whose parameter size is not constant
    
    Some ioctls (for example FS_IOC_FIEMAP) use structures whose size is
    not constant. The generic argument conversion code in do_ioctl()
    cannot handle this, so add support for implementing a special-case
    handler for a particular ioctl which does the conversion itself.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Riku Voipio <riku.voipio at iki.fi>

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 1939a5f..970efe3 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -2965,13 +2965,19 @@ enum {
 #undef STRUCT
 #undef STRUCT_SPECIAL
 
-typedef struct IOCTLEntry {
+typedef struct IOCTLEntry IOCTLEntry;
+
+typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
+                             int fd, abi_long cmd, abi_long arg);
+
+struct IOCTLEntry {
     unsigned int target_cmd;
     unsigned int host_cmd;
     const char *name;
     int access;
+    do_ioctl_fn *do_ioctl;
     const argtype arg_type[5];
-} IOCTLEntry;
+};
 
 #define IOC_R 0x0001
 #define IOC_W 0x0002
@@ -2981,7 +2987,9 @@ typedef struct IOCTLEntry {
 
 static IOCTLEntry ioctl_entries[] = {
 #define IOCTL(cmd, access, ...) \
-    { TARGET_ ## cmd, cmd, #cmd, access, {  __VA_ARGS__ } },
+    { TARGET_ ## cmd, cmd, #cmd, access, 0, {  __VA_ARGS__ } },
+#define IOCTL_SPECIAL(cmd, access, dofn, ...)                      \
+    { TARGET_ ## cmd, cmd, #cmd, access, dofn, {  __VA_ARGS__ } },
 #include "ioctls.h"
     { 0, 0, },
 };
@@ -3011,6 +3019,10 @@ static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg)
 #if defined(DEBUG)
     gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
 #endif
+    if (ie->do_ioctl) {
+        return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
+    }
+
     switch(arg_type[0]) {
     case TYPE_NULL:
         /* no argument */
commit cb752a608c514c1f493144f25828b3ff15049f5e
Author: Edgar E. Iglesias <edgar at axis.com>
Date:   Fri Jan 7 16:18:13 2011 +0100

    cris: Allow more TB chaning
    
    Signed-off-by: Edgar E. Iglesias <edgar at axis.com>

diff --git a/target-cris/translate.c b/target-cris/translate.c
index 57d8532..5184155 100644
--- a/target-cris/translate.c
+++ b/target-cris/translate.c
@@ -1129,7 +1129,7 @@ static void cris_store_direct_jmp(DisasContext *dc)
 	/* Store the direct jmp state into the cpu-state.  */
 	if (dc->jmp == JMP_DIRECT) {
 		tcg_gen_movi_tl(env_btarget, dc->jmp_pc);
-		tcg_gen_movi_tl(env_btaken, 1);
+		dc->jmp = JMP_INDIRECT;
 	}
 }
 
@@ -1139,17 +1139,11 @@ static void cris_prepare_cc_branch (DisasContext *dc,
 	/* This helps us re-schedule the micro-code to insns in delay-slots
 	   before the actual jump.  */
 	dc->delayed_branch = 2;
+	dc->jmp = JMP_DIRECT;
 	dc->jmp_pc = dc->pc + offset;
 
-	if (cond != CC_A)
-	{
-		dc->jmp = JMP_INDIRECT;
-		gen_tst_cc (dc, env_btaken, cond);
-		tcg_gen_movi_tl(env_btarget, dc->jmp_pc);
-	} else {
-		/* Allow chaining.  */
-		dc->jmp = JMP_DIRECT;
-	}
+	gen_tst_cc (dc, env_btaken, cond);
+	tcg_gen_movi_tl(env_btarget, dc->jmp_pc);
 }
 
 
@@ -1161,8 +1155,7 @@ static inline void cris_prepare_jmp (DisasContext *dc, unsigned int type)
 	   before the actual jump.  */
 	dc->delayed_branch = 2;
 	dc->jmp = type;
-	if (type == JMP_INDIRECT)
-		tcg_gen_movi_tl(env_btaken, 1);
+	tcg_gen_movi_tl(env_btaken, 1);
 }
 
 static void gen_load64(DisasContext *dc, TCGv_i64 dst, TCGv addr)
@@ -3315,8 +3308,24 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
 				if (tb->flags & 7)
 					t_gen_mov_env_TN(dslot, 
 						tcg_const_tl(0));
+				if (dc->cpustate_changed || !dc->flagx_known
+				    || (dc->flags_x != (tb->flags & X_FLAG))) {
+					cris_store_direct_jmp(dc);
+				}
 				if (dc->jmp == JMP_DIRECT) {
-					dc->is_jmp = DISAS_NEXT;
+					int l1;
+
+					l1 = gen_new_label();
+					cris_evaluate_flags(dc);
+
+					/* Conditional jmp.  */
+					tcg_gen_brcondi_tl(TCG_COND_EQ,
+							   env_btaken, 0, l1);
+					gen_goto_tb(dc, 1, dc->jmp_pc);
+					gen_set_label(l1);
+					gen_goto_tb(dc, 0, dc->pc);
+					dc->is_jmp = DISAS_TB_JUMP;
+					dc->jmp = JMP_NOJMP;
 				} else {
 					t_gen_cc_jmp(env_btarget, 
 						     tcg_const_tl(dc->pc));
@@ -3336,16 +3345,10 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
 		 && (dc->pc < next_page_start)
                  && num_insns < max_insns);
 
-	if (dc->tb_flags != orig_flags) {
-		dc->cpustate_changed = 1;
-	}
-
 	if (dc->clear_locked_irq)
 		t_gen_mov_env_TN(locked_irq, tcg_const_tl(0));
 
 	npc = dc->pc;
-	if (dc->jmp == JMP_DIRECT && !dc->delayed_branch)
-		npc = dc->jmp_pc;
 
         if (tb->cflags & CF_LAST_IO)
             gen_io_end();
commit c727f47d59641c43ce171126232fd8049296adf6
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Thu Jan 6 11:05:10 2011 +0000

    linux-user: Implement sync_file_range{,2} syscalls
    
    Implement the missing syscalls sync_file_range and sync_file_range2.
    The latter in particular is used by newer versions of apt on Ubuntu
    for ARM.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Riku Voipio <riku.voipio at iki.fi>

diff --git a/configure b/configure
index 47e4cf0..831a741 100755
--- a/configure
+++ b/configure
@@ -2075,6 +2075,21 @@ if compile_prog "$ARCH_CFLAGS" "" ; then
   fallocate=yes
 fi
 
+# check for sync_file_range
+sync_file_range=no
+cat > $TMPC << EOF
+#include <fcntl.h>
+
+int main(void)
+{
+    sync_file_range(0, 0, 0, 0);
+    return 0;
+}
+EOF
+if compile_prog "$ARCH_CFLAGS" "" ; then
+  sync_file_range=yes
+fi
+
 # check for dup3
 dup3=no
 cat > $TMPC << EOF
@@ -2613,6 +2628,9 @@ fi
 if test "$fallocate" = "yes" ; then
   echo "CONFIG_FALLOCATE=y" >> $config_host_mak
 fi
+if test "$sync_file_range" = "yes" ; then
+  echo "CONFIG_SYNC_FILE_RANGE=y" >> $config_host_mak
+fi
 if test "$dup3" = "yes" ; then
   echo "CONFIG_DUP3=y" >> $config_host_mak
 fi
diff --git a/linux-user/strace.list b/linux-user/strace.list
index 97b7f76..d7be0e7 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -1518,3 +1518,9 @@
 #ifdef TARGET_NR_utimensat
 { TARGET_NR_utimensat, "utimensat", NULL, print_utimensat, NULL },
 #endif
+#ifdef TARGET_NR_sync_file_range
+{ TARGET_NR_sync_file_range, "sync_file_range", NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_sync_file_range2
+{ TARGET_NR_sync_file_range2, "sync_file_range2", NULL, NULL, NULL },
+#endif
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index c3e8706..1939a5f 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -7365,6 +7365,29 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
         ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
         break;
 #endif
+#if defined(CONFIG_SYNC_FILE_RANGE)
+#if defined(TARGET_NR_sync_file_range)
+    case TARGET_NR_sync_file_range:
+#if TARGET_ABI_BITS == 32
+        ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
+                                        target_offset64(arg4, arg5), arg6));
+#else
+        ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
+#endif
+        break;
+#endif
+#if defined(TARGET_NR_sync_file_range2)
+    case TARGET_NR_sync_file_range2:
+        /* This is like sync_file_range but the arguments are reordered */
+#if TARGET_ABI_BITS == 32
+        ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
+                                        target_offset64(arg5, arg6), arg2));
+#else
+        ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
+#endif
+        break;
+#endif
+#endif
     default:
     unimplemented:
         gemu_log("qemu: Unsupported syscall: %d\n", num);
commit 2a704b137f1acfbd972aa6e9f031c5015c7e28cb
Author: Edgar E. Iglesias <edgar at axis.com>
Date:   Fri Jan 7 12:50:38 2011 +0100

    cris: Avoid useless tmp in t_gen_cc_jmp()
    
    Signed-off-by: Edgar E. Iglesias <edgar at axis.com>

diff --git a/target-cris/translate.c b/target-cris/translate.c
index 4e4606c..57d8532 100644
--- a/target-cris/translate.c
+++ b/target-cris/translate.c
@@ -577,20 +577,15 @@ static inline void t_gen_swapr(TCGv d, TCGv s)
 
 static void t_gen_cc_jmp(TCGv pc_true, TCGv pc_false)
 {
-	TCGv btaken;
 	int l1;
 
 	l1 = gen_new_label();
-	btaken = tcg_temp_new();
 
 	/* Conditional jmp.  */
-	tcg_gen_mov_tl(btaken, env_btaken);
 	tcg_gen_mov_tl(env_pc, pc_false);
-	tcg_gen_brcondi_tl(TCG_COND_EQ, btaken, 0, l1);
+	tcg_gen_brcondi_tl(TCG_COND_EQ, env_btaken, 0, l1);
 	tcg_gen_mov_tl(env_pc, pc_true);
 	gen_set_label(l1);
-
-	tcg_temp_free(btaken);
 }
 
 static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
commit 78935c4a4bfec8ef2f4f924cfc35ac09a963e81e
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Thu Jan 6 22:28:33 2011 +0100

    cirrus: delete GCC 4.6 warnings
    
    Commit 92d675d1c1f23f3617e24b63c825074a1d1da44b triggered uninitialized
    variables warning with GCC 4.6. Fix them by adding zero initializers.
    
    Acked-by: Blue Swirl <blauwirbel at gmail.com>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index 833a2eb..75d1cc6 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -673,9 +673,9 @@ static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s)
 
 static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
 {
-    int sx, sy;
-    int dx, dy;
-    int depth;
+    int sx = 0, sy = 0;
+    int dx = 0, dy = 0;
+    int depth = 0;
     int notify = 0;
 
     /* make sure to only copy if it's a plain copy ROP */
commit cecd8504b80148b66cdc1ce32046429bc3549090
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Thu Jan 6 19:37:55 2011 +0000

    target-arm: wire up the softfloat flush_input_to_zero flag
    
    Wire up the new softfloat support for flushing input denormals
    to zero on ARM. The FPSCR FZ bit enables flush-to-zero for
    both inputs and outputs, but the reporting of when inputs are
    flushed to zero is via a separate IDC bit rather than the UFC
    (underflow) bit used when output denormals are flushed to zero.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Acked-by: Aurelien Jarno <aurelien at aurel32.net>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/target-arm/helper.c b/target-arm/helper.c
index 05684a2..705b99f 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -2242,6 +2242,8 @@ static inline int vfp_exceptbits_from_host(int host_bits)
         target_bits |= 8;
     if (host_bits & float_flag_inexact)
         target_bits |= 0x10;
+    if (host_bits & float_flag_input_denormal)
+        target_bits |= 0x80;
     return target_bits;
 }
 
@@ -2278,6 +2280,8 @@ static inline int vfp_exceptbits_to_host(int target_bits)
         host_bits |= float_flag_underflow;
     if (target_bits & 0x10)
         host_bits |= float_flag_inexact;
+    if (target_bits & 0x80)
+        host_bits |= float_flag_input_denormal;
     return host_bits;
 }
 
@@ -2310,8 +2314,10 @@ void HELPER(vfp_set_fpscr)(CPUState *env, uint32_t val)
         }
         set_float_rounding_mode(i, &env->vfp.fp_status);
     }
-    if (changed & (1 << 24))
+    if (changed & (1 << 24)) {
         set_flush_to_zero((val & (1 << 24)) != 0, &env->vfp.fp_status);
+        set_flush_inputs_to_zero((val & (1 << 24)) != 0, &env->vfp.fp_status);
+    }
     if (changed & (1 << 25))
         set_default_nan_mode((val & (1 << 25)) != 0, &env->vfp.fp_status);
 
commit b12c390b9108d44cb0b05900d6c11a73ee0e9cae
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Thu Jan 6 19:37:54 2011 +0000

    target-arm: Set softfloat cumulative exc flags from correct FPSCR bits
    
    When handling a write to the ARM FPSCR, set the softfloat cumulative
    exception flags from the cumulative flags in the FPSCR, not the
    exception-enable bits. Also don't apply a mask: vfp_exceptbits_to_host
    will only look at the correct bits anyway.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Acked-by: Aurelien Jarno <aurelien at aurel32.net>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/target-arm/helper.c b/target-arm/helper.c
index 50c1017..05684a2 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -2315,7 +2315,7 @@ void HELPER(vfp_set_fpscr)(CPUState *env, uint32_t val)
     if (changed & (1 << 25))
         set_default_nan_mode((val & (1 << 25)) != 0, &env->vfp.fp_status);
 
-    i = vfp_exceptbits_to_host((val >> 8) & 0x1f);
+    i = vfp_exceptbits_to_host(val);
     set_float_exception_flags(i, &env->vfp.fp_status);
 }
 
commit 37d18660bbb1d60b4e59bf407b4b301749e0c3b9
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Thu Jan 6 19:37:53 2011 +0000

    softfloat: Implement flushing input denormals to zero
    
    Add support to softfloat for flushing input denormal float32 and float64
    to zero. softfloat's existing 'flush_to_zero' flag only flushes denormals
    to zero on output. Some CPUs need input denormals to be flushed before
    processing as well. Implement this, using a new status flag to enable it
    and a new exception status bit to indicate when it has happened. Existing
    CPUs should be unaffected as there is no behaviour change unless the
    mode is enabled.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Acked-by: Aurelien Jarno <aurelien at aurel32.net>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index 6f5b05d..17842f4 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -30,8 +30,6 @@ these four paragraphs for those parts of this code that are retained.
 
 =============================================================================*/
 
-/* FIXME: Flush-To-Zero only effects results.  Denormal inputs should also
-   be flushed to zero.  */
 #include "softfloat.h"
 
 /*----------------------------------------------------------------------------
@@ -204,6 +202,21 @@ INLINE flag extractFloat32Sign( float32 a )
 }
 
 /*----------------------------------------------------------------------------
+| If `a' is denormal and we are in flush-to-zero mode then set the
+| input-denormal exception and return zero. Otherwise just return the value.
+*----------------------------------------------------------------------------*/
+static float32 float32_squash_input_denormal(float32 a STATUS_PARAM)
+{
+    if (STATUS(flush_inputs_to_zero)) {
+        if (extractFloat32Exp(a) == 0 && extractFloat32Frac(a) != 0) {
+            float_raise(float_flag_input_denormal STATUS_VAR);
+            return make_float32(float32_val(a) & 0x80000000);
+        }
+    }
+    return a;
+}
+
+/*----------------------------------------------------------------------------
 | Normalizes the subnormal single-precision floating-point value represented
 | by the denormalized significand `aSig'.  The normalized exponent and
 | significand are stored at the locations pointed to by `zExpPtr' and
@@ -368,6 +381,21 @@ INLINE flag extractFloat64Sign( float64 a )
 }
 
 /*----------------------------------------------------------------------------
+| If `a' is denormal and we are in flush-to-zero mode then set the
+| input-denormal exception and return zero. Otherwise just return the value.
+*----------------------------------------------------------------------------*/
+static float64 float64_squash_input_denormal(float64 a STATUS_PARAM)
+{
+    if (STATUS(flush_inputs_to_zero)) {
+        if (extractFloat64Exp(a) == 0 && extractFloat64Frac(a) != 0) {
+            float_raise(float_flag_input_denormal STATUS_VAR);
+            return make_float64(float64_val(a) & (1ULL << 63));
+        }
+    }
+    return a;
+}
+
+/*----------------------------------------------------------------------------
 | Normalizes the subnormal double-precision floating-point value represented
 | by the denormalized significand `aSig'.  The normalized exponent and
 | significand are stored at the locations pointed to by `zExpPtr' and
@@ -1298,6 +1326,7 @@ int32 float32_to_int32( float32 a STATUS_PARAM )
     bits32 aSig;
     bits64 aSig64;
 
+    a = float32_squash_input_denormal(a STATUS_VAR);
     aSig = extractFloat32Frac( a );
     aExp = extractFloat32Exp( a );
     aSign = extractFloat32Sign( a );
@@ -1327,6 +1356,7 @@ int32 float32_to_int32_round_to_zero( float32 a STATUS_PARAM )
     int16 aExp, shiftCount;
     bits32 aSig;
     int32 z;
+    a = float32_squash_input_denormal(a STATUS_VAR);
 
     aSig = extractFloat32Frac( a );
     aExp = extractFloat32Exp( a );
@@ -1418,6 +1448,7 @@ int64 float32_to_int64( float32 a STATUS_PARAM )
     int16 aExp, shiftCount;
     bits32 aSig;
     bits64 aSig64, aSigExtra;
+    a = float32_squash_input_denormal(a STATUS_VAR);
 
     aSig = extractFloat32Frac( a );
     aExp = extractFloat32Exp( a );
@@ -1455,6 +1486,7 @@ int64 float32_to_int64_round_to_zero( float32 a STATUS_PARAM )
     bits32 aSig;
     bits64 aSig64;
     int64 z;
+    a = float32_squash_input_denormal(a STATUS_VAR);
 
     aSig = extractFloat32Frac( a );
     aExp = extractFloat32Exp( a );
@@ -1496,6 +1528,7 @@ float64 float32_to_float64( float32 a STATUS_PARAM )
     flag aSign;
     int16 aExp;
     bits32 aSig;
+    a = float32_squash_input_denormal(a STATUS_VAR);
 
     aSig = extractFloat32Frac( a );
     aExp = extractFloat32Exp( a );
@@ -1528,6 +1561,7 @@ floatx80 float32_to_floatx80( float32 a STATUS_PARAM )
     int16 aExp;
     bits32 aSig;
 
+    a = float32_squash_input_denormal(a STATUS_VAR);
     aSig = extractFloat32Frac( a );
     aExp = extractFloat32Exp( a );
     aSign = extractFloat32Sign( a );
@@ -1561,6 +1595,7 @@ float128 float32_to_float128( float32 a STATUS_PARAM )
     int16 aExp;
     bits32 aSig;
 
+    a = float32_squash_input_denormal(a STATUS_VAR);
     aSig = extractFloat32Frac( a );
     aExp = extractFloat32Exp( a );
     aSign = extractFloat32Sign( a );
@@ -1593,6 +1628,7 @@ float32 float32_round_to_int( float32 a STATUS_PARAM)
     bits32 lastBitMask, roundBitsMask;
     int8 roundingMode;
     bits32 z;
+    a = float32_squash_input_denormal(a STATUS_VAR);
 
     aExp = extractFloat32Exp( a );
     if ( 0x96 <= aExp ) {
@@ -1796,6 +1832,8 @@ static float32 subFloat32Sigs( float32 a, float32 b, flag zSign STATUS_PARAM)
 float32 float32_add( float32 a, float32 b STATUS_PARAM )
 {
     flag aSign, bSign;
+    a = float32_squash_input_denormal(a STATUS_VAR);
+    b = float32_squash_input_denormal(b STATUS_VAR);
 
     aSign = extractFloat32Sign( a );
     bSign = extractFloat32Sign( b );
@@ -1817,6 +1855,8 @@ float32 float32_add( float32 a, float32 b STATUS_PARAM )
 float32 float32_sub( float32 a, float32 b STATUS_PARAM )
 {
     flag aSign, bSign;
+    a = float32_squash_input_denormal(a STATUS_VAR);
+    b = float32_squash_input_denormal(b STATUS_VAR);
 
     aSign = extractFloat32Sign( a );
     bSign = extractFloat32Sign( b );
@@ -1843,6 +1883,9 @@ float32 float32_mul( float32 a, float32 b STATUS_PARAM )
     bits64 zSig64;
     bits32 zSig;
 
+    a = float32_squash_input_denormal(a STATUS_VAR);
+    b = float32_squash_input_denormal(b STATUS_VAR);
+
     aSig = extractFloat32Frac( a );
     aExp = extractFloat32Exp( a );
     aSign = extractFloat32Sign( a );
@@ -1900,6 +1943,8 @@ float32 float32_div( float32 a, float32 b STATUS_PARAM )
     flag aSign, bSign, zSign;
     int16 aExp, bExp, zExp;
     bits32 aSig, bSig, zSig;
+    a = float32_squash_input_denormal(a STATUS_VAR);
+    b = float32_squash_input_denormal(b STATUS_VAR);
 
     aSig = extractFloat32Frac( a );
     aExp = extractFloat32Exp( a );
@@ -1966,6 +2011,8 @@ float32 float32_rem( float32 a, float32 b STATUS_PARAM )
     bits64 aSig64, bSig64, q64;
     bits32 alternateASig;
     sbits32 sigMean;
+    a = float32_squash_input_denormal(a STATUS_VAR);
+    b = float32_squash_input_denormal(b STATUS_VAR);
 
     aSig = extractFloat32Frac( a );
     aExp = extractFloat32Exp( a );
@@ -2062,6 +2109,7 @@ float32 float32_sqrt( float32 a STATUS_PARAM )
     int16 aExp, zExp;
     bits32 aSig, zSig;
     bits64 rem, term;
+    a = float32_squash_input_denormal(a STATUS_VAR);
 
     aSig = extractFloat32Frac( a );
     aExp = extractFloat32Exp( a );
@@ -2148,6 +2196,7 @@ float32 float32_exp2( float32 a STATUS_PARAM )
     bits32 aSig;
     float64 r, x, xn;
     int i;
+    a = float32_squash_input_denormal(a STATUS_VAR);
 
     aSig = extractFloat32Frac( a );
     aExp = extractFloat32Exp( a );
@@ -2194,6 +2243,7 @@ float32 float32_log2( float32 a STATUS_PARAM )
     int16 aExp;
     bits32 aSig, zSig, i;
 
+    a = float32_squash_input_denormal(a STATUS_VAR);
     aSig = extractFloat32Frac( a );
     aExp = extractFloat32Exp( a );
     aSign = extractFloat32Sign( a );
@@ -2238,6 +2288,8 @@ float32 float32_log2( float32 a STATUS_PARAM )
 
 int float32_eq( float32 a, float32 b STATUS_PARAM )
 {
+    a = float32_squash_input_denormal(a STATUS_VAR);
+    b = float32_squash_input_denormal(b STATUS_VAR);
 
     if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
          || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
@@ -2263,6 +2315,8 @@ int float32_le( float32 a, float32 b STATUS_PARAM )
 {
     flag aSign, bSign;
     bits32 av, bv;
+    a = float32_squash_input_denormal(a STATUS_VAR);
+    b = float32_squash_input_denormal(b STATUS_VAR);
 
     if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
          || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
@@ -2289,6 +2343,8 @@ int float32_lt( float32 a, float32 b STATUS_PARAM )
 {
     flag aSign, bSign;
     bits32 av, bv;
+    a = float32_squash_input_denormal(a STATUS_VAR);
+    b = float32_squash_input_denormal(b STATUS_VAR);
 
     if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
          || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
@@ -2315,6 +2371,8 @@ int float32_lt( float32 a, float32 b STATUS_PARAM )
 int float32_eq_signaling( float32 a, float32 b STATUS_PARAM )
 {
     bits32 av, bv;
+    a = float32_squash_input_denormal(a STATUS_VAR);
+    b = float32_squash_input_denormal(b STATUS_VAR);
 
     if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
          || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
@@ -2339,6 +2397,8 @@ int float32_le_quiet( float32 a, float32 b STATUS_PARAM )
 {
     flag aSign, bSign;
     bits32 av, bv;
+    a = float32_squash_input_denormal(a STATUS_VAR);
+    b = float32_squash_input_denormal(b STATUS_VAR);
 
     if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
          || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
@@ -2368,6 +2428,8 @@ int float32_lt_quiet( float32 a, float32 b STATUS_PARAM )
 {
     flag aSign, bSign;
     bits32 av, bv;
+    a = float32_squash_input_denormal(a STATUS_VAR);
+    b = float32_squash_input_denormal(b STATUS_VAR);
 
     if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
          || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
@@ -2401,6 +2463,7 @@ int32 float64_to_int32( float64 a STATUS_PARAM )
     flag aSign;
     int16 aExp, shiftCount;
     bits64 aSig;
+    a = float64_squash_input_denormal(a STATUS_VAR);
 
     aSig = extractFloat64Frac( a );
     aExp = extractFloat64Exp( a );
@@ -2429,6 +2492,7 @@ int32 float64_to_int32_round_to_zero( float64 a STATUS_PARAM )
     int16 aExp, shiftCount;
     bits64 aSig, savedASig;
     int32 z;
+    a = float64_squash_input_denormal(a STATUS_VAR);
 
     aSig = extractFloat64Frac( a );
     aExp = extractFloat64Exp( a );
@@ -2525,6 +2589,7 @@ int64 float64_to_int64( float64 a STATUS_PARAM )
     flag aSign;
     int16 aExp, shiftCount;
     bits64 aSig, aSigExtra;
+    a = float64_squash_input_denormal(a STATUS_VAR);
 
     aSig = extractFloat64Frac( a );
     aExp = extractFloat64Exp( a );
@@ -2568,6 +2633,7 @@ int64 float64_to_int64_round_to_zero( float64 a STATUS_PARAM )
     int16 aExp, shiftCount;
     bits64 aSig;
     int64 z;
+    a = float64_squash_input_denormal(a STATUS_VAR);
 
     aSig = extractFloat64Frac( a );
     aExp = extractFloat64Exp( a );
@@ -2617,6 +2683,7 @@ float32 float64_to_float32( float64 a STATUS_PARAM )
     int16 aExp;
     bits64 aSig;
     bits32 zSig;
+    a = float64_squash_input_denormal(a STATUS_VAR);
 
     aSig = extractFloat64Frac( a );
     aExp = extractFloat64Exp( a );
@@ -2694,6 +2761,7 @@ bits16 float32_to_float16( float32 a, flag ieee STATUS_PARAM)
     bits32 mask;
     bits32 increment;
     int8 roundingMode;
+    a = float32_squash_input_denormal(a STATUS_VAR);
 
     aSig = extractFloat32Frac( a );
     aExp = extractFloat32Exp( a );
@@ -2788,6 +2856,7 @@ floatx80 float64_to_floatx80( float64 a STATUS_PARAM )
     int16 aExp;
     bits64 aSig;
 
+    a = float64_squash_input_denormal(a STATUS_VAR);
     aSig = extractFloat64Frac( a );
     aExp = extractFloat64Exp( a );
     aSign = extractFloat64Sign( a );
@@ -2822,6 +2891,7 @@ float128 float64_to_float128( float64 a STATUS_PARAM )
     int16 aExp;
     bits64 aSig, zSig0, zSig1;
 
+    a = float64_squash_input_denormal(a STATUS_VAR);
     aSig = extractFloat64Frac( a );
     aExp = extractFloat64Exp( a );
     aSign = extractFloat64Sign( a );
@@ -2855,6 +2925,7 @@ float64 float64_round_to_int( float64 a STATUS_PARAM )
     bits64 lastBitMask, roundBitsMask;
     int8 roundingMode;
     bits64 z;
+    a = float64_squash_input_denormal(a STATUS_VAR);
 
     aExp = extractFloat64Exp( a );
     if ( 0x433 <= aExp ) {
@@ -3071,6 +3142,8 @@ static float64 subFloat64Sigs( float64 a, float64 b, flag zSign STATUS_PARAM )
 float64 float64_add( float64 a, float64 b STATUS_PARAM )
 {
     flag aSign, bSign;
+    a = float64_squash_input_denormal(a STATUS_VAR);
+    b = float64_squash_input_denormal(b STATUS_VAR);
 
     aSign = extractFloat64Sign( a );
     bSign = extractFloat64Sign( b );
@@ -3092,6 +3165,8 @@ float64 float64_add( float64 a, float64 b STATUS_PARAM )
 float64 float64_sub( float64 a, float64 b STATUS_PARAM )
 {
     flag aSign, bSign;
+    a = float64_squash_input_denormal(a STATUS_VAR);
+    b = float64_squash_input_denormal(b STATUS_VAR);
 
     aSign = extractFloat64Sign( a );
     bSign = extractFloat64Sign( b );
@@ -3116,6 +3191,9 @@ float64 float64_mul( float64 a, float64 b STATUS_PARAM )
     int16 aExp, bExp, zExp;
     bits64 aSig, bSig, zSig0, zSig1;
 
+    a = float64_squash_input_denormal(a STATUS_VAR);
+    b = float64_squash_input_denormal(b STATUS_VAR);
+
     aSig = extractFloat64Frac( a );
     aExp = extractFloat64Exp( a );
     aSign = extractFloat64Sign( a );
@@ -3175,6 +3253,8 @@ float64 float64_div( float64 a, float64 b STATUS_PARAM )
     bits64 aSig, bSig, zSig;
     bits64 rem0, rem1;
     bits64 term0, term1;
+    a = float64_squash_input_denormal(a STATUS_VAR);
+    b = float64_squash_input_denormal(b STATUS_VAR);
 
     aSig = extractFloat64Frac( a );
     aExp = extractFloat64Exp( a );
@@ -3246,6 +3326,8 @@ float64 float64_rem( float64 a, float64 b STATUS_PARAM )
     bits64 q, alternateASig;
     sbits64 sigMean;
 
+    a = float64_squash_input_denormal(a STATUS_VAR);
+    b = float64_squash_input_denormal(b STATUS_VAR);
     aSig = extractFloat64Frac( a );
     aExp = extractFloat64Exp( a );
     aSign = extractFloat64Sign( a );
@@ -3328,6 +3410,7 @@ float64 float64_sqrt( float64 a STATUS_PARAM )
     int16 aExp, zExp;
     bits64 aSig, zSig, doubleZSig;
     bits64 rem0, rem1, term0, term1;
+    a = float64_squash_input_denormal(a STATUS_VAR);
 
     aSig = extractFloat64Frac( a );
     aExp = extractFloat64Exp( a );
@@ -3377,6 +3460,7 @@ float64 float64_log2( float64 a STATUS_PARAM )
     flag aSign, zSign;
     int16 aExp;
     bits64 aSig, aSig0, aSig1, zSig, i;
+    a = float64_squash_input_denormal(a STATUS_VAR);
 
     aSig = extractFloat64Frac( a );
     aExp = extractFloat64Exp( a );
@@ -3422,6 +3506,8 @@ float64 float64_log2( float64 a STATUS_PARAM )
 int float64_eq( float64 a, float64 b STATUS_PARAM )
 {
     bits64 av, bv;
+    a = float64_squash_input_denormal(a STATUS_VAR);
+    b = float64_squash_input_denormal(b STATUS_VAR);
 
     if (    ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
          || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
@@ -3448,6 +3534,8 @@ int float64_le( float64 a, float64 b STATUS_PARAM )
 {
     flag aSign, bSign;
     bits64 av, bv;
+    a = float64_squash_input_denormal(a STATUS_VAR);
+    b = float64_squash_input_denormal(b STATUS_VAR);
 
     if (    ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
          || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
@@ -3475,6 +3563,8 @@ int float64_lt( float64 a, float64 b STATUS_PARAM )
     flag aSign, bSign;
     bits64 av, bv;
 
+    a = float64_squash_input_denormal(a STATUS_VAR);
+    b = float64_squash_input_denormal(b STATUS_VAR);
     if (    ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
          || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
        ) {
@@ -3500,6 +3590,8 @@ int float64_lt( float64 a, float64 b STATUS_PARAM )
 int float64_eq_signaling( float64 a, float64 b STATUS_PARAM )
 {
     bits64 av, bv;
+    a = float64_squash_input_denormal(a STATUS_VAR);
+    b = float64_squash_input_denormal(b STATUS_VAR);
 
     if (    ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
          || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
@@ -3524,6 +3616,8 @@ int float64_le_quiet( float64 a, float64 b STATUS_PARAM )
 {
     flag aSign, bSign;
     bits64 av, bv;
+    a = float64_squash_input_denormal(a STATUS_VAR);
+    b = float64_squash_input_denormal(b STATUS_VAR);
 
     if (    ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
          || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
@@ -3553,6 +3647,8 @@ int float64_lt_quiet( float64 a, float64 b STATUS_PARAM )
 {
     flag aSign, bSign;
     bits64 av, bv;
+    a = float64_squash_input_denormal(a STATUS_VAR);
+    b = float64_squash_input_denormal(b STATUS_VAR);
 
     if (    ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
          || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
@@ -5833,6 +5929,8 @@ INLINE int float ## s ## _compare_internal( float ## s a, float ## s b,      \
 {                                                                            \
     flag aSign, bSign;                                                       \
     bits ## s av, bv;                                                        \
+    a = float ## s ## _squash_input_denormal(a STATUS_VAR);                  \
+    b = float ## s ## _squash_input_denormal(b STATUS_VAR);                  \
                                                                              \
     if (( ( extractFloat ## s ## Exp( a ) == nan_exp ) &&                    \
          extractFloat ## s ## Frac( a ) ) ||                                 \
@@ -5929,6 +6027,7 @@ float32 float32_scalbn( float32 a, int n STATUS_PARAM )
     int16 aExp;
     bits32 aSig;
 
+    a = float32_squash_input_denormal(a STATUS_VAR);
     aSig = extractFloat32Frac( a );
     aExp = extractFloat32Exp( a );
     aSign = extractFloat32Sign( a );
@@ -5952,6 +6051,7 @@ float64 float64_scalbn( float64 a, int n STATUS_PARAM )
     int16 aExp;
     bits64 aSig;
 
+    a = float64_squash_input_denormal(a STATUS_VAR);
     aSig = extractFloat64Frac( a );
     aExp = extractFloat64Exp( a );
     aSign = extractFloat64Sign( a );
diff --git a/fpu/softfloat.h b/fpu/softfloat.h
index f2104c6..15052cc 100644
--- a/fpu/softfloat.h
+++ b/fpu/softfloat.h
@@ -180,7 +180,8 @@ enum {
     float_flag_divbyzero =  4,
     float_flag_overflow  =  8,
     float_flag_underflow = 16,
-    float_flag_inexact   = 32
+    float_flag_inexact   = 32,
+    float_flag_input_denormal = 64
 };
 
 typedef struct float_status {
@@ -190,7 +191,10 @@ typedef struct float_status {
 #ifdef FLOATX80
     signed char floatx80_rounding_precision;
 #endif
+    /* should denormalised results go to zero and set the inexact flag? */
     flag flush_to_zero;
+    /* should denormalised inputs go to zero and set the input_denormal flag? */
+    flag flush_inputs_to_zero;
     flag default_nan_mode;
 } float_status;
 
@@ -200,6 +204,10 @@ INLINE void set_flush_to_zero(flag val STATUS_PARAM)
 {
     STATUS(flush_to_zero) = val;
 }
+INLINE void set_flush_inputs_to_zero(flag val STATUS_PARAM)
+{
+    STATUS(flush_inputs_to_zero) = val;
+}
 INLINE void set_default_nan_mode(flag val STATUS_PARAM)
 {
     STATUS(default_nan_mode) = val;
@@ -294,11 +302,17 @@ float32 float32_scalbn( float32, int STATUS_PARAM );
 
 INLINE float32 float32_abs(float32 a)
 {
+    /* Note that abs does *not* handle NaN specially, nor does
+     * it flush denormal inputs to zero.
+     */
     return make_float32(float32_val(a) & 0x7fffffff);
 }
 
 INLINE float32 float32_chs(float32 a)
 {
+    /* Note that chs does *not* handle NaN specially, nor does
+     * it flush denormal inputs to zero.
+     */
     return make_float32(float32_val(a) ^ 0x80000000);
 }
 
@@ -374,11 +388,17 @@ float64 float64_scalbn( float64, int STATUS_PARAM );
 
 INLINE float64 float64_abs(float64 a)
 {
+    /* Note that abs does *not* handle NaN specially, nor does
+     * it flush denormal inputs to zero.
+     */
     return make_float64(float64_val(a) & 0x7fffffffffffffffLL);
 }
 
 INLINE float64 float64_chs(float64 a)
 {
+    /* Note that chs does *not* handle NaN specially, nor does
+     * it flush denormal inputs to zero.
+     */
     return make_float64(float64_val(a) ^ 0x8000000000000000LL);
 }
 
commit 838fa72d0b721766616e94a0f7dc76b15146cd82
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Thu Jan 6 19:53:56 2011 +0100

    target-arm: fix SMMLA/SMMLS instructions
    
    SMMLA and SMMLS are broken on both in normal and thumb mode, that is
    both (different) implementations are wrong. They try to avoid a 64-bit
    add for the rounding, which is not trivial if you want to support both
    SMMLA and SMMLS with the same code.
    
    The code below uses the same implementation for both modes, using the
    code from the ARM manual. It also fixes the thumb decoding that was a
    mix between normal and thumb mode.
    
    This fixes the issues reported in
    https://bugs.launchpad.net/qemu/+bug/629298
    
    Reviewed-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/target-arm/translate.c b/target-arm/translate.c
index 2598268..2ce82f3 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -287,11 +287,32 @@ static void gen_bfi(TCGv dest, TCGv base, TCGv val, int shift, uint32_t mask)
     tcg_gen_or_i32(dest, base, val);
 }
 
-/* Round the top 32 bits of a 64-bit value.  */
-static void gen_roundqd(TCGv a, TCGv b)
+/* Return (b << 32) + a. Mark inputs as dead */
+static TCGv_i64 gen_addq_msw(TCGv_i64 a, TCGv b)
 {
-    tcg_gen_shri_i32(a, a, 31);
-    tcg_gen_add_i32(a, a, b);
+    TCGv_i64 tmp64 = tcg_temp_new_i64();
+
+    tcg_gen_extu_i32_i64(tmp64, b);
+    dead_tmp(b);
+    tcg_gen_shli_i64(tmp64, tmp64, 32);
+    tcg_gen_add_i64(a, tmp64, a);
+
+    tcg_temp_free_i64(tmp64);
+    return a;
+}
+
+/* Return (b << 32) - a. Mark inputs as dead. */
+static TCGv_i64 gen_subq_msw(TCGv_i64 a, TCGv b)
+{
+    TCGv_i64 tmp64 = tcg_temp_new_i64();
+
+    tcg_gen_extu_i32_i64(tmp64, b);
+    dead_tmp(b);
+    tcg_gen_shli_i64(tmp64, tmp64, 32);
+    tcg_gen_sub_i64(a, tmp64, a);
+
+    tcg_temp_free_i64(tmp64);
+    return a;
 }
 
 /* FIXME: Most targets have native widening multiplication.
@@ -325,22 +346,6 @@ static TCGv_i64 gen_muls_i64_i32(TCGv a, TCGv b)
     return tmp1;
 }
 
-/* Signed 32x32->64 multiply.  */
-static void gen_imull(TCGv a, TCGv b)
-{
-    TCGv_i64 tmp1 = tcg_temp_new_i64();
-    TCGv_i64 tmp2 = tcg_temp_new_i64();
-
-    tcg_gen_ext_i32_i64(tmp1, a);
-    tcg_gen_ext_i32_i64(tmp2, b);
-    tcg_gen_mul_i64(tmp1, tmp1, tmp2);
-    tcg_temp_free_i64(tmp2);
-    tcg_gen_trunc_i64_i32(a, tmp1);
-    tcg_gen_shri_i64(tmp1, tmp1, 32);
-    tcg_gen_trunc_i64_i32(b, tmp1);
-    tcg_temp_free_i64(tmp1);
-}
-
 /* Swap low and high halfwords.  */
 static void gen_swap_half(TCGv var)
 {
@@ -6953,23 +6958,25 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                     tmp = load_reg(s, rm);
                     tmp2 = load_reg(s, rs);
                     if (insn & (1 << 20)) {
-                        /* Signed multiply most significant [accumulate].  */
+                        /* Signed multiply most significant [accumulate].
+                           (SMMUL, SMMLA, SMMLS) */
                         tmp64 = gen_muls_i64_i32(tmp, tmp2);
-                        if (insn & (1 << 5))
-                            tcg_gen_addi_i64(tmp64, tmp64, 0x80000000u);
-                        tcg_gen_shri_i64(tmp64, tmp64, 32);
-                        tmp = new_tmp();
-                        tcg_gen_trunc_i64_i32(tmp, tmp64);
-                        tcg_temp_free_i64(tmp64);
+
                         if (rd != 15) {
-                            tmp2 = load_reg(s, rd);
+                            tmp = load_reg(s, rd);
                             if (insn & (1 << 6)) {
-                                tcg_gen_sub_i32(tmp, tmp, tmp2);
+                                tmp64 = gen_subq_msw(tmp64, tmp);
                             } else {
-                                tcg_gen_add_i32(tmp, tmp, tmp2);
+                                tmp64 = gen_addq_msw(tmp64, tmp);
                             }
-                            dead_tmp(tmp2);
                         }
+                        if (insn & (1 << 5)) {
+                            tcg_gen_addi_i64(tmp64, tmp64, 0x80000000u);
+                        }
+                        tcg_gen_shri_i64(tmp64, tmp64, 32);
+                        tmp = new_tmp();
+                        tcg_gen_trunc_i64_i32(tmp, tmp64);
+                        tcg_temp_free_i64(tmp64);
                         store_reg(s, rn, tmp);
                     } else {
                         if (insn & (1 << 5))
@@ -7840,24 +7847,23 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                     dead_tmp(tmp2);
                   }
                 break;
-            case 5: case 6: /* 32 * 32 -> 32msb */
-                gen_imull(tmp, tmp2);
-                if (insn & (1 << 5)) {
-                    gen_roundqd(tmp, tmp2);
-                    dead_tmp(tmp2);
-                } else {
-                    dead_tmp(tmp);
-                    tmp = tmp2;
-                }
+            case 5: case 6: /* 32 * 32 -> 32msb (SMMUL, SMMLA, SMMLS) */
+                tmp64 = gen_muls_i64_i32(tmp, tmp2);
                 if (rs != 15) {
-                    tmp2 = load_reg(s, rs);
-                    if (insn & (1 << 21)) {
-                        tcg_gen_add_i32(tmp, tmp, tmp2);
+                    tmp = load_reg(s, rs);
+                    if (insn & (1 << 20)) {
+                        tmp64 = gen_addq_msw(tmp64, tmp);
                     } else {
-                        tcg_gen_sub_i32(tmp, tmp2, tmp);
+                        tmp64 = gen_subq_msw(tmp64, tmp);
                     }
-                    dead_tmp(tmp2);
                 }
+                if (insn & (1 << 4)) {
+                    tcg_gen_addi_i64(tmp64, tmp64, 0x80000000u);
+                }
+                tcg_gen_shri_i64(tmp64, tmp64, 32);
+                tmp = new_tmp();
+                tcg_gen_trunc_i64_i32(tmp, tmp64);
+                tcg_temp_free_i64(tmp64);
                 break;
             case 7: /* Unsigned sum of absolute differences.  */
                 gen_helper_usad8(tmp, tmp, tmp2);
commit 71df0eeb98a1ecff7770aa486faf08a8c1049745
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Thu Jan 6 18:25:37 2011 +0000

    block: delete a write-only variable
    
    Avoid a warning with GCC 4.6.0:
    /src/qemu/block.c: In function 'bdrv_img_create':
    /src/qemu/block.c:2862:25: error: variable 'fmt' set but not used [-Werror=unused-but-set-variable]
    
    CC: Kevin Wolf <kwolf at redhat.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/block.c b/block.c
index 9b5e9e1..ff2795b 100644
--- a/block.c
+++ b/block.c
@@ -2859,13 +2859,8 @@ int bdrv_img_create(const char *filename, const char *fmt,
     if (get_option_parameter(param, BLOCK_OPT_SIZE)->value.n == -1) {
         if (backing_file && backing_file->value.s) {
             uint64_t size;
-            const char *fmt = NULL;
             char buf[32];
 
-            if (backing_fmt && backing_fmt->value.s) {
-                fmt = backing_fmt->value.s;
-            }
-
             bs = bdrv_new("");
 
             ret = bdrv_open(bs, backing_file->value.s, flags, drv);
commit 3fbb33d08d63908849a037ad6432cb12c763dd12
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Thu Jan 6 18:25:26 2011 +0000

    cirrus_vga: Declare as little endian
    
    This patch replaces explicit bswaps with endianness hints to the
    mmio layer.
    
    CC: Alexander Graf <agraf at suse.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index 199136c..833a2eb 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -2004,30 +2004,20 @@ static uint32_t cirrus_vga_mem_readb(void *opaque, target_phys_addr_t addr)
 static uint32_t cirrus_vga_mem_readw(void *opaque, target_phys_addr_t addr)
 {
     uint32_t v;
-#ifdef TARGET_WORDS_BIGENDIAN
-    v = cirrus_vga_mem_readb(opaque, addr) << 8;
-    v |= cirrus_vga_mem_readb(opaque, addr + 1);
-#else
+
     v = cirrus_vga_mem_readb(opaque, addr);
     v |= cirrus_vga_mem_readb(opaque, addr + 1) << 8;
-#endif
     return v;
 }
 
 static uint32_t cirrus_vga_mem_readl(void *opaque, target_phys_addr_t addr)
 {
     uint32_t v;
-#ifdef TARGET_WORDS_BIGENDIAN
-    v = cirrus_vga_mem_readb(opaque, addr) << 24;
-    v |= cirrus_vga_mem_readb(opaque, addr + 1) << 16;
-    v |= cirrus_vga_mem_readb(opaque, addr + 2) << 8;
-    v |= cirrus_vga_mem_readb(opaque, addr + 3);
-#else
+
     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;
-#endif
     return v;
 }
 
@@ -2098,28 +2088,16 @@ 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)
 {
-#ifdef TARGET_WORDS_BIGENDIAN
-    cirrus_vga_mem_writeb(opaque, addr, (val >> 8) & 0xff);
-    cirrus_vga_mem_writeb(opaque, addr + 1, val & 0xff);
-#else
     cirrus_vga_mem_writeb(opaque, addr, val & 0xff);
     cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-#endif
 }
 
 static void cirrus_vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
-#ifdef TARGET_WORDS_BIGENDIAN
-    cirrus_vga_mem_writeb(opaque, addr, (val >> 24) & 0xff);
-    cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
-    cirrus_vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
-    cirrus_vga_mem_writeb(opaque, addr + 3, val & 0xff);
-#else
     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);
-#endif
 }
 
 static CPUReadMemoryFunc * const cirrus_vga_mem_read[3] = {
@@ -2341,30 +2319,20 @@ static uint32_t cirrus_linear_readb(void *opaque, target_phys_addr_t addr)
 static uint32_t cirrus_linear_readw(void *opaque, target_phys_addr_t addr)
 {
     uint32_t v;
-#ifdef TARGET_WORDS_BIGENDIAN
-    v = cirrus_linear_readb(opaque, addr) << 8;
-    v |= cirrus_linear_readb(opaque, addr + 1);
-#else
+
     v = cirrus_linear_readb(opaque, addr);
     v |= cirrus_linear_readb(opaque, addr + 1) << 8;
-#endif
     return v;
 }
 
 static uint32_t cirrus_linear_readl(void *opaque, target_phys_addr_t addr)
 {
     uint32_t v;
-#ifdef TARGET_WORDS_BIGENDIAN
-    v = cirrus_linear_readb(opaque, addr) << 24;
-    v |= cirrus_linear_readb(opaque, addr + 1) << 16;
-    v |= cirrus_linear_readb(opaque, addr + 2) << 8;
-    v |= cirrus_linear_readb(opaque, addr + 3);
-#else
+
     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;
-#endif
     return v;
 }
 
@@ -2412,29 +2380,17 @@ 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)
 {
-#ifdef TARGET_WORDS_BIGENDIAN
-    cirrus_linear_writeb(opaque, addr, (val >> 8) & 0xff);
-    cirrus_linear_writeb(opaque, addr + 1, val & 0xff);
-#else
     cirrus_linear_writeb(opaque, addr, val & 0xff);
     cirrus_linear_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-#endif
 }
 
 static void cirrus_linear_writel(void *opaque, target_phys_addr_t addr,
 				 uint32_t val)
 {
-#ifdef TARGET_WORDS_BIGENDIAN
-    cirrus_linear_writeb(opaque, addr, (val >> 24) & 0xff);
-    cirrus_linear_writeb(opaque, addr + 1, (val >> 16) & 0xff);
-    cirrus_linear_writeb(opaque, addr + 2, (val >> 8) & 0xff);
-    cirrus_linear_writeb(opaque, addr + 3, val & 0xff);
-#else
     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);
-#endif
 }
 
 
@@ -2469,30 +2425,20 @@ static uint32_t cirrus_linear_bitblt_readb(void *opaque, target_phys_addr_t addr
 static uint32_t cirrus_linear_bitblt_readw(void *opaque, target_phys_addr_t addr)
 {
     uint32_t v;
-#ifdef TARGET_WORDS_BIGENDIAN
-    v = cirrus_linear_bitblt_readb(opaque, addr) << 8;
-    v |= cirrus_linear_bitblt_readb(opaque, addr + 1);
-#else
+
     v = cirrus_linear_bitblt_readb(opaque, addr);
     v |= cirrus_linear_bitblt_readb(opaque, addr + 1) << 8;
-#endif
     return v;
 }
 
 static uint32_t cirrus_linear_bitblt_readl(void *opaque, target_phys_addr_t addr)
 {
     uint32_t v;
-#ifdef TARGET_WORDS_BIGENDIAN
-    v = cirrus_linear_bitblt_readb(opaque, addr) << 24;
-    v |= cirrus_linear_bitblt_readb(opaque, addr + 1) << 16;
-    v |= cirrus_linear_bitblt_readb(opaque, addr + 2) << 8;
-    v |= cirrus_linear_bitblt_readb(opaque, addr + 3);
-#else
+
     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;
-#endif
     return v;
 }
 
@@ -2513,29 +2459,17 @@ 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)
 {
-#ifdef TARGET_WORDS_BIGENDIAN
-    cirrus_linear_bitblt_writeb(opaque, addr, (val >> 8) & 0xff);
-    cirrus_linear_bitblt_writeb(opaque, addr + 1, val & 0xff);
-#else
     cirrus_linear_bitblt_writeb(opaque, addr, val & 0xff);
     cirrus_linear_bitblt_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-#endif
 }
 
 static void cirrus_linear_bitblt_writel(void *opaque, target_phys_addr_t addr,
 				 uint32_t val)
 {
-#ifdef TARGET_WORDS_BIGENDIAN
-    cirrus_linear_bitblt_writeb(opaque, addr, (val >> 24) & 0xff);
-    cirrus_linear_bitblt_writeb(opaque, addr + 1, (val >> 16) & 0xff);
-    cirrus_linear_bitblt_writeb(opaque, addr + 2, (val >> 8) & 0xff);
-    cirrus_linear_bitblt_writeb(opaque, addr + 3, val & 0xff);
-#else
     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);
-#endif
 }
 
 
@@ -2842,30 +2776,20 @@ 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;
-#ifdef TARGET_WORDS_BIGENDIAN
-    v = cirrus_mmio_readb(opaque, addr) << 8;
-    v |= cirrus_mmio_readb(opaque, addr + 1);
-#else
+
     v = cirrus_mmio_readb(opaque, addr);
     v |= cirrus_mmio_readb(opaque, addr + 1) << 8;
-#endif
     return v;
 }
 
 static uint32_t cirrus_mmio_readl(void *opaque, target_phys_addr_t addr)
 {
     uint32_t v;
-#ifdef TARGET_WORDS_BIGENDIAN
-    v = cirrus_mmio_readb(opaque, addr) << 24;
-    v |= cirrus_mmio_readb(opaque, addr + 1) << 16;
-    v |= cirrus_mmio_readb(opaque, addr + 2) << 8;
-    v |= cirrus_mmio_readb(opaque, addr + 3);
-#else
+
     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;
-#endif
     return v;
 }
 
@@ -2886,29 +2810,17 @@ 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)
 {
-#ifdef TARGET_WORDS_BIGENDIAN
-    cirrus_mmio_writeb(opaque, addr, (val >> 8) & 0xff);
-    cirrus_mmio_writeb(opaque, addr + 1, val & 0xff);
-#else
     cirrus_mmio_writeb(opaque, addr, val & 0xff);
     cirrus_mmio_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-#endif
 }
 
 static void cirrus_mmio_writel(void *opaque, target_phys_addr_t addr,
 			       uint32_t val)
 {
-#ifdef TARGET_WORDS_BIGENDIAN
-    cirrus_mmio_writeb(opaque, addr, (val >> 24) & 0xff);
-    cirrus_mmio_writeb(opaque, addr + 1, (val >> 16) & 0xff);
-    cirrus_mmio_writeb(opaque, addr + 2, (val >> 8) & 0xff);
-    cirrus_mmio_writeb(opaque, addr + 3, val & 0xff);
-#else
     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);
-#endif
 }
 
 
@@ -3078,7 +2990,7 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci)
 
     s->vga.vga_io_memory = cpu_register_io_memory(cirrus_vga_mem_read,
                                                   cirrus_vga_mem_write, s,
-                                                  DEVICE_NATIVE_ENDIAN);
+                                                  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);
@@ -3086,18 +2998,18 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci)
     /* I/O handler for LFB */
     s->cirrus_linear_io_addr =
         cpu_register_io_memory(cirrus_linear_read, cirrus_linear_write, s,
-                               DEVICE_NATIVE_ENDIAN);
+                               DEVICE_LITTLE_ENDIAN);
 
     /* 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_NATIVE_ENDIAN);
+                               DEVICE_LITTLE_ENDIAN);
 
     /* 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_NATIVE_ENDIAN);
+                               DEVICE_LITTLE_ENDIAN);
 
     s->real_vram_size =
         (s->device_id == CIRRUS_ID_CLGD5446) ? 4096 * 1024 : 2048 * 1024;
commit 4b78a802ffaabb325a0f7b773031da92d173bde1
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Thu Jan 6 18:24:35 2011 +0000

    pc: move port 92 stuff back to pc.c from pckbd.c
    
    956a3e6bb7386de48b642d4fee11f7f86a2fcf9a introduced a bug concerning
    reset bit for port 92.
    
    Since the keyboard output port and port 92 are not compatible anyway,
    let's separate them.
    
    Reported-by: Peter Lieven <pl at dlh.net>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
    --
    v2: added reset handler and VMState

diff --git a/hw/pc.c b/hw/pc.c
index 18a4a9f..fface7d 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -411,11 +411,92 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
     qemu_register_reset(pc_cmos_init_late, &arg);
 }
 
+/* port 92 stuff: could be split off */
+typedef struct Port92State {
+    ISADevice dev;
+    uint8_t outport;
+    qemu_irq *a20_out;
+} Port92State;
+
+static void port92_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    Port92State *s = opaque;
+
+    DPRINTF("port92: write 0x%02x\n", val);
+    s->outport = val;
+    qemu_set_irq(*s->a20_out, (val >> 1) & 1);
+    if (val & 1) {
+        qemu_system_reset_request();
+    }
+}
+
+static uint32_t port92_read(void *opaque, uint32_t addr)
+{
+    Port92State *s = opaque;
+    uint32_t ret;
+
+    ret = s->outport;
+    DPRINTF("port92: read 0x%02x\n", ret);
+    return ret;
+}
+
+static void port92_init(ISADevice *dev, qemu_irq *a20_out)
+{
+    Port92State *s = DO_UPCAST(Port92State, dev, dev);
+
+    s->a20_out = a20_out;
+}
+
+static const VMStateDescription vmstate_port92_isa = {
+    .name = "port92",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT8(outport, Port92State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void port92_reset(DeviceState *d)
+{
+    Port92State *s = container_of(d, Port92State, dev.qdev);
+
+    s->outport &= ~1;
+}
+
+static int port92_initfn(ISADevice *dev)
+{
+    Port92State *s = DO_UPCAST(Port92State, dev, dev);
+
+    register_ioport_read(0x92, 1, 1, port92_read, s);
+    register_ioport_write(0x92, 1, 1, port92_write, s);
+    isa_init_ioport(dev, 0x92);
+    s->outport = 0;
+    return 0;
+}
+
+static ISADeviceInfo port92_info = {
+    .qdev.name     = "port92",
+    .qdev.size     = sizeof(Port92State),
+    .qdev.vmsd     = &vmstate_port92_isa,
+    .qdev.no_user  = 1,
+    .qdev.reset    = port92_reset,
+    .init          = port92_initfn,
+};
+
+static void port92_register(void)
+{
+    isa_qdev_register(&port92_info);
+}
+device_init(port92_register)
+
 static void handle_a20_line_change(void *opaque, int irq, int level)
 {
     CPUState *cpu = opaque;
 
     /* XXX: send to all CPUs ? */
+    /* XXX: add logic to handle multiple A20 line sources */
     cpu_x86_set_a20(cpu, level);
 }
 
@@ -1027,7 +1108,7 @@ void pc_basic_device_init(qemu_irq *isa_irq,
     PITState *pit;
     qemu_irq rtc_irq = NULL;
     qemu_irq *a20_line;
-    ISADevice *i8042;
+    ISADevice *i8042, *port92;
     qemu_irq *cpu_exit_irq;
 
     register_ioport_write(0x80, 1, 1, ioport80_write, NULL);
@@ -1061,10 +1142,12 @@ void pc_basic_device_init(qemu_irq *isa_irq,
         }
     }
 
-    a20_line = qemu_allocate_irqs(handle_a20_line_change, first_cpu, 1);
+    a20_line = qemu_allocate_irqs(handle_a20_line_change, first_cpu, 2);
     i8042 = isa_create_simple("i8042");
-    i8042_setup_a20_line(i8042, a20_line);
+    i8042_setup_a20_line(i8042, &a20_line[0]);
     vmmouse_init(i8042);
+    port92 = isa_create_simple("port92");
+    port92_init(port92, &a20_line[1]);
 
     cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
     DMA_init(0, cpu_exit_irq);
diff --git a/hw/pckbd.c b/hw/pckbd.c
index 863b485..ae65c04 100644
--- a/hw/pckbd.c
+++ b/hw/pckbd.c
@@ -211,10 +211,8 @@ static void kbd_queue(KBDState *s, int b, int aux)
         ps2_queue(s->kbd, b);
 }
 
-static void ioport92_write(void *opaque, uint32_t addr, uint32_t val)
+static void outport_write(KBDState *s, uint32_t val)
 {
-    KBDState *s = opaque;
-
     DPRINTF("kbd: write outport=0x%02x\n", val);
     s->outport = val;
     if (s->a20_out) {
@@ -225,16 +223,6 @@ static void ioport92_write(void *opaque, uint32_t addr, uint32_t val)
     }
 }
 
-static uint32_t ioport92_read(void *opaque, uint32_t addr)
-{
-    KBDState *s = opaque;
-    uint32_t ret;
-
-    ret = s->outport;
-    DPRINTF("kbd: read outport=0x%02x\n", ret);
-    return ret;
-}
-
 static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
 {
     KBDState *s = opaque;
@@ -357,7 +345,7 @@ static void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
         kbd_queue(s, val, 1);
         break;
     case KBD_CCMD_WRITE_OUTPORT:
-        ioport92_write(s, 0, val);
+        outport_write(s, val);
         break;
     case KBD_CCMD_WRITE_MOUSE:
         ps2_write_mouse(s->mouse, val);
@@ -489,9 +477,6 @@ static int i8042_initfn(ISADevice *dev)
     register_ioport_read(0x64, 1, 1, kbd_read_status, s);
     register_ioport_write(0x64, 1, 1, kbd_write_command, s);
     isa_init_ioport(dev, 0x64);
-    register_ioport_read(0x92, 1, 1, ioport92_read, s);
-    register_ioport_write(0x92, 1, 1, ioport92_write, s);
-    isa_init_ioport(dev, 0x92);
 
     s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
     s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
commit e024e881bb1a8b5085026589360d26ed97acdd64
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Thu Jan 6 15:38:19 2011 +0100

    target-ppc: Implement correct NaN propagation rules
    
    Implement the correct NaN propagation rules for PowerPC targets by
    providing an appropriate pickNaN function.
    
    Also fix the #ifdef tests for default NaN definition, the correct name
    is TARGET_PPC instead of TARGET_POWERPC.
    
    Reviewed-by: Nathan Froyd <froydnj at codesourcery.com>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h
index acdd299..f293f24 100644
--- a/fpu/softfloat-specialize.h
+++ b/fpu/softfloat-specialize.h
@@ -61,7 +61,7 @@ typedef struct {
 *----------------------------------------------------------------------------*/
 #if defined(TARGET_SPARC)
 #define float32_default_nan make_float32(0x7FFFFFFF)
-#elif defined(TARGET_POWERPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA)
+#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA)
 #define float32_default_nan make_float32(0x7FC00000)
 #elif SNAN_BIT_IS_ONE
 #define float32_default_nan make_float32(0x7FBFFFFF)
@@ -219,6 +219,21 @@ static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
         return 1;
     }
 }
+#elif defined(TARGET_PPC)
+static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
+                   flag aIsLargerSignificand)
+{
+    /* PowerPC propagation rules:
+     *  1. A if it sNaN or qNaN
+     *  2. B if it sNaN or qNaN
+     * A signaling NaN is always silenced before returning it.
+     */
+    if (aIsSNaN || aIsQNaN) {
+        return 0;
+    } else {
+        return 1;
+    }
+}
 #else
 static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
                     flag aIsLargerSignificand)
@@ -296,7 +311,7 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM)
 *----------------------------------------------------------------------------*/
 #if defined(TARGET_SPARC)
 #define float64_default_nan make_float64(LIT64( 0x7FFFFFFFFFFFFFFF ))
-#elif defined(TARGET_POWERPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA)
+#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA)
 #define float64_default_nan make_float64(LIT64( 0x7FF8000000000000 ))
 #elif SNAN_BIT_IS_ONE
 #define float64_default_nan make_float64(LIT64( 0x7FF7FFFFFFFFFFFF ))
commit 084d19ba718a08d434dc44a83ff01f3152d59635
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Thu Jan 6 15:38:19 2011 +0100

    target-mips: Implement correct NaN propagation rules
    
    Implement the correct NaN propagation rules for MIPS targets by
    providing an appropriate pickNaN function.
    
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h
index 3ce5bb5..acdd299 100644
--- a/fpu/softfloat-specialize.h
+++ b/fpu/softfloat-specialize.h
@@ -192,6 +192,33 @@ static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
         return 1;
     }
 }
+#elif defined(TARGET_MIPS)
+static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
+                    flag aIsLargerSignificand)
+{
+    /* According to MIPS specifications, if one of the two operands is
+     * a sNaN, a new qNaN has to be generated. This is done in
+     * floatXX_maybe_silence_nan(). For qNaN inputs the specifications
+     * says: "When possible, this QNaN result is one of the operand QNaN
+     * values." In practice it seems that most implementations choose
+     * the first operand if both operands are qNaN. In short this gives
+     * the following rules:
+     *  1. A if it is signaling
+     *  2. B if it is signaling
+     *  3. A (quiet)
+     *  4. B (quiet)
+     * A signaling NaN is always silenced before returning it.
+     */
+    if (aIsSNaN) {
+        return 0;
+    } else if (bIsSNaN) {
+        return 1;
+    } else if (aIsQNaN) {
+        return 0;
+    } else {
+        return 1;
+    }
+}
 #else
 static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
                     flag aIsLargerSignificand)
commit 1f398e0825b3365746ac3a3f6f5a9954b0064f28
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Thu Jan 6 15:38:19 2011 +0100

    softfloat: use float{32,64,x80,128}_maybe_silence_nan()
    
    Use float{32,64,x80,128}_maybe_silence_nan() instead of toggling the
    sNaN bit manually. This allow per target implementation of sNaN to qNaN
    conversion.
    
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>
    Reviewed-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h
index b1acc45..3ce5bb5 100644
--- a/fpu/softfloat-specialize.h
+++ b/fpu/softfloat-specialize.h
@@ -161,7 +161,8 @@ static float32 commonNaNToFloat32( commonNaNT a )
 | The routine is passed various bits of information about the
 | two NaNs and should return 0 to select NaN a and 1 for NaN b.
 | Note that signalling NaNs are always squashed to quiet NaNs
-| by the caller, by flipping the SNaN bit before returning them.
+| by the caller, by calling floatXX_maybe_silence_nan() before
+| returning them.
 |
 | aIsLargerSignificand is only valid if both a and b are NaNs
 | of some kind, and is true if a has the larger significand,
@@ -233,7 +234,7 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM)
 {
     flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN;
     flag aIsLargerSignificand;
-    bits32 av, bv, res;
+    bits32 av, bv;
 
     if ( STATUS(default_nan_mode) )
         return float32_default_nan;
@@ -244,13 +245,7 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM)
     bIsSignalingNaN = float32_is_signaling_nan( b );
     av = float32_val(a);
     bv = float32_val(b);
-#if SNAN_BIT_IS_ONE
-    av &= ~0x00400000;
-    bv &= ~0x00400000;
-#else
-    av |= 0x00400000;
-    bv |= 0x00400000;
-#endif
+
     if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
 
     if ((bits32)(av<<1) < (bits32)(bv<<1)) {
@@ -263,12 +258,10 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM)
 
     if (pickNaN(aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN,
                 aIsLargerSignificand)) {
-        res = bv;
+        return float32_maybe_silence_nan(b);
     } else {
-        res = av;
+        return float32_maybe_silence_nan(a);
     }
-
-    return make_float32(res);
 }
 
 /*----------------------------------------------------------------------------
@@ -386,7 +379,7 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM)
 {
     flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN;
     flag aIsLargerSignificand;
-    bits64 av, bv, res;
+    bits64 av, bv;
 
     if ( STATUS(default_nan_mode) )
         return float64_default_nan;
@@ -397,13 +390,7 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM)
     bIsSignalingNaN = float64_is_signaling_nan( b );
     av = float64_val(a);
     bv = float64_val(b);
-#if SNAN_BIT_IS_ONE
-    av &= ~LIT64( 0x0008000000000000 );
-    bv &= ~LIT64( 0x0008000000000000 );
-#else
-    av |= LIT64( 0x0008000000000000 );
-    bv |= LIT64( 0x0008000000000000 );
-#endif
+
     if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
 
     if ((bits64)(av<<1) < (bits64)(bv<<1)) {
@@ -416,12 +403,10 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM)
 
     if (pickNaN(aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN,
                 aIsLargerSignificand)) {
-        res = bv;
+        return float64_maybe_silence_nan(b);
     } else {
-        res = av;
+        return float64_maybe_silence_nan(a);
     }
-
-    return make_float64(res);
 }
 
 #ifdef FLOATX80
@@ -557,13 +542,7 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM)
     aIsSignalingNaN = floatx80_is_signaling_nan( a );
     bIsQuietNaN = floatx80_is_quiet_nan( b );
     bIsSignalingNaN = floatx80_is_signaling_nan( b );
-#if SNAN_BIT_IS_ONE
-    a.low &= ~LIT64( 0xC000000000000000 );
-    b.low &= ~LIT64( 0xC000000000000000 );
-#else
-    a.low |= LIT64( 0xC000000000000000 );
-    b.low |= LIT64( 0xC000000000000000 );
-#endif
+
     if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
 
     if (a.low < b.low) {
@@ -576,9 +555,9 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM)
 
     if (pickNaN(aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN,
                 aIsLargerSignificand)) {
-        return b;
+        return floatx80_maybe_silence_nan(b);
     } else {
-        return a;
+        return floatx80_maybe_silence_nan(a);
     }
 }
 
@@ -708,13 +687,7 @@ static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM)
     aIsSignalingNaN = float128_is_signaling_nan( a );
     bIsQuietNaN = float128_is_quiet_nan( b );
     bIsSignalingNaN = float128_is_signaling_nan( b );
-#if SNAN_BIT_IS_ONE
-    a.high &= ~LIT64( 0x0000800000000000 );
-    b.high &= ~LIT64( 0x0000800000000000 );
-#else
-    a.high |= LIT64( 0x0000800000000000 );
-    b.high |= LIT64( 0x0000800000000000 );
-#endif
+
     if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
 
     if (lt128(a.high<<1, a.low, b.high<<1, b.low)) {
@@ -727,9 +700,9 @@ static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM)
 
     if (pickNaN(aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN,
                 aIsLargerSignificand)) {
-        return b;
+        return float128_maybe_silence_nan(b);
     } else {
-        return a;
+        return float128_maybe_silence_nan(a);
     }
 }
 
commit f6a7d92aed30964b6096d921e3c0df0487bb7b22
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Thu Jan 6 15:38:19 2011 +0100

    softfloat: add float{x80,128}_maybe_silence_nan()
    
    Add float{x80,128}_maybe_silence_nan() functions, they will be need by
    propagateFloat{x80,128}NaN().
    
    Reviewed-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h
index bc6f0c1..b1acc45 100644
--- a/fpu/softfloat-specialize.h
+++ b/fpu/softfloat-specialize.h
@@ -480,6 +480,29 @@ int floatx80_is_signaling_nan( floatx80 a )
 }
 
 /*----------------------------------------------------------------------------
+| Returns a quiet NaN if the extended double-precision floating point value
+| `a' is a signaling NaN; otherwise returns `a'.
+*----------------------------------------------------------------------------*/
+
+floatx80 floatx80_maybe_silence_nan( floatx80 a )
+{
+    if (floatx80_is_signaling_nan(a)) {
+#if SNAN_BIT_IS_ONE
+#  if defined(TARGET_MIPS)
+        a.low = floatx80_default_nan_low;
+        a.high = floatx80_default_nan_high;
+#  else
+#    error Rules for silencing a signaling NaN are target-specific
+#  endif
+#else
+        a.low |= LIT64( 0xC000000000000000 );
+        return a;
+#endif
+    }
+    return a;
+}
+
+/*----------------------------------------------------------------------------
 | Returns the result of converting the extended double-precision floating-
 | point NaN `a' to the canonical NaN format.  If `a' is a signaling NaN, the
 | invalid exception is raised.
@@ -612,6 +635,29 @@ int float128_is_signaling_nan( float128 a )
 }
 
 /*----------------------------------------------------------------------------
+| Returns a quiet NaN if the quadruple-precision floating point value `a' is
+| a signaling NaN; otherwise returns `a'.
+*----------------------------------------------------------------------------*/
+
+float128 float128_maybe_silence_nan( float128 a )
+{
+    if (float128_is_signaling_nan(a)) {
+#if SNAN_BIT_IS_ONE
+#  if defined(TARGET_MIPS)
+        a.low = float128_default_nan_low;
+        a.high = float128_default_nan_high;
+#  else
+#    error Rules for silencing a signaling NaN are target-specific
+#  endif
+#else
+        a.high |= LIT64( 0x0000800000000000 );
+        return a;
+#endif
+    }
+    return a;
+}
+
+/*----------------------------------------------------------------------------
 | Returns the result of converting the quadruple-precision floating-point NaN
 | `a' to the canonical NaN format.  If `a' is a signaling NaN, the invalid
 | exception is raised.
diff --git a/fpu/softfloat.h b/fpu/softfloat.h
index 1f37877..f2104c6 100644
--- a/fpu/softfloat.h
+++ b/fpu/softfloat.h
@@ -439,6 +439,7 @@ int floatx80_le_quiet( floatx80, floatx80 STATUS_PARAM );
 int floatx80_lt_quiet( floatx80, floatx80 STATUS_PARAM );
 int floatx80_is_quiet_nan( floatx80 );
 int floatx80_is_signaling_nan( floatx80 );
+floatx80 floatx80_maybe_silence_nan( floatx80 );
 floatx80 floatx80_scalbn( floatx80, int STATUS_PARAM );
 
 INLINE floatx80 floatx80_abs(floatx80 a)
@@ -505,6 +506,7 @@ int float128_compare( float128, float128 STATUS_PARAM );
 int float128_compare_quiet( float128, float128 STATUS_PARAM );
 int float128_is_quiet_nan( float128 );
 int float128_is_signaling_nan( float128 );
+float128 float128_maybe_silence_nan( float128 );
 float128 float128_scalbn( float128, int STATUS_PARAM );
 
 INLINE float128 float128_abs(float128 a)
commit 93ae1c6fea6433bca732c907d7c3ee9be4f8a2ab
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Thu Jan 6 15:38:19 2011 +0100

    softfloat: fix float{32,64}_maybe_silence_nan() for MIPS
    
    On targets that define sNaN with the sNaN bit as one, simply clearing
    this bit may correspond to an infinite value.
    
    Convert it to a default NaN if SNAN_BIT_IS_ONE, as it corresponds to
    the MIPS implementation, the only emulated CPU with SNAN_BIT_IS_ONE.
    When other CPU of this type are added, this might be updated to include
    more cases.
    
    Acked-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h
index 33930f9..bc6f0c1 100644
--- a/fpu/softfloat-specialize.h
+++ b/fpu/softfloat-specialize.h
@@ -107,13 +107,17 @@ int float32_is_signaling_nan( float32 a_ )
 float32 float32_maybe_silence_nan( float32 a_ )
 {
     if (float32_is_signaling_nan(a_)) {
-        uint32_t a = float32_val(a_);
 #if SNAN_BIT_IS_ONE
-        a &= ~(1 << 22);
+#  if defined(TARGET_MIPS)
+        return float32_default_nan;
+#  else
+#    error Rules for silencing a signaling NaN are target-specific
+#  endif
 #else
+        bits32 a = float32_val(a_);
         a |= (1 << 22);
-#endif
         return make_float32(a);
+#endif
     }
     return a_;
 }
@@ -322,13 +326,17 @@ int float64_is_signaling_nan( float64 a_ )
 float64 float64_maybe_silence_nan( float64 a_ )
 {
     if (float64_is_signaling_nan(a_)) {
-        bits64 a = float64_val(a_);
 #if SNAN_BIT_IS_ONE
-        a &= ~LIT64( 0x0008000000000000 );
+#  if defined(TARGET_MIPS)
+        return float64_default_nan;
+#  else
+#    error Rules for silencing a signaling NaN are target-specific
+#  endif
 #else
+        bits64 a = float64_val(a_);
         a |= LIT64( 0x0008000000000000 );
-#endif
         return make_float64(a);
+#endif
     }
     return a_;
 }
commit d735d695e7b547272412f63433e023496c4d36ed
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Thu Jan 6 15:38:19 2011 +0100

    softfloat: rename *IsNaN variables to *IsQuietNaN
    
    Similarly to what has been done in commit
    185698715dfb18c82ad2a5dbc169908602d43e81 rename the misnamed *IsNaN
    variables into *IsQuietNaN.
    
    Reviewed-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h
index 5da3a85..33930f9 100644
--- a/fpu/softfloat-specialize.h
+++ b/fpu/softfloat-specialize.h
@@ -227,15 +227,16 @@ static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
 
 static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM)
 {
-    flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN, aIsLargerSignificand;
+    flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN;
+    flag aIsLargerSignificand;
     bits32 av, bv, res;
 
     if ( STATUS(default_nan_mode) )
         return float32_default_nan;
 
-    aIsNaN = float32_is_quiet_nan( a );
+    aIsQuietNaN = float32_is_quiet_nan( a );
     aIsSignalingNaN = float32_is_signaling_nan( a );
-    bIsNaN = float32_is_quiet_nan( b );
+    bIsQuietNaN = float32_is_quiet_nan( b );
     bIsSignalingNaN = float32_is_signaling_nan( b );
     av = float32_val(a);
     bv = float32_val(b);
@@ -256,7 +257,7 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM)
         aIsLargerSignificand = (av < bv) ? 1 : 0;
     }
 
-    if (pickNaN(aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN,
+    if (pickNaN(aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN,
                 aIsLargerSignificand)) {
         res = bv;
     } else {
@@ -375,15 +376,16 @@ static float64 commonNaNToFloat64( commonNaNT a )
 
 static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM)
 {
-    flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN, aIsLargerSignificand;
+    flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN;
+    flag aIsLargerSignificand;
     bits64 av, bv, res;
 
     if ( STATUS(default_nan_mode) )
         return float64_default_nan;
 
-    aIsNaN = float64_is_quiet_nan( a );
+    aIsQuietNaN = float64_is_quiet_nan( a );
     aIsSignalingNaN = float64_is_signaling_nan( a );
-    bIsNaN = float64_is_quiet_nan( b );
+    bIsQuietNaN = float64_is_quiet_nan( b );
     bIsSignalingNaN = float64_is_signaling_nan( b );
     av = float64_val(a);
     bv = float64_val(b);
@@ -404,7 +406,7 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM)
         aIsLargerSignificand = (av < bv) ? 1 : 0;
     }
 
-    if (pickNaN(aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN,
+    if (pickNaN(aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN,
                 aIsLargerSignificand)) {
         res = bv;
     } else {
@@ -511,7 +513,8 @@ static floatx80 commonNaNToFloatx80( commonNaNT a )
 
 static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM)
 {
-    flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN, aIsLargerSignificand;
+    flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN;
+    flag aIsLargerSignificand;
 
     if ( STATUS(default_nan_mode) ) {
         a.low = floatx80_default_nan_low;
@@ -519,9 +522,9 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM)
         return a;
     }
 
-    aIsNaN = floatx80_is_quiet_nan( a );
+    aIsQuietNaN = floatx80_is_quiet_nan( a );
     aIsSignalingNaN = floatx80_is_signaling_nan( a );
-    bIsNaN = floatx80_is_quiet_nan( b );
+    bIsQuietNaN = floatx80_is_quiet_nan( b );
     bIsSignalingNaN = floatx80_is_signaling_nan( b );
 #if SNAN_BIT_IS_ONE
     a.low &= ~LIT64( 0xC000000000000000 );
@@ -540,7 +543,7 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM)
         aIsLargerSignificand = (a.high < b.high) ? 1 : 0;
     }
 
-    if (pickNaN(aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN,
+    if (pickNaN(aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN,
                 aIsLargerSignificand)) {
         return b;
     } else {
@@ -638,7 +641,8 @@ static float128 commonNaNToFloat128( commonNaNT a )
 
 static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM)
 {
-    flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN, aIsLargerSignificand;
+    flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN;
+    flag aIsLargerSignificand;
 
     if ( STATUS(default_nan_mode) ) {
         a.low = float128_default_nan_low;
@@ -646,9 +650,9 @@ static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM)
         return a;
     }
 
-    aIsNaN = float128_is_quiet_nan( a );
+    aIsQuietNaN = float128_is_quiet_nan( a );
     aIsSignalingNaN = float128_is_signaling_nan( a );
-    bIsNaN = float128_is_quiet_nan( b );
+    bIsQuietNaN = float128_is_quiet_nan( b );
     bIsSignalingNaN = float128_is_signaling_nan( b );
 #if SNAN_BIT_IS_ONE
     a.high &= ~LIT64( 0x0000800000000000 );
@@ -667,7 +671,7 @@ static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM)
         aIsLargerSignificand = (a.high < b.high) ? 1 : 0;
     }
 
-    if (pickNaN(aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN,
+    if (pickNaN(aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN,
                 aIsLargerSignificand)) {
         return b;
     } else {
commit 34d23861989a2901fa76385940817cc94072c721
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Thu Jan 6 15:38:19 2011 +0100

    softfloat: remove HPPA specific code
    
    We don't have any HPPA target, so let's remove HPPA specific code. It
    can be re-added when someone adds an HPPA target.
    
    This has been blessed by Stuart Brady <sdb at zubnet.me.uk>, author of the
    target-hppa fork.
    
    Reviewed-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h
index f43f2d0..5da3a85 100644
--- a/fpu/softfloat-specialize.h
+++ b/fpu/softfloat-specialize.h
@@ -30,7 +30,7 @@ these four paragraphs for those parts of this code that are retained.
 
 =============================================================================*/
 
-#if defined(TARGET_MIPS) || defined(TARGET_HPPA)
+#if defined(TARGET_MIPS)
 #define SNAN_BIT_IS_ONE		1
 #else
 #define SNAN_BIT_IS_ONE		0
@@ -63,8 +63,6 @@ typedef struct {
 #define float32_default_nan make_float32(0x7FFFFFFF)
 #elif defined(TARGET_POWERPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA)
 #define float32_default_nan make_float32(0x7FC00000)
-#elif defined(TARGET_HPPA)
-#define float32_default_nan make_float32(0x7FA00000)
 #elif SNAN_BIT_IS_ONE
 #define float32_default_nan make_float32(0x7FBFFFFF)
 #else
@@ -275,8 +273,6 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM)
 #define float64_default_nan make_float64(LIT64( 0x7FFFFFFFFFFFFFFF ))
 #elif defined(TARGET_POWERPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA)
 #define float64_default_nan make_float64(LIT64( 0x7FF8000000000000 ))
-#elif defined(TARGET_HPPA)
-#define float64_default_nan make_float64(LIT64( 0x7FF4000000000000 ))
 #elif SNAN_BIT_IS_ONE
 #define float64_default_nan make_float64(LIT64( 0x7FF7FFFFFFFFFFFF ))
 #else
commit 82b323cd296a079caf818c8c97eab3b4673cad29
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Thu Jan 6 15:38:18 2011 +0100

    target-ppc: use float32_is_any_nan()
    
    Use the new function float32_is_any_nan() instead of
    float32_is_quiet_nan() || float32_is_signaling_nan().
    
    Acked-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index c69ffc9..279f345 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -1902,7 +1902,7 @@ target_ulong helper_dlmzb (target_ulong high, target_ulong low, uint32_t update_
 /* If X is a NaN, store the corresponding QNaN into RESULT.  Otherwise,
  * execute the following block.  */
 #define DO_HANDLE_NAN(result, x)                \
-    if (float32_is_quiet_nan(x) || float32_is_signaling_nan(x)) {     \
+    if (float32_is_any_nan(x)) {                                \
         CPU_FloatU __f;                                         \
         __f.f = x;                                              \
         __f.l = __f.l | (1 << 22);  /* Set QNaN bit. */         \
@@ -2247,8 +2247,7 @@ void helper_vcmpbfp_dot (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
         float_status s = env->vec_status;                               \
         set_float_rounding_mode(float_round_to_zero, &s);               \
         for (i = 0; i < ARRAY_SIZE(r->f); i++) {                        \
-            if (float32_is_quiet_nan(b->f[i]) ||                              \
-                float32_is_signaling_nan(b->f[i])) {                    \
+            if (float32_is_any_nan(b->f[i])) {                          \
                 r->element[i] = 0;                                      \
             } else {                                                    \
                 float64 t = float32_to_float64(b->f[i], &s);            \
commit 3eb28bbd472c0d4e3182421c4af7043afa059903
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Thu Jan 6 15:38:18 2011 +0100

    target-ppc: fix default qNaN
    
    On PPC the default qNaN doesn't have the sign bit set.
    
    Acked-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index 31520ab..c69ffc9 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -643,7 +643,7 @@ static inline uint64_t fload_invalid_op_excp(int op)
         env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
         if (ve == 0) {
             /* Set the result to quiet NaN */
-            ret = 0xFFF8000000000000ULL;
+            ret = 0x7FF8000000000000ULL;
             env->fpscr &= ~(0xF << FPSCR_FPCC);
             env->fpscr |= 0x11 << FPSCR_FPCC;
         }
@@ -654,7 +654,7 @@ static inline uint64_t fload_invalid_op_excp(int op)
         env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
         if (ve == 0) {
             /* Set the result to quiet NaN */
-            ret = 0xFFF8000000000000ULL;
+            ret = 0x7FF8000000000000ULL;
             env->fpscr &= ~(0xF << FPSCR_FPCC);
             env->fpscr |= 0x11 << FPSCR_FPCC;
         }
commit dd94ad96e51457d8d9562a73659734b559d2f4b1
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Thu Jan 6 15:38:18 2011 +0100

    target-ppc: remove PRECISE_EMULATION define
    
    The PRECISE_EMULATION is "hardcoded" to one in target-ppc/exec.h and not
    something easily tunable. Remove it and non-precise emulation code as
    it doesn't make a noticeable difference in speed. People wanting speed
    improvement should use softfloat-native instead.
    
    Acked-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/target-ppc/exec.h b/target-ppc/exec.h
index 44cc5e9..4688ef5 100644
--- a/target-ppc/exec.h
+++ b/target-ppc/exec.h
@@ -26,9 +26,6 @@
 #include "cpu.h"
 #include "exec-all.h"
 
-/* Precise emulation is needed to correctly emulate exception flags */
-#define USE_PRECISE_EMULATION 1
-
 register struct CPUPPCState *env asm(AREG0);
 
 #if !defined(CONFIG_USER_ONLY)
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index 5ded1c1..31520ab 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -974,7 +974,7 @@ uint64_t helper_fadd (uint64_t arg1, uint64_t arg2)
 
     farg1.ll = arg1;
     farg2.ll = arg2;
-#if USE_PRECISE_EMULATION
+
     if (unlikely(float64_is_signaling_nan(farg1.d) ||
                  float64_is_signaling_nan(farg2.d))) {
         /* sNaN addition */
@@ -986,9 +986,7 @@ uint64_t helper_fadd (uint64_t arg1, uint64_t arg2)
     } else {
         farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
     }
-#else
-    farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
-#endif
+
     return farg1.ll;
 }
 
@@ -999,8 +997,7 @@ uint64_t helper_fsub (uint64_t arg1, uint64_t arg2)
 
     farg1.ll = arg1;
     farg2.ll = arg2;
-#if USE_PRECISE_EMULATION
-{
+
     if (unlikely(float64_is_signaling_nan(farg1.d) ||
                  float64_is_signaling_nan(farg2.d))) {
         /* sNaN subtraction */
@@ -1012,10 +1009,7 @@ uint64_t helper_fsub (uint64_t arg1, uint64_t arg2)
     } else {
         farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
     }
-}
-#else
-    farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
-#endif
+
     return farg1.ll;
 }
 
@@ -1026,7 +1020,7 @@ uint64_t helper_fmul (uint64_t arg1, uint64_t arg2)
 
     farg1.ll = arg1;
     farg2.ll = arg2;
-#if USE_PRECISE_EMULATION
+
     if (unlikely(float64_is_signaling_nan(farg1.d) ||
                  float64_is_signaling_nan(farg2.d))) {
         /* sNaN multiplication */
@@ -1038,9 +1032,7 @@ uint64_t helper_fmul (uint64_t arg1, uint64_t arg2)
     } else {
         farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
     }
-#else
-    farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
-#endif
+
     return farg1.ll;
 }
 
@@ -1051,7 +1043,7 @@ uint64_t helper_fdiv (uint64_t arg1, uint64_t arg2)
 
     farg1.ll = arg1;
     farg2.ll = arg2;
-#if USE_PRECISE_EMULATION
+
     if (unlikely(float64_is_signaling_nan(farg1.d) ||
                  float64_is_signaling_nan(farg2.d))) {
         /* sNaN division */
@@ -1065,9 +1057,7 @@ uint64_t helper_fdiv (uint64_t arg1, uint64_t arg2)
     } else {
         farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
     }
-#else
-    farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
-#endif
+
     return farg1.ll;
 }
 
@@ -1116,12 +1106,10 @@ uint64_t helper_fctiw (uint64_t arg)
         farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
     } else {
         farg.ll = float64_to_int32(farg.d, &env->fp_status);
-#if USE_PRECISE_EMULATION
         /* XXX: higher bits are not supposed to be significant.
          *     to make tests easier, return the same as a real PowerPC 750
          */
         farg.ll |= 0xFFF80000ULL << 32;
-#endif
     }
     return farg.ll;
 }
@@ -1140,12 +1128,10 @@ uint64_t helper_fctiwz (uint64_t arg)
         farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
     } else {
         farg.ll = float64_to_int32_round_to_zero(farg.d, &env->fp_status);
-#if USE_PRECISE_EMULATION
         /* XXX: higher bits are not supposed to be significant.
          *     to make tests easier, return the same as a real PowerPC 750
          */
         farg.ll |= 0xFFF80000ULL << 32;
-#endif
     }
     return farg.ll;
 }
@@ -1245,7 +1231,7 @@ uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
     farg1.ll = arg1;
     farg2.ll = arg2;
     farg3.ll = arg3;
-#if USE_PRECISE_EMULATION
+
     if (unlikely(float64_is_signaling_nan(farg1.d) ||
                  float64_is_signaling_nan(farg2.d) ||
                  float64_is_signaling_nan(farg3.d))) {
@@ -1277,10 +1263,7 @@ uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
         farg1.d = (farg1.d * farg2.d) + farg3.d;
 #endif
     }
-#else
-    farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
-    farg1.d = float64_add(farg1.d, farg3.d, &env->fp_status);
-#endif
+
     return farg1.ll;
 }
 
@@ -1292,7 +1275,7 @@ uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
     farg1.ll = arg1;
     farg2.ll = arg2;
     farg3.ll = arg3;
-#if USE_PRECISE_EMULATION
+
     if (unlikely(float64_is_signaling_nan(farg1.d) ||
                  float64_is_signaling_nan(farg2.d) ||
                  float64_is_signaling_nan(farg3.d))) {
@@ -1324,10 +1307,6 @@ uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
         farg1.d = (farg1.d * farg2.d) - farg3.d;
 #endif
     }
-#else
-    farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
-    farg1.d = float64_sub(farg1.d, farg3.d, &env->fp_status);
-#endif
     return farg1.ll;
 }
 
@@ -1350,7 +1329,6 @@ uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
         /* Multiplication of zero by infinity */
         farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
     } else {
-#if USE_PRECISE_EMULATION
 #ifdef FLOAT128
         /* This is the way the PowerPC specification defines it */
         float128 ft0_128, ft1_128;
@@ -1371,10 +1349,6 @@ uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
         /* This is OK on x86 hosts */
         farg1.d = (farg1.d * farg2.d) + farg3.d;
 #endif
-#else
-        farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
-        farg1.d = float64_add(farg1.d, farg3.d, &env->fp_status);
-#endif
         if (likely(!float64_is_quiet_nan(farg1.d)))
             farg1.d = float64_chs(farg1.d);
     }
@@ -1400,7 +1374,6 @@ uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
         /* Multiplication of zero by infinity */
         farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
     } else {
-#if USE_PRECISE_EMULATION
 #ifdef FLOAT128
         /* This is the way the PowerPC specification defines it */
         float128 ft0_128, ft1_128;
@@ -1421,10 +1394,6 @@ uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
         /* This is OK on x86 hosts */
         farg1.d = (farg1.d * farg2.d) - farg3.d;
 #endif
-#else
-        farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
-        farg1.d = float64_sub(farg1.d, farg3.d, &env->fp_status);
-#endif
         if (likely(!float64_is_quiet_nan(farg1.d)))
             farg1.d = float64_chs(farg1.d);
     }
@@ -1438,7 +1407,6 @@ uint64_t helper_frsp (uint64_t arg)
     float32 f32;
     farg.ll = arg;
 
-#if USE_PRECISE_EMULATION
     if (unlikely(float64_is_signaling_nan(farg.d))) {
         /* sNaN square root */
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
@@ -1446,10 +1414,6 @@ uint64_t helper_frsp (uint64_t arg)
        f32 = float64_to_float32(farg.d, &env->fp_status);
        farg.d = float32_to_float64(f32, &env->fp_status);
     }
-#else
-    f32 = float64_to_float32(farg.d, &env->fp_status);
-    farg.d = float32_to_float64(f32, &env->fp_status);
-#endif
     return farg.ll;
 }
 
commit 23979dc5411befabe9049e37075b2b6320debc4e
Author: Edgar E. Iglesias <edgar.iglesias at petalogix.com>
Date:   Wed Jan 5 02:21:19 2011 +0100

    microblaze: Use more TB chaining
    
    For some workloads with tight loops this ~doubles the emulation
    speed.
    
    Signed-off-by: Edgar E. Iglesias <edgar.iglesias at petalogix.com>

diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c
index 1ada15e..c018c99 100644
--- a/target-microblaze/translate.c
+++ b/target-microblaze/translate.c
@@ -752,9 +752,8 @@ static void dec_bit(DisasContext *dc)
 static inline void sync_jmpstate(DisasContext *dc)
 {
     if (dc->jmp == JMP_DIRECT) {
-            dc->jmp = JMP_INDIRECT;
-            tcg_gen_movi_tl(env_btaken, 1);
-            tcg_gen_movi_tl(env_btarget, dc->jmp_pc);
+        dc->jmp = JMP_INDIRECT;
+        tcg_gen_movi_tl(env_btarget, dc->jmp_pc);
     }
 }
 
@@ -976,11 +975,13 @@ static void dec_bcc(DisasContext *dc)
         int32_t offset = (int32_t)((int16_t)dc->imm); /* sign-extend.  */
 
         tcg_gen_movi_tl(env_btarget, dc->pc + offset);
+        dc->jmp = JMP_DIRECT;
+        dc->jmp_pc = dc->pc + offset;
     } else {
+        dc->jmp = JMP_INDIRECT;
         tcg_gen_movi_tl(env_btarget, dc->pc);
         tcg_gen_add_tl(env_btarget, env_btarget, *(dec_alu_op_b(dc)));
     }
-    dc->jmp = JMP_INDIRECT;
     eval_cc(dc, cc, env_btaken, cpu_R[dc->ra], tcg_const_tl(0));
 }
 
@@ -1028,6 +1029,7 @@ static void dec_br(DisasContext *dc)
         if (dec_alu_op_b_is_small_imm(dc)) {
             dc->jmp = JMP_DIRECT;
             dc->jmp_pc = dc->pc + (int32_t)((int16_t)dc->imm);
+            tcg_gen_movi_tl(env_btaken, 1);
         } else {
             tcg_gen_movi_tl(env_btaken, 1);
             tcg_gen_movi_tl(env_btarget, dc->pc);
@@ -1130,6 +1132,7 @@ static void dec_rts(DisasContext *dc)
     } else
         LOG_DIS("rts ir=%x\n", dc->ir);
 
+    dc->jmp = JMP_INDIRECT;
     tcg_gen_movi_tl(env_btaken, 1);
     tcg_gen_add_tl(env_btarget, cpu_R[dc->ra], *(dec_alu_op_b(dc)));
 }
@@ -1370,6 +1373,9 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
     dc->is_jmp = DISAS_NEXT;
     dc->jmp = 0;
     dc->delayed_branch = !!(dc->tb_flags & D_FLAG);
+    if (dc->delayed_branch) {
+        dc->jmp = JMP_INDIRECT;
+    }
     dc->pc = pc_start;
     dc->singlestep_enabled = env->singlestep_enabled;
     dc->cpustate_changed = 0;
@@ -1441,9 +1447,21 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
                 /* Clear the delay slot flag.  */
                 dc->tb_flags &= ~D_FLAG;
                 /* If it is a direct jump, try direct chaining.  */
-                if (dc->jmp != JMP_DIRECT) {
+                if (dc->jmp == JMP_INDIRECT) {
                     eval_cond_jmp(dc, env_btarget, tcg_const_tl(dc->pc));
                     dc->is_jmp = DISAS_JUMP;
+                } else if (dc->jmp == JMP_DIRECT) {
+                    int l1;
+
+                    t_sync_flags(dc);
+                    l1 = gen_new_label();
+                    /* Conditional jmp.  */
+                    tcg_gen_brcondi_tl(TCG_COND_NE, env_btaken, 0, l1);
+                    gen_goto_tb(dc, 1, dc->pc);
+                    gen_set_label(l1);
+                    gen_goto_tb(dc, 0, dc->jmp_pc);
+
+                    dc->is_jmp = DISAS_TB_JUMP;
                 }
                 break;
             }
commit 92d675d1c1f23f3617e24b63c825074a1d1da44b
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Tue Jan 4 21:58:24 2011 +0100

    cirrus_vga: fix division by 0 for color expansion rop
    
    Commit d85d0d3883f5a567fa2969a0396e42e0a662b3fa introduces a regression
    with Windows ME that leads to a division by 0 and a crash.
    
    It uses the color expansion rop with the source pitch set to 0. This is
    something allowed, as the manual explicitely says "When the source of
    color-expand data is display memory, the source pitch is ignored.".
    
    This patch fixes this regression by computing sx, sy and others
    variables only if they are going to be used later, that is for a plain
    copy ROP. It basically consists in moving code.
    
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index 4f5040c..199136c 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -675,43 +675,44 @@ static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
 {
     int sx, sy;
     int dx, dy;
-    int width, height;
     int depth;
     int notify = 0;
 
-    depth = s->vga.get_bpp(&s->vga) / 8;
-    s->vga.get_resolution(&s->vga, &width, &height);
-
-    /* extra x, y */
-    sx = (src % ABS(s->cirrus_blt_srcpitch)) / depth;
-    sy = (src / ABS(s->cirrus_blt_srcpitch));
-    dx = (dst % ABS(s->cirrus_blt_dstpitch)) / depth;
-    dy = (dst / ABS(s->cirrus_blt_dstpitch));
-
-    /* normalize width */
-    w /= depth;
-
-    /* if we're doing a backward copy, we have to adjust
-       our x/y to be the upper left corner (instead of the lower
-       right corner) */
-    if (s->cirrus_blt_dstpitch < 0) {
-	sx -= (s->cirrus_blt_width / depth) - 1;
-	dx -= (s->cirrus_blt_width / depth) - 1;
-	sy -= s->cirrus_blt_height - 1;
-	dy -= s->cirrus_blt_height - 1;
-    }
+    /* make sure to only copy if it's a plain copy ROP */
+    if (*s->cirrus_rop == cirrus_bitblt_rop_fwd_src ||
+        *s->cirrus_rop == cirrus_bitblt_rop_bkwd_src) {
 
-    /* are we in the visible portion of memory? */
-    if (sx >= 0 && sy >= 0 && dx >= 0 && dy >= 0 &&
-	(sx + w) <= width && (sy + h) <= height &&
-	(dx + w) <= width && (dy + h) <= height) {
-	notify = 1;
-    }
+        int width, height;
+
+        depth = s->vga.get_bpp(&s->vga) / 8;
+        s->vga.get_resolution(&s->vga, &width, &height);
+
+        /* extra x, y */
+        sx = (src % ABS(s->cirrus_blt_srcpitch)) / depth;
+        sy = (src / ABS(s->cirrus_blt_srcpitch));
+        dx = (dst % ABS(s->cirrus_blt_dstpitch)) / depth;
+        dy = (dst / ABS(s->cirrus_blt_dstpitch));
 
-    /* make to sure only copy if it's a plain copy ROP */
-    if (*s->cirrus_rop != cirrus_bitblt_rop_fwd_src &&
-	*s->cirrus_rop != cirrus_bitblt_rop_bkwd_src)
-	notify = 0;
+        /* normalize width */
+        w /= depth;
+
+        /* if we're doing a backward copy, we have to adjust
+           our x/y to be the upper left corner (instead of the lower
+           right corner) */
+        if (s->cirrus_blt_dstpitch < 0) {
+            sx -= (s->cirrus_blt_width / depth) - 1;
+            dx -= (s->cirrus_blt_width / depth) - 1;
+            sy -= s->cirrus_blt_height - 1;
+            dy -= s->cirrus_blt_height - 1;
+        }
+
+        /* are we in the visible portion of memory? */
+        if (sx >= 0 && sy >= 0 && dx >= 0 && dy >= 0 &&
+            (sx + w) <= width && (sy + h) <= height &&
+            (dx + w) <= width && (dy + h) <= height) {
+            notify = 1;
+        }
+    }
 
     /* we have to flush all pending changes so that the copy
        is generated at the appropriate moment in time */
commit 9ae19b657ee20f4d03bdca8dbf367b932801ac93
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Tue Jan 4 21:58:24 2011 +0100

    Fix curses on big endian hosts
    
    On big endian hosts, the curses interface is unusable: the emulated
    graphic card only displays garbage, while the monitor interface displays
    nothing (or rather only spaces).
    
    The curses interface is waiting for data in native endianness, so
    console_write_ch() should not do any conversion. The conversion should
    be done when reading the video buffer in hw/vga.c. I supposed this
    buffer is in little endian mode, though it's not impossible that the
    data is actually in guest endianness. I currently have no big endian
    guest to way (they all switch to graphic mode immediately).
    
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/console.h b/console.h
index b2fc908..3157330 100644
--- a/console.h
+++ b/console.h
@@ -329,7 +329,7 @@ static inline void console_write_ch(console_ch_t *dest, uint32_t ch)
 {
     if (!(ch & 0xff))
         ch |= ' ';
-    cpu_to_le32wu((uint32_t *) dest, ch);
+    *dest = ch;
 }
 
 typedef void (*vga_hw_update_ptr)(void *);
diff --git a/hw/vga.c b/hw/vga.c
index c632fd7..e2151a2 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -2073,14 +2073,14 @@ static void vga_update_text(void *opaque, console_ch_t *chardata)
 
         if (full_update) {
             for (i = 0; i < size; src ++, dst ++, i ++)
-                console_write_ch(dst, VMEM2CHTYPE(*src));
+                console_write_ch(dst, VMEM2CHTYPE(le32_to_cpu(*src)));
 
             dpy_update(s->ds, 0, 0, width, height);
         } else {
             c_max = 0;
 
             for (i = 0; i < size; src ++, dst ++, i ++) {
-                console_write_ch(&val, VMEM2CHTYPE(*src));
+                console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
                 if (*dst != val) {
                     *dst = val;
                     c_max = i;
@@ -2089,7 +2089,7 @@ static void vga_update_text(void *opaque, console_ch_t *chardata)
             }
             c_min = i;
             for (; i < size; src ++, dst ++, i ++) {
-                console_write_ch(&val, VMEM2CHTYPE(*src));
+                console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
                 if (*dst != val) {
                     *dst = val;
                     c_max = i;
commit 8a7d0890acd03f45f1d86e12449938891ae18ed9
Author: Michael Walle <michael at walle.cc>
Date:   Tue Jan 4 01:48:55 2011 +0100

    noaudio: correctly account acquired samples
    
    This will fix the return value of the function which otherwise returns too
    many samples because sw->total_hw_samples_acquired isn't correctly
    accounted.
    
    Signed-off-by: Michael Walle <michael at walle.cc>
    Signed-off-by: malc <av1474 at comtv.ru>

diff --git a/audio/noaudio.c b/audio/noaudio.c
index 8015858..0304094 100644
--- a/audio/noaudio.c
+++ b/audio/noaudio.c
@@ -117,9 +117,12 @@ static int no_run_in (HWVoiceIn *hw)
 
 static int no_read (SWVoiceIn *sw, void *buf, int size)
 {
+    /* use custom code here instead of audio_pcm_sw_read() to avoid
+     * useless resampling/mixing */
     int samples = size >> sw->info.shift;
     int total = sw->hw->total_samples_captured - sw->total_hw_samples_acquired;
     int to_clear = audio_MIN (samples, total);
+    sw->total_hw_samples_acquired += total;
     audio_pcm_info_clear_buf (&sw->info, buf, to_clear);
     return to_clear << sw->info.shift;
 }
commit 011da610ba6416df54feed46bcde1955211a2149
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Thu Dec 16 11:51:18 2010 +0000

    target-arm: Implement correct NaN propagation rules
    
    Implement the correct NaN propagation rules for ARM targets by
    providing an appropriate pickNaN function.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h
index 8dcf469..f43f2d0 100644
--- a/fpu/softfloat-specialize.h
+++ b/fpu/softfloat-specialize.h
@@ -168,6 +168,28 @@ static float32 commonNaNToFloat32( commonNaNT a )
 | tie-break rule.
 *----------------------------------------------------------------------------*/
 
+#if defined(TARGET_ARM)
+static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
+                    flag aIsLargerSignificand)
+{
+    /* ARM mandated NaN propagation rules: take the first of:
+     *  1. A if it is signaling
+     *  2. B if it is signaling
+     *  3. A (quiet)
+     *  4. B (quiet)
+     * A signaling NaN is always quietened before returning it.
+     */
+    if (aIsSNaN) {
+        return 0;
+    } else if (bIsSNaN) {
+        return 1;
+    } else if (aIsQNaN) {
+        return 0;
+    } else {
+        return 1;
+    }
+}
+#else
 static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
                     flag aIsLargerSignificand)
 {
@@ -197,6 +219,7 @@ static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
         return 1;
     }
 }
+#endif
 
 /*----------------------------------------------------------------------------
 | Takes two single-precision floating-point values `a' and `b', one of which
commit 354f211b1a49a7387929e22d6e63849fcba48f8a
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Thu Dec 16 11:51:17 2010 +0000

    softfloat: abstract out target-specific NaN propagation rules
    
    IEEE754 doesn't specify precisely what NaN should be returned as
    the result of an operation on two input NaNs. This is therefore
    target-specific. Abstract out the code in propagateFloat*NaN()
    which was implementing the x87 propagation rules, so that it
    can be easily replaced on a per-target basis.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h
index f382f7a..8dcf469 100644
--- a/fpu/softfloat-specialize.h
+++ b/fpu/softfloat-specialize.h
@@ -153,6 +153,52 @@ static float32 commonNaNToFloat32( commonNaNT a )
 }
 
 /*----------------------------------------------------------------------------
+| Select which NaN to propagate for a two-input operation.
+| IEEE754 doesn't specify all the details of this, so the
+| algorithm is target-specific.
+| The routine is passed various bits of information about the
+| two NaNs and should return 0 to select NaN a and 1 for NaN b.
+| Note that signalling NaNs are always squashed to quiet NaNs
+| by the caller, by flipping the SNaN bit before returning them.
+|
+| aIsLargerSignificand is only valid if both a and b are NaNs
+| of some kind, and is true if a has the larger significand,
+| or if both a and b have the same significand but a is
+| positive but b is negative. It is only needed for the x87
+| tie-break rule.
+*----------------------------------------------------------------------------*/
+
+static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
+                    flag aIsLargerSignificand)
+{
+    /* This implements x87 NaN propagation rules:
+     * SNaN + QNaN => return the QNaN
+     * two SNaNs => return the one with the larger significand, silenced
+     * two QNaNs => return the one with the larger significand
+     * SNaN and a non-NaN => return the SNaN, silenced
+     * QNaN and a non-NaN => return the QNaN
+     *
+     * If we get down to comparing significands and they are the same,
+     * return the NaN with the positive sign bit (if any).
+     */
+    if (aIsSNaN) {
+        if (bIsSNaN) {
+            return aIsLargerSignificand ? 0 : 1;
+        }
+        return bIsQNaN ? 1 : 0;
+    }
+    else if (aIsQNaN) {
+        if (bIsSNaN || !bIsQNaN)
+            return 0;
+        else {
+            return aIsLargerSignificand ? 0 : 1;
+        }
+    } else {
+        return 1;
+    }
+}
+
+/*----------------------------------------------------------------------------
 | Takes two single-precision floating-point values `a' and `b', one of which
 | is a NaN, and returns the appropriate NaN result.  If either `a' or `b' is a
 | signaling NaN, the invalid exception is raised.
@@ -160,7 +206,7 @@ static float32 commonNaNToFloat32( commonNaNT a )
 
 static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM)
 {
-    flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
+    flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN, aIsLargerSignificand;
     bits32 av, bv, res;
 
     if ( STATUS(default_nan_mode) )
@@ -180,26 +226,22 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM)
     bv |= 0x00400000;
 #endif
     if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
-    if ( aIsSignalingNaN ) {
-        if ( bIsSignalingNaN ) goto returnLargerSignificand;
-        res = bIsNaN ? bv : av;
-    }
-    else if ( aIsNaN ) {
-        if ( bIsSignalingNaN || ! bIsNaN )
-            res = av;
-        else {
- returnLargerSignificand:
-            if ( (bits32) ( av<<1 ) < (bits32) ( bv<<1 ) )
-                res = bv;
-            else if ( (bits32) ( bv<<1 ) < (bits32) ( av<<1 ) )
-                res = av;
-            else
-                res = ( av < bv ) ? av : bv;
-        }
+
+    if ((bits32)(av<<1) < (bits32)(bv<<1)) {
+        aIsLargerSignificand = 0;
+    } else if ((bits32)(bv<<1) < (bits32)(av<<1)) {
+        aIsLargerSignificand = 1;
+    } else {
+        aIsLargerSignificand = (av < bv) ? 1 : 0;
     }
-    else {
+
+    if (pickNaN(aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN,
+                aIsLargerSignificand)) {
         res = bv;
+    } else {
+        res = av;
     }
+
     return make_float32(res);
 }
 
@@ -314,7 +356,7 @@ static float64 commonNaNToFloat64( commonNaNT a )
 
 static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM)
 {
-    flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
+    flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN, aIsLargerSignificand;
     bits64 av, bv, res;
 
     if ( STATUS(default_nan_mode) )
@@ -334,26 +376,22 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM)
     bv |= LIT64( 0x0008000000000000 );
 #endif
     if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
-    if ( aIsSignalingNaN ) {
-        if ( bIsSignalingNaN ) goto returnLargerSignificand;
-        res = bIsNaN ? bv : av;
-    }
-    else if ( aIsNaN ) {
-        if ( bIsSignalingNaN || ! bIsNaN )
-            res = av;
-        else {
- returnLargerSignificand:
-            if ( (bits64) ( av<<1 ) < (bits64) ( bv<<1 ) )
-                res = bv;
-            else if ( (bits64) ( bv<<1 ) < (bits64) ( av<<1 ) )
-                res = av;
-            else
-                res = ( av < bv ) ? av : bv;
-        }
+
+    if ((bits64)(av<<1) < (bits64)(bv<<1)) {
+        aIsLargerSignificand = 0;
+    } else if ((bits64)(bv<<1) < (bits64)(av<<1)) {
+        aIsLargerSignificand = 1;
+    } else {
+        aIsLargerSignificand = (av < bv) ? 1 : 0;
     }
-    else {
+
+    if (pickNaN(aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN,
+                aIsLargerSignificand)) {
         res = bv;
+    } else {
+        res = av;
     }
+
     return make_float64(res);
 }
 
@@ -454,7 +492,7 @@ static floatx80 commonNaNToFloatx80( commonNaNT a )
 
 static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM)
 {
-    flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
+    flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN, aIsLargerSignificand;
 
     if ( STATUS(default_nan_mode) ) {
         a.low = floatx80_default_nan_low;
@@ -474,19 +512,20 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM)
     b.low |= LIT64( 0xC000000000000000 );
 #endif
     if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
-    if ( aIsSignalingNaN ) {
-        if ( bIsSignalingNaN ) goto returnLargerSignificand;
-        return bIsNaN ? b : a;
-    }
-    else if ( aIsNaN ) {
-        if ( bIsSignalingNaN || ! bIsNaN ) return a;
- returnLargerSignificand:
-        if ( a.low < b.low ) return b;
-        if ( b.low < a.low ) return a;
-        return ( a.high < b.high ) ? a : b;
+
+    if (a.low < b.low) {
+        aIsLargerSignificand = 0;
+    } else if (b.low < a.low) {
+        aIsLargerSignificand = 1;
+    } else {
+        aIsLargerSignificand = (a.high < b.high) ? 1 : 0;
     }
-    else {
+
+    if (pickNaN(aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN,
+                aIsLargerSignificand)) {
         return b;
+    } else {
+        return a;
     }
 }
 
@@ -580,7 +619,7 @@ static float128 commonNaNToFloat128( commonNaNT a )
 
 static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM)
 {
-    flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
+    flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN, aIsLargerSignificand;
 
     if ( STATUS(default_nan_mode) ) {
         a.low = float128_default_nan_low;
@@ -600,19 +639,20 @@ static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM)
     b.high |= LIT64( 0x0000800000000000 );
 #endif
     if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
-    if ( aIsSignalingNaN ) {
-        if ( bIsSignalingNaN ) goto returnLargerSignificand;
-        return bIsNaN ? b : a;
-    }
-    else if ( aIsNaN ) {
-        if ( bIsSignalingNaN || ! bIsNaN ) return a;
- returnLargerSignificand:
-        if ( lt128( a.high<<1, a.low, b.high<<1, b.low ) ) return b;
-        if ( lt128( b.high<<1, b.low, a.high<<1, a.low ) ) return a;
-        return ( a.high < b.high ) ? a : b;
+
+    if (lt128(a.high<<1, a.low, b.high<<1, b.low)) {
+        aIsLargerSignificand = 0;
+    } else if (lt128(b.high<<1, b.low, a.high<<1, a.low)) {
+        aIsLargerSignificand = 1;
+    } else {
+        aIsLargerSignificand = (a.high < b.high) ? 1 : 0;
     }
-    else {
+
+    if (pickNaN(aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN,
+                aIsLargerSignificand)) {
         return b;
+    } else {
+        return a;
     }
 }
 
commit 185698715dfb18c82ad2a5dbc169908602d43e81
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Fri Dec 17 15:56:06 2010 +0000

    softfloat: Rename float*_is_nan() functions to float*_is_quiet_nan()
    
    The softfloat functions float*_is_nan() were badly misnamed,
    because they return true only for quiet NaNs, not for all NaNs.
    Rename them to float*_is_quiet_nan() to more accurately reflect
    what they do.
    
    This change was produced by:
     perl -p -i -e 's/_is_nan/_is_quiet_nan/g' $(git grep -l is_nan)
    (with the results manually checked.)
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Reviewed-by: Nathan Froyd <froydnj at codesourcery.com>
    Acked-by: Edgar E. Iglesias <edgar.iglesias at gmail.com>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/fpu/softfloat-native.c b/fpu/softfloat-native.c
index 049c830..008bb53 100644
--- a/fpu/softfloat-native.c
+++ b/fpu/softfloat-native.c
@@ -254,7 +254,7 @@ int float32_is_signaling_nan( float32 a1)
     return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
 }
 
-int float32_is_nan( float32 a1 )
+int float32_is_quiet_nan( float32 a1 )
 {
     float32u u;
     uint64_t a;
@@ -411,7 +411,7 @@ int float64_is_signaling_nan( float64 a1)
 
 }
 
-int float64_is_nan( float64 a1 )
+int float64_is_quiet_nan( float64 a1 )
 {
     float64u u;
     uint64_t a;
@@ -504,7 +504,7 @@ int floatx80_is_signaling_nan( floatx80 a1)
         && ( u.i.low == aLow );
 }
 
-int floatx80_is_nan( floatx80 a1 )
+int floatx80_is_quiet_nan( floatx80 a1 )
 {
     floatx80u u;
     u.f = a1;
diff --git a/fpu/softfloat-native.h b/fpu/softfloat-native.h
index 6da0bcb..80b5f28 100644
--- a/fpu/softfloat-native.h
+++ b/fpu/softfloat-native.h
@@ -242,7 +242,7 @@ INLINE int float32_unordered( float32 a, float32 b STATUS_PARAM)
 int float32_compare( float32, float32 STATUS_PARAM );
 int float32_compare_quiet( float32, float32 STATUS_PARAM );
 int float32_is_signaling_nan( float32 );
-int float32_is_nan( float32 );
+int float32_is_quiet_nan( float32 );
 
 INLINE float32 float32_abs(float32 a)
 {
@@ -351,7 +351,7 @@ INLINE int float64_unordered( float64 a, float64 b STATUS_PARAM)
 int float64_compare( float64, float64 STATUS_PARAM );
 int float64_compare_quiet( float64, float64 STATUS_PARAM );
 int float64_is_signaling_nan( float64 );
-int float64_is_nan( float64 );
+int float64_is_quiet_nan( float64 );
 
 INLINE float64 float64_abs(float64 a)
 {
@@ -455,7 +455,7 @@ INLINE int floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM)
 int floatx80_compare( floatx80, floatx80 STATUS_PARAM );
 int floatx80_compare_quiet( floatx80, floatx80 STATUS_PARAM );
 int floatx80_is_signaling_nan( floatx80 );
-int floatx80_is_nan( floatx80 );
+int floatx80_is_quiet_nan( floatx80 );
 
 INLINE floatx80 floatx80_abs(floatx80 a)
 {
diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h
index 0746878..f382f7a 100644
--- a/fpu/softfloat-specialize.h
+++ b/fpu/softfloat-specialize.h
@@ -76,7 +76,7 @@ typedef struct {
 | NaN; otherwise returns 0.
 *----------------------------------------------------------------------------*/
 
-int float32_is_nan( float32 a_ )
+int float32_is_quiet_nan( float32 a_ )
 {
     uint32_t a = float32_val(a_);
 #if SNAN_BIT_IS_ONE
@@ -166,9 +166,9 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM)
     if ( STATUS(default_nan_mode) )
         return float32_default_nan;
 
-    aIsNaN = float32_is_nan( a );
+    aIsNaN = float32_is_quiet_nan( a );
     aIsSignalingNaN = float32_is_signaling_nan( a );
-    bIsNaN = float32_is_nan( b );
+    bIsNaN = float32_is_quiet_nan( b );
     bIsSignalingNaN = float32_is_signaling_nan( b );
     av = float32_val(a);
     bv = float32_val(b);
@@ -223,7 +223,7 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM)
 | NaN; otherwise returns 0.
 *----------------------------------------------------------------------------*/
 
-int float64_is_nan( float64 a_ )
+int float64_is_quiet_nan( float64 a_ )
 {
     bits64 a = float64_val(a_);
 #if SNAN_BIT_IS_ONE
@@ -320,9 +320,9 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM)
     if ( STATUS(default_nan_mode) )
         return float64_default_nan;
 
-    aIsNaN = float64_is_nan( a );
+    aIsNaN = float64_is_quiet_nan( a );
     aIsSignalingNaN = float64_is_signaling_nan( a );
-    bIsNaN = float64_is_nan( b );
+    bIsNaN = float64_is_quiet_nan( b );
     bIsSignalingNaN = float64_is_signaling_nan( b );
     av = float64_val(a);
     bv = float64_val(b);
@@ -377,7 +377,7 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM)
 | quiet NaN; otherwise returns 0.
 *----------------------------------------------------------------------------*/
 
-int floatx80_is_nan( floatx80 a )
+int floatx80_is_quiet_nan( floatx80 a )
 {
 #if SNAN_BIT_IS_ONE
     bits64 aLow;
@@ -462,9 +462,9 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM)
         return a;
     }
 
-    aIsNaN = floatx80_is_nan( a );
+    aIsNaN = floatx80_is_quiet_nan( a );
     aIsSignalingNaN = floatx80_is_signaling_nan( a );
-    bIsNaN = floatx80_is_nan( b );
+    bIsNaN = floatx80_is_quiet_nan( b );
     bIsSignalingNaN = floatx80_is_signaling_nan( b );
 #if SNAN_BIT_IS_ONE
     a.low &= ~LIT64( 0xC000000000000000 );
@@ -511,7 +511,7 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM)
 | NaN; otherwise returns 0.
 *----------------------------------------------------------------------------*/
 
-int float128_is_nan( float128 a )
+int float128_is_quiet_nan( float128 a )
 {
 #if SNAN_BIT_IS_ONE
     return
@@ -588,9 +588,9 @@ static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM)
         return a;
     }
 
-    aIsNaN = float128_is_nan( a );
+    aIsNaN = float128_is_quiet_nan( a );
     aIsSignalingNaN = float128_is_signaling_nan( a );
-    bIsNaN = float128_is_nan( b );
+    bIsNaN = float128_is_quiet_nan( b );
     bIsSignalingNaN = float128_is_signaling_nan( b );
 #if SNAN_BIT_IS_ONE
     a.high &= ~LIT64( 0x0000800000000000 );
diff --git a/fpu/softfloat.h b/fpu/softfloat.h
index 1c1004d..1f37877 100644
--- a/fpu/softfloat.h
+++ b/fpu/softfloat.h
@@ -287,7 +287,7 @@ int float32_le_quiet( float32, float32 STATUS_PARAM );
 int float32_lt_quiet( float32, float32 STATUS_PARAM );
 int float32_compare( float32, float32 STATUS_PARAM );
 int float32_compare_quiet( float32, float32 STATUS_PARAM );
-int float32_is_nan( float32 );
+int float32_is_quiet_nan( float32 );
 int float32_is_signaling_nan( float32 );
 float32 float32_maybe_silence_nan( float32 );
 float32 float32_scalbn( float32, int STATUS_PARAM );
@@ -367,7 +367,7 @@ int float64_le_quiet( float64, float64 STATUS_PARAM );
 int float64_lt_quiet( float64, float64 STATUS_PARAM );
 int float64_compare( float64, float64 STATUS_PARAM );
 int float64_compare_quiet( float64, float64 STATUS_PARAM );
-int float64_is_nan( float64 a );
+int float64_is_quiet_nan( float64 a );
 int float64_is_signaling_nan( float64 );
 float64 float64_maybe_silence_nan( float64 );
 float64 float64_scalbn( float64, int STATUS_PARAM );
@@ -437,7 +437,7 @@ int floatx80_lt( floatx80, floatx80 STATUS_PARAM );
 int floatx80_eq_signaling( floatx80, floatx80 STATUS_PARAM );
 int floatx80_le_quiet( floatx80, floatx80 STATUS_PARAM );
 int floatx80_lt_quiet( floatx80, floatx80 STATUS_PARAM );
-int floatx80_is_nan( floatx80 );
+int floatx80_is_quiet_nan( floatx80 );
 int floatx80_is_signaling_nan( floatx80 );
 floatx80 floatx80_scalbn( floatx80, int STATUS_PARAM );
 
@@ -503,7 +503,7 @@ int float128_le_quiet( float128, float128 STATUS_PARAM );
 int float128_lt_quiet( float128, float128 STATUS_PARAM );
 int float128_compare( float128, float128 STATUS_PARAM );
 int float128_compare_quiet( float128, float128 STATUS_PARAM );
-int float128_is_nan( float128 );
+int float128_is_quiet_nan( float128 );
 int float128_is_signaling_nan( float128 );
 float128 float128_scalbn( float128, int STATUS_PARAM );
 
diff --git a/linux-user/arm/nwfpe/fpa11_cprt.c b/linux-user/arm/nwfpe/fpa11_cprt.c
index 5d64591..0e61b58 100644
--- a/linux-user/arm/nwfpe/fpa11_cprt.c
+++ b/linux-user/arm/nwfpe/fpa11_cprt.c
@@ -199,21 +199,21 @@ static unsigned int PerformComparison(const unsigned int opcode)
    {
       case typeSingle:
         //printk("single.\n");
-	if (float32_is_nan(fpa11->fpreg[Fn].fSingle))
+	if (float32_is_quiet_nan(fpa11->fpreg[Fn].fSingle))
 	   goto unordered;
         rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
       break;
 
       case typeDouble:
         //printk("double.\n");
-	if (float64_is_nan(fpa11->fpreg[Fn].fDouble))
+	if (float64_is_quiet_nan(fpa11->fpreg[Fn].fDouble))
 	   goto unordered;
         rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status);
       break;
 
       case typeExtended:
         //printk("extended.\n");
-	if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended))
+	if (floatx80_is_quiet_nan(fpa11->fpreg[Fn].fExtended))
 	   goto unordered;
         rFn = fpa11->fpreg[Fn].fExtended;
       break;
@@ -225,7 +225,7 @@ static unsigned int PerformComparison(const unsigned int opcode)
    {
      //printk("Fm is a constant: #%d.\n",Fm);
      rFm = getExtendedConstant(Fm);
-     if (floatx80_is_nan(rFm))
+     if (floatx80_is_quiet_nan(rFm))
         goto unordered;
    }
    else
@@ -235,21 +235,21 @@ static unsigned int PerformComparison(const unsigned int opcode)
       {
          case typeSingle:
            //printk("single.\n");
-	   if (float32_is_nan(fpa11->fpreg[Fm].fSingle))
+	   if (float32_is_quiet_nan(fpa11->fpreg[Fm].fSingle))
 	      goto unordered;
            rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status);
          break;
 
          case typeDouble:
            //printk("double.\n");
-	   if (float64_is_nan(fpa11->fpreg[Fm].fDouble))
+	   if (float64_is_quiet_nan(fpa11->fpreg[Fm].fDouble))
 	      goto unordered;
            rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status);
          break;
 
          case typeExtended:
            //printk("extended.\n");
-	   if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended))
+	   if (floatx80_is_quiet_nan(fpa11->fpreg[Fm].fExtended))
 	      goto unordered;
            rFm = fpa11->fpreg[Fm].fExtended;
          break;
diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c
index ff5ae26..6c2ae20 100644
--- a/target-alpha/op_helper.c
+++ b/target-alpha/op_helper.c
@@ -904,7 +904,7 @@ uint64_t helper_cmptun (uint64_t a, uint64_t b)
     fa = t_to_float64(a);
     fb = t_to_float64(b);
 
-    if (float64_is_nan(fa) || float64_is_nan(fb))
+    if (float64_is_quiet_nan(fa) || float64_is_quiet_nan(fb))
         return 0x4000000000000000ULL;
     else
         return 0;
diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index 56de897..514b039 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -614,10 +614,10 @@ float64 HELPER(sub_cmp_f64)(CPUState *env, float64 a, float64 b)
     /* ??? Should flush denormals to zero.  */
     float64 res;
     res = float64_sub(a, b, &env->fp_status);
-    if (float64_is_nan(res)) {
+    if (float64_is_quiet_nan(res)) {
         /* +/-inf compares equal against itself, but sub returns nan.  */
-        if (!float64_is_nan(a)
-            && !float64_is_nan(b)) {
+        if (!float64_is_quiet_nan(a)
+            && !float64_is_quiet_nan(b)) {
             res = float64_zero;
             if (float64_lt_quiet(a, res, &env->fp_status))
                 res = float64_chs(res);
diff --git a/target-microblaze/op_helper.c b/target-microblaze/op_helper.c
index 3d2b313..97461ae 100644
--- a/target-microblaze/op_helper.c
+++ b/target-microblaze/op_helper.c
@@ -308,7 +308,7 @@ uint32_t helper_fcmp_un(uint32_t a, uint32_t b)
         r = 1;
     }
 
-    if (float32_is_nan(fa.f) || float32_is_nan(fb.f)) {
+    if (float32_is_quiet_nan(fa.f) || float32_is_quiet_nan(fb.f)) {
         r = 1;
     }
 
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index ec6864d..669faf1 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -2877,10 +2877,10 @@ static int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM)
 {
     if (float64_is_signaling_nan(a) ||
         float64_is_signaling_nan(b) ||
-        (sig && (float64_is_nan(a) || float64_is_nan(b)))) {
+        (sig && (float64_is_quiet_nan(a) || float64_is_quiet_nan(b)))) {
         float_raise(float_flag_invalid, status);
         return 1;
-    } else if (float64_is_nan(a) || float64_is_nan(b)) {
+    } else if (float64_is_quiet_nan(a) || float64_is_quiet_nan(b)) {
         return 1;
     } else {
         return 0;
@@ -2935,10 +2935,10 @@ static flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM)
 {
     if (float32_is_signaling_nan(a) ||
         float32_is_signaling_nan(b) ||
-        (sig && (float32_is_nan(a) || float32_is_nan(b)))) {
+        (sig && (float32_is_quiet_nan(a) || float32_is_quiet_nan(b)))) {
         float_raise(float_flag_invalid, status);
         return 1;
-    } else if (float32_is_nan(a) || float32_is_nan(b)) {
+    } else if (float32_is_quiet_nan(a) || float32_is_quiet_nan(b)) {
         return 1;
     } else {
         return 0;
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index f32a5ff..5ded1c1 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -546,7 +546,7 @@ uint32_t helper_compute_fprf (uint64_t arg, uint32_t set_fprf)
     int ret;
     farg.ll = arg;
     isneg = float64_is_neg(farg.d);
-    if (unlikely(float64_is_nan(farg.d))) {
+    if (unlikely(float64_is_quiet_nan(farg.d))) {
         if (float64_is_signaling_nan(farg.d)) {
             /* Signaling NaN: flags are undefined */
             ret = 0x00;
@@ -1111,7 +1111,7 @@ uint64_t helper_fctiw (uint64_t arg)
     if (unlikely(float64_is_signaling_nan(farg.d))) {
         /* sNaN conversion */
         farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
-    } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
+    } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
         /* qNan / infinity conversion */
         farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
     } else {
@@ -1135,7 +1135,7 @@ uint64_t helper_fctiwz (uint64_t arg)
     if (unlikely(float64_is_signaling_nan(farg.d))) {
         /* sNaN conversion */
         farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
-    } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
+    } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
         /* qNan / infinity conversion */
         farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
     } else {
@@ -1168,7 +1168,7 @@ uint64_t helper_fctid (uint64_t arg)
     if (unlikely(float64_is_signaling_nan(farg.d))) {
         /* sNaN conversion */
         farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
-    } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
+    } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
         /* qNan / infinity conversion */
         farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
     } else {
@@ -1186,7 +1186,7 @@ uint64_t helper_fctidz (uint64_t arg)
     if (unlikely(float64_is_signaling_nan(farg.d))) {
         /* sNaN conversion */
         farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
-    } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
+    } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
         /* qNan / infinity conversion */
         farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
     } else {
@@ -1205,7 +1205,7 @@ static inline uint64_t do_fri(uint64_t arg, int rounding_mode)
     if (unlikely(float64_is_signaling_nan(farg.d))) {
         /* sNaN round */
         farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
-    } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
+    } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
         /* qNan / infinity round */
         farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
     } else {
@@ -1375,7 +1375,7 @@ uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
         farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
         farg1.d = float64_add(farg1.d, farg3.d, &env->fp_status);
 #endif
-        if (likely(!float64_is_nan(farg1.d)))
+        if (likely(!float64_is_quiet_nan(farg1.d)))
             farg1.d = float64_chs(farg1.d);
     }
     return farg1.ll;
@@ -1425,7 +1425,7 @@ uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
         farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
         farg1.d = float64_sub(farg1.d, farg3.d, &env->fp_status);
 #endif
-        if (likely(!float64_is_nan(farg1.d)))
+        if (likely(!float64_is_quiet_nan(farg1.d)))
             farg1.d = float64_chs(farg1.d);
     }
     return farg1.ll;
@@ -1533,7 +1533,7 @@ uint64_t helper_fsel (uint64_t arg1, uint64_t arg2, uint64_t arg3)
 
     farg1.ll = arg1;
 
-    if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) && !float64_is_nan(farg1.d))
+    if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) && !float64_is_quiet_nan(farg1.d))
         return arg2;
     else
         return arg3;
@@ -1546,8 +1546,8 @@ void helper_fcmpu (uint64_t arg1, uint64_t arg2, uint32_t crfD)
     farg1.ll = arg1;
     farg2.ll = arg2;
 
-    if (unlikely(float64_is_nan(farg1.d) ||
-                 float64_is_nan(farg2.d))) {
+    if (unlikely(float64_is_quiet_nan(farg1.d) ||
+                 float64_is_quiet_nan(farg2.d))) {
         ret = 0x01UL;
     } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
         ret = 0x08UL;
@@ -1575,8 +1575,8 @@ void helper_fcmpo (uint64_t arg1, uint64_t arg2, uint32_t crfD)
     farg1.ll = arg1;
     farg2.ll = arg2;
 
-    if (unlikely(float64_is_nan(farg1.d) ||
-                 float64_is_nan(farg2.d))) {
+    if (unlikely(float64_is_quiet_nan(farg1.d) ||
+                 float64_is_quiet_nan(farg2.d))) {
         ret = 0x01UL;
     } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
         ret = 0x08UL;
@@ -1938,7 +1938,7 @@ target_ulong helper_dlmzb (target_ulong high, target_ulong low, uint32_t update_
 /* If X is a NaN, store the corresponding QNaN into RESULT.  Otherwise,
  * execute the following block.  */
 #define DO_HANDLE_NAN(result, x)                \
-    if (float32_is_nan(x) || float32_is_signaling_nan(x)) {     \
+    if (float32_is_quiet_nan(x) || float32_is_signaling_nan(x)) {     \
         CPU_FloatU __f;                                         \
         __f.f = x;                                              \
         __f.l = __f.l | (1 << 22);  /* Set QNaN bit. */         \
@@ -2283,7 +2283,7 @@ void helper_vcmpbfp_dot (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
         float_status s = env->vec_status;                               \
         set_float_rounding_mode(float_round_to_zero, &s);               \
         for (i = 0; i < ARRAY_SIZE(r->f); i++) {                        \
-            if (float32_is_nan(b->f[i]) ||                              \
+            if (float32_is_quiet_nan(b->f[i]) ||                              \
                 float32_is_signaling_nan(b->f[i])) {                    \
                 r->element[i] = 0;                                      \
             } else {                                                    \
@@ -3132,7 +3132,7 @@ static inline int32_t efsctsi(uint32_t val)
 
     u.l = val;
     /* NaN are not treated the same way IEEE 754 does */
-    if (unlikely(float32_is_nan(u.f)))
+    if (unlikely(float32_is_quiet_nan(u.f)))
         return 0;
 
     return float32_to_int32(u.f, &env->vec_status);
@@ -3144,7 +3144,7 @@ static inline uint32_t efsctui(uint32_t val)
 
     u.l = val;
     /* NaN are not treated the same way IEEE 754 does */
-    if (unlikely(float32_is_nan(u.f)))
+    if (unlikely(float32_is_quiet_nan(u.f)))
         return 0;
 
     return float32_to_uint32(u.f, &env->vec_status);
@@ -3156,7 +3156,7 @@ static inline uint32_t efsctsiz(uint32_t val)
 
     u.l = val;
     /* NaN are not treated the same way IEEE 754 does */
-    if (unlikely(float32_is_nan(u.f)))
+    if (unlikely(float32_is_quiet_nan(u.f)))
         return 0;
 
     return float32_to_int32_round_to_zero(u.f, &env->vec_status);
@@ -3168,7 +3168,7 @@ static inline uint32_t efsctuiz(uint32_t val)
 
     u.l = val;
     /* NaN are not treated the same way IEEE 754 does */
-    if (unlikely(float32_is_nan(u.f)))
+    if (unlikely(float32_is_quiet_nan(u.f)))
         return 0;
 
     return float32_to_uint32_round_to_zero(u.f, &env->vec_status);
@@ -3205,7 +3205,7 @@ static inline uint32_t efsctsf(uint32_t val)
 
     u.l = val;
     /* NaN are not treated the same way IEEE 754 does */
-    if (unlikely(float32_is_nan(u.f)))
+    if (unlikely(float32_is_quiet_nan(u.f)))
         return 0;
     tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
     u.f = float32_mul(u.f, tmp, &env->vec_status);
@@ -3220,7 +3220,7 @@ static inline uint32_t efsctuf(uint32_t val)
 
     u.l = val;
     /* NaN are not treated the same way IEEE 754 does */
-    if (unlikely(float32_is_nan(u.f)))
+    if (unlikely(float32_is_quiet_nan(u.f)))
         return 0;
     tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
     u.f = float32_mul(u.f, tmp, &env->vec_status);
@@ -3474,7 +3474,7 @@ uint32_t helper_efdctsi (uint64_t val)
 
     u.ll = val;
     /* NaN are not treated the same way IEEE 754 does */
-    if (unlikely(float64_is_nan(u.d)))
+    if (unlikely(float64_is_quiet_nan(u.d)))
         return 0;
 
     return float64_to_int32(u.d, &env->vec_status);
@@ -3486,7 +3486,7 @@ uint32_t helper_efdctui (uint64_t val)
 
     u.ll = val;
     /* NaN are not treated the same way IEEE 754 does */
-    if (unlikely(float64_is_nan(u.d)))
+    if (unlikely(float64_is_quiet_nan(u.d)))
         return 0;
 
     return float64_to_uint32(u.d, &env->vec_status);
@@ -3498,7 +3498,7 @@ uint32_t helper_efdctsiz (uint64_t val)
 
     u.ll = val;
     /* NaN are not treated the same way IEEE 754 does */
-    if (unlikely(float64_is_nan(u.d)))
+    if (unlikely(float64_is_quiet_nan(u.d)))
         return 0;
 
     return float64_to_int32_round_to_zero(u.d, &env->vec_status);
@@ -3510,7 +3510,7 @@ uint64_t helper_efdctsidz (uint64_t val)
 
     u.ll = val;
     /* NaN are not treated the same way IEEE 754 does */
-    if (unlikely(float64_is_nan(u.d)))
+    if (unlikely(float64_is_quiet_nan(u.d)))
         return 0;
 
     return float64_to_int64_round_to_zero(u.d, &env->vec_status);
@@ -3522,7 +3522,7 @@ uint32_t helper_efdctuiz (uint64_t val)
 
     u.ll = val;
     /* NaN are not treated the same way IEEE 754 does */
-    if (unlikely(float64_is_nan(u.d)))
+    if (unlikely(float64_is_quiet_nan(u.d)))
         return 0;
 
     return float64_to_uint32_round_to_zero(u.d, &env->vec_status);
@@ -3534,7 +3534,7 @@ uint64_t helper_efdctuidz (uint64_t val)
 
     u.ll = val;
     /* NaN are not treated the same way IEEE 754 does */
-    if (unlikely(float64_is_nan(u.d)))
+    if (unlikely(float64_is_quiet_nan(u.d)))
         return 0;
 
     return float64_to_uint64_round_to_zero(u.d, &env->vec_status);
@@ -3571,7 +3571,7 @@ uint32_t helper_efdctsf (uint64_t val)
 
     u.ll = val;
     /* NaN are not treated the same way IEEE 754 does */
-    if (unlikely(float64_is_nan(u.d)))
+    if (unlikely(float64_is_quiet_nan(u.d)))
         return 0;
     tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
     u.d = float64_mul(u.d, tmp, &env->vec_status);
@@ -3586,7 +3586,7 @@ uint32_t helper_efdctuf (uint64_t val)
 
     u.ll = val;
     /* NaN are not treated the same way IEEE 754 does */
-    if (unlikely(float64_is_nan(u.d)))
+    if (unlikely(float64_is_quiet_nan(u.d)))
         return 0;
     tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
     u.d = float64_mul(u.d, tmp, &env->vec_status);
commit f96a38347a0c6ab31fbb6200c13e684d1fee449c
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Tue Dec 28 17:46:59 2010 +0100

    TCG: Improve tb_phys_hash_func()
    
    Most of emulated CPU have instructions aligned on 16 or 32 bits, while
    on others GCC tries to align the target jump location. This means that
    1/2 or 3/4 of tb_phys_hash entries are never used.
    
    Update the hash function tb_phys_hash_func() to ignore the two lowest
    bits of the address. This brings a 6% speed-up when booting a MIPS
    image.
    
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/exec-all.h b/exec-all.h
index 6821b17..a4b75bd 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -177,7 +177,7 @@ static inline unsigned int tb_jmp_cache_hash_func(target_ulong pc)
 
 static inline unsigned int tb_phys_hash_func(tb_page_addr_t pc)
 {
-    return pc & (CODE_GEN_PHYS_HASH_SIZE - 1);
+    return (pc >> 2) & (CODE_GEN_PHYS_HASH_SIZE - 1);
 }
 
 TranslationBlock *tb_alloc(target_ulong pc);
commit 8aac08b10b2e8c131b9385d2dc37e4a02e1d12c1
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Fri Dec 31 17:50:27 2010 +0100

    target-arm: fix UMAAL instruction
    
    UMAAL should use unsigned multiply instead of signed.
    
    This patch fixes this issue by handling UMAAL separately from
    UMULL/UMLAL/SMULL/SMLAL as these instructions are different
    enough. It also explicitly list instructions in case and catch
    nonexistent instruction as illegal. Also fixes a few style issues.
    
    This fixes the issues reported in
    https://bugs.launchpad.net/qemu/+bug/696015
    
    Reviewed-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/target-arm/translate.c b/target-arm/translate.c
index 8d494ec..2598268 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -6637,26 +6637,38 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                             gen_logic_CC(tmp);
                         store_reg(s, rd, tmp);
                         break;
-                    default:
-                        /* 64 bit mul */
+                    case 4:
+                        /* 64 bit mul double accumulate (UMAAL) */
+                        ARCH(6);
                         tmp = load_reg(s, rs);
                         tmp2 = load_reg(s, rm);
-                        if (insn & (1 << 22))
+                        tmp64 = gen_mulu_i64_i32(tmp, tmp2);
+                        gen_addq_lo(s, tmp64, rn);
+                        gen_addq_lo(s, tmp64, rd);
+                        gen_storeq_reg(s, rn, rd, tmp64);
+                        tcg_temp_free_i64(tmp64);
+                        break;
+                    case 8: case 9: case 10: case 11:
+                    case 12: case 13: case 14: case 15:
+                        /* 64 bit mul: UMULL, UMLAL, SMULL, SMLAL. */
+                        tmp = load_reg(s, rs);
+                        tmp2 = load_reg(s, rm);
+                        if (insn & (1 << 22)) {
                             tmp64 = gen_muls_i64_i32(tmp, tmp2);
-                        else
+                        } else {
                             tmp64 = gen_mulu_i64_i32(tmp, tmp2);
-                        if (insn & (1 << 21)) /* mult accumulate */
+                        }
+                        if (insn & (1 << 21)) { /* mult accumulate */
                             gen_addq(s, tmp64, rn, rd);
-                        if (!(insn & (1 << 23))) { /* double accumulate */
-                            ARCH(6);
-                            gen_addq_lo(s, tmp64, rn);
-                            gen_addq_lo(s, tmp64, rd);
                         }
-                        if (insn & (1 << 20))
+                        if (insn & (1 << 20)) {
                             gen_logicq_cc(tmp64);
+                        }
                         gen_storeq_reg(s, rn, rd, tmp64);
                         tcg_temp_free_i64(tmp64);
                         break;
+                    default:
+                        goto illegal_op;
                     }
                 } else {
                     rn = (insn >> 16) & 0xf;
commit 6d5c34fa027d1477c0572ea74421e21b0f733838
Author: Mike Pall <mike-lp10 at luajit.org>
Date:   Fri Dec 31 21:17:53 2010 +0100

    Fix translation of unary PPC/SPE instructions (efdneg etc.).
    
    Signed-off-by: Mike Pall <mike-lp10 at luajit.org>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index c82a483..74e06d7 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -7751,10 +7751,10 @@ static inline void gen_evfsabs(DisasContext *ctx)
         return;
     }
 #if defined(TARGET_PPC64)
-    tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~0x8000000080000000LL);
+    tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~0x8000000080000000LL);
 #else
-    tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~0x80000000);
-    tcg_gen_andi_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], ~0x80000000);
+    tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~0x80000000);
+    tcg_gen_andi_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], ~0x80000000);
 #endif
 }
 static inline void gen_evfsnabs(DisasContext *ctx)
@@ -7764,10 +7764,10 @@ static inline void gen_evfsnabs(DisasContext *ctx)
         return;
     }
 #if defined(TARGET_PPC64)
-    tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000080000000LL);
+    tcg_gen_ori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000080000000LL);
 #else
-    tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
-    tcg_gen_ori_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000);
+    tcg_gen_ori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
+    tcg_gen_ori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000);
 #endif
 }
 static inline void gen_evfsneg(DisasContext *ctx)
@@ -7777,10 +7777,10 @@ static inline void gen_evfsneg(DisasContext *ctx)
         return;
     }
 #if defined(TARGET_PPC64)
-    tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000080000000LL);
+    tcg_gen_xori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000080000000LL);
 #else
-    tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
-    tcg_gen_xori_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000);
+    tcg_gen_xori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
+    tcg_gen_xori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000);
 #endif
 }
 
@@ -7832,7 +7832,7 @@ static inline void gen_efsabs(DisasContext *ctx)
         gen_exception(ctx, POWERPC_EXCP_APU);
         return;
     }
-    tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], (target_long)~0x80000000LL);
+    tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], (target_long)~0x80000000LL);
 }
 static inline void gen_efsnabs(DisasContext *ctx)
 {
@@ -7840,7 +7840,7 @@ static inline void gen_efsnabs(DisasContext *ctx)
         gen_exception(ctx, POWERPC_EXCP_APU);
         return;
     }
-    tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
+    tcg_gen_ori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
 }
 static inline void gen_efsneg(DisasContext *ctx)
 {
@@ -7848,7 +7848,7 @@ static inline void gen_efsneg(DisasContext *ctx)
         gen_exception(ctx, POWERPC_EXCP_APU);
         return;
     }
-    tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
+    tcg_gen_xori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
 }
 
 /* Conversion */
@@ -7901,9 +7901,10 @@ static inline void gen_efdabs(DisasContext *ctx)
         return;
     }
 #if defined(TARGET_PPC64)
-    tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~0x8000000000000000LL);
+    tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~0x8000000000000000LL);
 #else
-    tcg_gen_andi_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], ~0x80000000);
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_andi_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], ~0x80000000);
 #endif
 }
 static inline void gen_efdnabs(DisasContext *ctx)
@@ -7913,9 +7914,10 @@ static inline void gen_efdnabs(DisasContext *ctx)
         return;
     }
 #if defined(TARGET_PPC64)
-    tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000000000000LL);
+    tcg_gen_ori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000000000000LL);
 #else
-    tcg_gen_ori_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000);
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_ori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000);
 #endif
 }
 static inline void gen_efdneg(DisasContext *ctx)
@@ -7925,9 +7927,10 @@ static inline void gen_efdneg(DisasContext *ctx)
         return;
     }
 #if defined(TARGET_PPC64)
-    tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000000000000LL);
+    tcg_gen_xori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000000000000LL);
 #else
-    tcg_gen_xori_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000);
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_xori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000);
 #endif
 }
 
commit 0fcec41eec0432c77645b4a407d3a3e030c4abc4
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Sat Dec 25 23:25:47 2010 +0100

    target-sparc: fix udiv(cc) and sdiv(cc)
    
    Since commit 5a4bb580cdb10b066f9fd67658b31cac4a4ea5e5, Xorg crashes on
    a Debian Etch image. The commit itself is fine, but it triggers a bug
    due to wrong computation of flags for udiv(cc) and sdiv(cc).
    
    This patch only compute cc_src2 for the cc version of udiv/sdiv. It
    also moves the update of cc_dst and cc_op to the helper, as it is
    faster doing it here when there is already an helper.
    
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-sparc/helper.h b/target-sparc/helper.h
index 6f103e7..e6d82f9 100644
--- a/target-sparc/helper.h
+++ b/target-sparc/helper.h
@@ -37,7 +37,9 @@ DEF_HELPER_0(save, void)
 DEF_HELPER_0(restore, void)
 DEF_HELPER_1(flush, void, tl)
 DEF_HELPER_2(udiv, tl, tl, tl)
+DEF_HELPER_2(udiv_cc, tl, tl, tl)
 DEF_HELPER_2(sdiv, tl, tl, tl)
+DEF_HELPER_2(sdiv_cc, tl, tl, tl)
 DEF_HELPER_2(stdf, void, tl, int)
 DEF_HELPER_2(lddf, void, tl, int)
 DEF_HELPER_2(ldqf, void, tl, int)
diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
index 4f753ba..58f9f82 100644
--- a/target-sparc/op_helper.c
+++ b/target-sparc/op_helper.c
@@ -3300,8 +3300,9 @@ void helper_rett(void)
 }
 #endif
 
-target_ulong helper_udiv(target_ulong a, target_ulong b)
+static target_ulong helper_udiv_common(target_ulong a, target_ulong b, int cc)
 {
+    int overflow = 0;
     uint64_t x0;
     uint32_t x1;
 
@@ -3314,16 +3315,31 @@ target_ulong helper_udiv(target_ulong a, target_ulong b)
 
     x0 = x0 / x1;
     if (x0 > 0xffffffff) {
-        env->cc_src2 = 1;
-        return 0xffffffff;
-    } else {
-        env->cc_src2 = 0;
-        return x0;
+        x0 = 0xffffffff;
+        overflow = 1;
+    }
+
+    if (cc) {
+        env->cc_dst = x0;
+        env->cc_src2 = overflow;
+        env->cc_op = CC_OP_DIV;
     }
+    return x0;
 }
 
-target_ulong helper_sdiv(target_ulong a, target_ulong b)
+target_ulong helper_udiv(target_ulong a, target_ulong b)
+{
+    return helper_udiv_common(a, b, 0);
+}
+
+target_ulong helper_udiv_cc(target_ulong a, target_ulong b)
+{
+    return helper_udiv_common(a, b, 1);
+}
+
+static target_ulong helper_sdiv_common(target_ulong a, target_ulong b, int cc)
 {
+    int overflow = 0;
     int64_t x0;
     int32_t x1;
 
@@ -3336,12 +3352,26 @@ target_ulong helper_sdiv(target_ulong a, target_ulong b)
 
     x0 = x0 / x1;
     if ((int32_t) x0 != x0) {
-        env->cc_src2 = 1;
-        return x0 < 0? 0x80000000: 0x7fffffff;
-    } else {
-        env->cc_src2 = 0;
-        return x0;
+        x0 = x0 < 0 ? 0x80000000: 0x7fffffff;
+        overflow = 1;
+    }
+
+    if (cc) {
+        env->cc_dst = x0;
+        env->cc_src2 = overflow;
+        env->cc_op = CC_OP_DIV;
     }
+    return x0;
+}
+
+target_ulong helper_sdiv(target_ulong a, target_ulong b)
+{
+    return helper_sdiv_common(a, b, 0);
+}
+
+target_ulong helper_sdiv_cc(target_ulong a, target_ulong b)
+{
+    return helper_sdiv_common(a, b, 1);
 }
 
 void helper_stdf(target_ulong addr, int mem_idx)
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 23f9519..21c5675 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -3162,20 +3162,20 @@ static void disas_sparc_insn(DisasContext * dc)
 #endif
                     case 0xe: /* udiv */
                         CHECK_IU_FEATURE(dc, DIV);
-                        gen_helper_udiv(cpu_dst, cpu_src1, cpu_src2);
                         if (xop & 0x10) {
-                            tcg_gen_mov_tl(cpu_cc_dst, cpu_dst);
-                            tcg_gen_movi_i32(cpu_cc_op, CC_OP_DIV);
+                            gen_helper_udiv_cc(cpu_dst, cpu_src1, cpu_src2);
                             dc->cc_op = CC_OP_DIV;
+                        } else {
+                            gen_helper_udiv(cpu_dst, cpu_src1, cpu_src2);
                         }
                         break;
                     case 0xf: /* sdiv */
                         CHECK_IU_FEATURE(dc, DIV);
-                        gen_helper_sdiv(cpu_dst, cpu_src1, cpu_src2);
                         if (xop & 0x10) {
-                            tcg_gen_mov_tl(cpu_cc_dst, cpu_dst);
-                            tcg_gen_movi_i32(cpu_cc_op, CC_OP_DIV);
+                            gen_helper_sdiv_cc(cpu_dst, cpu_src1, cpu_src2);
                             dc->cc_op = CC_OP_DIV;
+                        } else {
+                            gen_helper_sdiv(cpu_dst, cpu_src1, cpu_src2);
                         }
                         break;
                     default:
commit 818c2e1b9777599d333855330d94050b3432c8b7
Merge: 4058fd9... 7572150...
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Mon Dec 27 22:59:48 2010 +0100

    Merge branch 'spice.v23.pull' of git://anongit.freedesktop.org/spice/qemu
    
    * 'spice.v23.pull' of git://anongit.freedesktop.org/spice/qemu:
      vnc/spice: add set_passwd monitor command.
      vnc: support password expire
      vnc: auth reject cleanup
      spice: add qmp 'query-spice' and hmp 'info spice' commands.
      spice: connection events.
      spice: add qxl device
      spice: add qxl vgabios binary.

commit 4058fd98fd7e9c476774717adbd49698dd273166
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Mon Dec 27 15:52:24 2010 +0100

    x86: Filter out garbage from segment flags dump
    
    Only bits 8..23 of the segment flags contain valid data, so only dump
    those when printing the CPU state.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/target-i386/helper.c b/target-i386/helper.c
index 26ea1e5..25a3e36 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -175,12 +175,12 @@ cpu_x86_dump_seg_cache(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
 #ifdef TARGET_X86_64
     if (env->hflags & HF_CS64_MASK) {
         cpu_fprintf(f, "%-3s=%04x %016" PRIx64 " %08x %08x", name,
-                    sc->selector, sc->base, sc->limit, sc->flags);
+                    sc->selector, sc->base, sc->limit, sc->flags & 0x00ffff00);
     } else
 #endif
     {
         cpu_fprintf(f, "%-3s=%04x %08x %08x %08x", name, sc->selector,
-                    (uint32_t)sc->base, sc->limit, sc->flags);
+                    (uint32_t)sc->base, sc->limit, sc->flags & 0x00ffff00);
     }
 
     if (!(env->hflags & HF_PE_MASK) || !(sc->flags & DESC_P_MASK))
commit 5569fd7c38ddc7482c9b05af0988779cd0027f6d
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Wed Dec 15 17:56:18 2010 -0200

    Fix migrate set speed doc arg
    
    We used to ignore any fractional part in 0.13, but due to recent
    changes (started with 9f9b17a4f0865286391e4d3a0a735230122a2289)
    migrate_set_speed will reject the fractional part.
    
    We don't expect existing clients to be relying on this, but we
    need to update the documentation to reflect the change.
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/qmp-commands.hx b/qmp-commands.hx
index 3486223..164ecbc 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -510,7 +510,7 @@ Set maximum speed for migrations.
 
 Arguments:
 
-- "value": maximum speed, in bytes per second (json-number)
+- "value": maximum speed, in bytes per second (json-int)
 
 Example:
 
commit 16440c5fa0a3ba87c7ea92218466673ede7c08f0
Author: Juha Riihimäki <juha.riihimaki at nokia.com>
Date:   Wed Dec 8 13:15:18 2010 +0200

    target-arm: correct cp15 c1_sys reset value for arm1136 and cortex-a9
    
    Signed-off-by: Juha Riihimäki <juha.riihimaki at nokia.com>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/target-arm/helper.c b/target-arm/helper.c
index e54fb27..50c1017 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -76,6 +76,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         memcpy(env->cp15.c0_c1, arm1136_cp15_c0_c1, 8 * sizeof(uint32_t));
         memcpy(env->cp15.c0_c2, arm1136_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_V6);
@@ -131,6 +132,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c0_clid = (1 << 27) | (1 << 24) | 3;
         env->cp15.c0_ccsid[0] = 0xe00fe015; /* 16k L1 dcache. */
         env->cp15.c0_ccsid[1] = 0x200fe015; /* 16k L1 icache. */
+        env->cp15.c1_sys = 0x00c50078;
         break;
     case ARM_CPUID_CORTEXM3:
         set_feature(env, ARM_FEATURE_V6);
commit 9c486ad6e4e4afcd582460b4c70b1e2be856dbfd
Author: Mattias Holm <holm at liacs.nl>
Date:   Wed Dec 8 13:15:17 2010 +0200

    target-arm: correct cp15 c1_sys reset value for cortex-a8
    
    Signed-off-by: Juha Riihimäki <juha.riihimaki at nokia.com>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/target-arm/helper.c b/target-arm/helper.c
index 409a6c0..e54fb27 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -109,6 +109,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c0_ccsid[0] = 0xe007e01a; /* 16k L1 dcache. */
         env->cp15.c0_ccsid[1] = 0x2007e01a; /* 16k L1 icache. */
         env->cp15.c0_ccsid[2] = 0xf0000000; /* No L2 icache. */
+        env->cp15.c1_sys = 0x00c50078;
         break;
     case ARM_CPUID_CORTEXA9:
         set_feature(env, ARM_FEATURE_V6);
commit c0034328090880621ad8f33e03ae03599e353865
Author: Juha Riihimäki <juha.riihimaki at nokia.com>
Date:   Wed Dec 8 13:15:16 2010 +0200

    target-arm: fix vmsav6 access control
    
    Override access control checks (including execute) for mmu translation
    table descriptors assigned to manager domains.
    
    Signed-off-by: Juha Riihimäki <juha.riihimaki at nokia.com>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/target-arm/helper.c b/target-arm/helper.c
index 9ba2f4f..409a6c0 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1084,22 +1084,26 @@ static int get_phys_addr_v6(CPUState *env, uint32_t address, int access_type,
         }
         code = 15;
     }
-    if (xn && access_type == 2)
-        goto do_fault;
+    if (domain == 3) {
+        *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+    } else {
+        if (xn && access_type == 2)
+            goto do_fault;
 
-    /* The simplified model uses AP[0] as an access control bit.  */
-    if ((env->cp15.c1_sys & (1 << 29)) && (ap & 1) == 0) {
-        /* Access flag fault.  */
-        code = (code == 15) ? 6 : 3;
-        goto do_fault;
-    }
-    *prot = check_ap(env, ap, domain, access_type, is_user);
-    if (!*prot) {
-        /* Access permission fault.  */
-        goto do_fault;
-    }
-    if (!xn) {
-        *prot |= PAGE_EXEC;
+        /* The simplified model uses AP[0] as an access control bit.  */
+        if ((env->cp15.c1_sys & (1 << 29)) && (ap & 1) == 0) {
+            /* Access flag fault.  */
+            code = (code == 15) ? 6 : 3;
+            goto do_fault;
+        }
+        *prot = check_ap(env, ap, domain, access_type, is_user);
+        if (!*prot) {
+            /* Access permission fault.  */
+            goto do_fault;
+        }
+        if (!xn) {
+            *prot |= PAGE_EXEC;
+        }
     }
     *phys_ptr = phys_addr;
     return 0;
commit a5d88f3e030f9f83e63b0cb3c09a3293d8057f4a
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Tue Dec 7 14:13:45 2010 +0000

    target-arm: Correct result in saturating cases for VQSHL of s8/16/32
    
    Where VQSHL of a signed 8/16/32 bit value saturated, the result
    value was not being calculated correctly (it should be either
    the minimum or maximum value for the size of the signed type).
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c
index 48b9f5b..dae063e 100644
--- a/target-arm/neon_helper.c
+++ b/target-arm/neon_helper.c
@@ -580,9 +580,15 @@ uint64_t HELPER(neon_qshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop)
     int8_t tmp; \
     tmp = (int8_t)src2; \
     if (tmp >= (ssize_t)sizeof(src1) * 8) { \
-        if (src1) \
+        if (src1) { \
             SET_QC(); \
-        dest = src1 >> 31; \
+            dest = (uint32_t)(1 << (sizeof(src1) * 8 - 1)); \
+            if (src1 > 0) { \
+                dest--; \
+            } \
+        } else { \
+            dest = src1; \
+        } \
     } else if (tmp <= -(ssize_t)sizeof(src1) * 8) { \
         dest = src1 >> 31; \
     } else if (tmp < 0) { \
@@ -591,7 +597,10 @@ uint64_t HELPER(neon_qshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop)
         dest = src1 << tmp; \
         if ((dest >> tmp) != src1) { \
             SET_QC(); \
-            dest = src2 >> 31; \
+            dest = (uint32_t)(1 << (sizeof(src1) * 8 - 1)); \
+            if (src1 > 0) { \
+                dest--; \
+            } \
         } \
     }} while (0)
 NEON_VOP_ENV(qshl_s8, neon_s8, 4)
commit 620d791e341fe0b36e6c2a5659b2cc9f7866948f
Author: Juha Riihimäki <juha.riihimaki at nokia.com>
Date:   Tue Dec 7 14:13:44 2010 +0000

    target-arm: remove pointless else clause in VQSHL of u64
    
    Remove a pointless else clause in the neon_qshl_u64 helper.
    
    Signed-off-by: Juha Riihimäki <juha.riihimaki at nokia.com>
    Reviewed-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c
index 2dc3d96..48b9f5b 100644
--- a/target-arm/neon_helper.c
+++ b/target-arm/neon_helper.c
@@ -560,8 +560,6 @@ uint64_t HELPER(neon_qshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop)
         if (val) {
             val = ~(uint64_t)0;
             SET_QC();
-        } else {
-            val = 0;
         }
     } else if (shift <= -64) {
         val = 0;
commit eb7a3d7964f748ba815200372d7ff403737c54d7
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Tue Dec 7 14:13:43 2010 +0000

    target-arm: Fix VQSHL of signed 64 bit values by shift counts >= 64
    
    VQSHL of a signed 64 bit non-zero value by a shift count >= 64 should
    saturate; return the correct value in this case.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c
index d29b884..2dc3d96 100644
--- a/target-arm/neon_helper.c
+++ b/target-arm/neon_helper.c
@@ -608,7 +608,7 @@ uint64_t HELPER(neon_qshl_s64)(CPUState *env, uint64_t valop, uint64_t shiftop)
     if (shift >= 64) {
         if (val) {
             SET_QC();
-            val = (val >> 63) & ~SIGNBIT64;
+            val = (val >> 63) ^ ~SIGNBIT64;
         }
     } else if (shift <= -64) {
         val >>= 63;
commit 4c9b70aeca70b3e0a68a771727f388551620b3ed
Author: Juha Riihimäki <juha.riihimaki at nokia.com>
Date:   Tue Dec 7 14:13:42 2010 +0000

    target-arm: Fix VQSHL of signed 64 bit values
    
    Add a missing '-' which meant that we were misinterpreting the shift
    argument for VQSHL of 64 bit signed values and treating almost every
    shift value as if it were an extremely large right shift.
    
    Signed-off-by: Juha Riihimäki <juha.riihimaki at nokia.com>
    Reviewed-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c
index 5e6452b..d29b884 100644
--- a/target-arm/neon_helper.c
+++ b/target-arm/neon_helper.c
@@ -610,7 +610,7 @@ uint64_t HELPER(neon_qshl_s64)(CPUState *env, uint64_t valop, uint64_t shiftop)
             SET_QC();
             val = (val >> 63) & ~SIGNBIT64;
         }
-    } else if (shift <= 64) {
+    } else if (shift <= -64) {
         val >>= 63;
     } else if (shift < 0) {
         val >>= -shift;
commit def126ce37b037afc55878197159d9ddcb24a9e4
Author: Juha Riihimäki <juha.riihimaki at nokia.com>
Date:   Tue Dec 7 14:13:41 2010 +0000

    target-arm: Fix arguments passed to VQSHL helpers
    
    Correct the arguments passed when generating neon qshl_{u,s}64()
    helpers so that we use the correct registers.
    
    Signed-off-by: Juha Riihimäki <juha.riihimaki at nokia.com>
    Reviewed-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/target-arm/translate.c b/target-arm/translate.c
index 24b4fb6..8d494ec 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -4236,9 +4236,9 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                 case 9: /* VQSHL */
                     if (u) {
                         gen_helper_neon_qshl_u64(cpu_V0, cpu_env,
-                                                 cpu_V0, cpu_V0);
+                                                 cpu_V1, cpu_V0);
                     } else {
-                        gen_helper_neon_qshl_s64(cpu_V1, cpu_env,
+                        gen_helper_neon_qshl_s64(cpu_V0, cpu_env,
                                                  cpu_V1, cpu_V0);
                     }
                     break;
commit 1a855029af40df40144a322bba0e1e61c68eed2a
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Mon Dec 27 19:54:49 2010 +0100

    target-arm: fix bug in translation of REVSH
    
    The translation of REVSH shifted the low byte 8 steps left before performing
    an 8-bit sign extend, causing this part of the expression to alwas be 0.
    
    Reported-by: Johan Bengtsson <teofrastius at gmail.com>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/target-arm/translate.c b/target-arm/translate.c
index d4a0666..24b4fb6 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -250,13 +250,9 @@ static void gen_rev16(TCGv var)
 /* Byteswap low halfword and sign extend.  */
 static void gen_revsh(TCGv var)
 {
-    TCGv tmp = new_tmp();
-    tcg_gen_shri_i32(tmp, var, 8);
-    tcg_gen_andi_i32(tmp, tmp, 0x00ff);
-    tcg_gen_shli_i32(var, var, 8);
-    tcg_gen_ext8s_i32(var, var);
-    tcg_gen_or_i32(var, var, tmp);
-    dead_tmp(tmp);
+    tcg_gen_ext16u_i32(var, var);
+    tcg_gen_bswap16_i32(var, var);
+    tcg_gen_ext16s_i32(var, var);
 }
 
 /* Unsigned bitfield extract.  */
commit 5697f6ae4183f3b3320a1fe677e3404a05e75783
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Mon Dec 27 18:29:20 2010 +0100

    Fix a missing trailing newline
    
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/vl.c b/vl.c
index 768dbf4..c605347 100644
--- a/vl.c
+++ b/vl.c
@@ -2603,7 +2603,7 @@ int main(int argc, char **argv, char **envp)
 		     if (p != NULL) {
 		        *p++ = 0;
 			if (strncmp(p, "process=", 8)) {
-			    fprintf(stderr, "Unknown subargument %s to -name", p);
+			    fprintf(stderr, "Unknown subargument %s to -name\n", p);
 			    exit(1);
 			}
 			p += 8;
commit 4cdc1cd137e0b98766916a7cdf2d5a9b3c6632fa
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Sat Dec 25 22:56:32 2010 +0100

    target-mips: fix host CPU consumption when guest is idle
    
    When the CPU is in wait state, do not wake-up if an interrupt can't be
    taken. This avoid host CPU running at 100% if a device (e.g. timer) has
    an interrupt line left enabled.
    
    Also factorize code to check if interrupts are enabled in
    cpu_mips_hw_interrupts_pending().
    
    Based on a patch from Edgar E. Iglesias <edgar.iglesias at gmail.com>
    
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>
    Acked-by: Edgar E. Iglesias <edgar.iglesias at gmail.com>

diff --git a/cpu-exec.c b/cpu-exec.c
index 39e5eea..8c9fb8b 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -454,11 +454,7 @@ int cpu_exec(CPUState *env1)
                     }
 #elif defined(TARGET_MIPS)
                     if ((interrupt_request & CPU_INTERRUPT_HARD) &&
-                        cpu_mips_hw_interrupts_pending(env) &&
-                        (env->CP0_Status & (1 << CP0St_IE)) &&
-                        !(env->CP0_Status & (1 << CP0St_EXL)) &&
-                        !(env->CP0_Status & (1 << CP0St_ERL)) &&
-                        !(env->hflags & MIPS_HFLAG_DM)) {
+                        cpu_mips_hw_interrupts_pending(env)) {
                         /* Raise it */
                         env->exception_index = EXCP_EXT_INTERRUPT;
                         env->error_code = 0;
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index c1f211f..2419aa9 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -532,6 +532,14 @@ static inline int cpu_mips_hw_interrupts_pending(CPUState *env)
     int32_t status;
     int r;
 
+    if (!(env->CP0_Status & (1 << CP0St_IE)) ||
+        (env->CP0_Status & (1 << CP0St_EXL)) ||
+        (env->CP0_Status & (1 << CP0St_ERL)) ||
+        (env->hflags & MIPS_HFLAG_DM)) {
+        /* Interrupts are disabled */
+        return 0;
+    }
+
     pending = env->CP0_Cause & CP0Ca_IP_mask;
     status = env->CP0_Status & CP0Ca_IP_mask;
 
diff --git a/target-mips/exec.h b/target-mips/exec.h
index af61b54..1273654 100644
--- a/target-mips/exec.h
+++ b/target-mips/exec.h
@@ -19,10 +19,22 @@ register struct CPUMIPSState *env asm(AREG0);
 
 static inline int cpu_has_work(CPUState *env)
 {
-    return (env->interrupt_request &
-            (CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER));
-}
+    int has_work = 0;
+
+    /* It is implementation dependent if non-enabled interrupts
+       wake-up the CPU, however most of the implementations only
+       check for interrupts that can be taken. */
+    if ((env->interrupt_request & CPU_INTERRUPT_HARD) &&
+        cpu_mips_hw_interrupts_pending(env)) {
+        has_work = 1;
+    }
 
+    if (env->interrupt_request & CPU_INTERRUPT_TIMER) {
+        has_work = 1;
+    }
+
+    return has_work;
+}
 
 static inline int cpu_halted(CPUState *env)
 {
commit 6c33286ad3a432627d763ee93aa42200cbb68269
Author: Alexander Graf <agraf at suse.de>
Date:   Wed Nov 17 13:01:04 2010 +0100

    s390: compile fixes
    
    The s390 target doesn't compile out of the box anymore. This patch fixes all
    the obvious glitches that got introduced in the last few weeks.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/hw/s390-virtio-bus.h b/hw/s390-virtio-bus.h
index 41558c9..669b610 100644
--- a/hw/s390-virtio-bus.h
+++ b/hw/s390-virtio-bus.h
@@ -17,6 +17,8 @@
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 
+#include "virtio-net.h"
+
 #define VIRTIO_DEV_OFFS_TYPE		0	/* 8 bits */
 #define VIRTIO_DEV_OFFS_NUM_VQ		1	/* 8 bits */
 #define VIRTIO_DEV_OFFS_FEATURE_LEN	2	/* 8 bits */
diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c
index e7aec14..f29b624 100644
--- a/hw/s390-virtio.c
+++ b/hw/s390-virtio.c
@@ -19,6 +19,7 @@
 
 #include "hw.h"
 #include "block.h"
+#include "blockdev.h"
 #include "sysemu.h"
 #include "net.h"
 #include "boards.h"
diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index 9bf6abb..adf4a9e 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -119,7 +119,7 @@ int kvm_arch_put_registers(CPUState *env, int level)
 
 int kvm_arch_get_registers(CPUState *env)
 {
-    uint32_t ret;
+    int ret;
     struct kvm_regs regs;
     int i;
 
diff --git a/target-s390x/translate.c b/target-s390x/translate.c
index 881d8c4..d33bfb1 100644
--- a/target-s390x/translate.c
+++ b/target-s390x/translate.c
@@ -36,7 +36,7 @@ void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
         }
     }
     for (i = 0; i < 16; i++) {
-        cpu_fprintf(f, "F%02d=%016lx", i, env->fregs[i]);
+        cpu_fprintf(f, "F%02d=%016lx", i, (long)env->fregs[i].i);
         if ((i % 4) == 3) {
             cpu_fprintf(f, "\n");
         } else {
commit 9ed5726c043958359b0f1fa44ab3e4f25f9d9a47
Author: Nathan Froyd <froydnj at codesourcery.com>
Date:   Fri Oct 29 07:48:46 2010 -0700

    target-mips: fix translation of MT instructions
    
    The translation of dmt/emt/dvpe/evpe was doing the moral equivalent of:
    
      int x;
      ...		/* no initialization of x */
      x = f (x);
    
    which confused later bits of TCG rather badly, leading to crashes.
    
    Fix the helpers to only return results (those instructions have no
    inputs), and fix the translation code accordingly.
    
    Signed-off-by: Nathan Froyd <froydnj at codesourcery.com>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/target-mips/helper.h b/target-mips/helper.h
index cb13fb2..297ab64 100644
--- a/target-mips/helper.h
+++ b/target-mips/helper.h
@@ -154,10 +154,10 @@ DEF_HELPER_2(mttlo, void, tl, i32)
 DEF_HELPER_2(mtthi, void, tl, i32)
 DEF_HELPER_2(mttacx, void, tl, i32)
 DEF_HELPER_1(mttdsp, void, tl)
-DEF_HELPER_1(dmt, tl, tl)
-DEF_HELPER_1(emt, tl, tl)
-DEF_HELPER_1(dvpe, tl, tl)
-DEF_HELPER_1(evpe, tl, tl)
+DEF_HELPER_0(dmt, tl)
+DEF_HELPER_0(emt, tl)
+DEF_HELPER_0(dvpe, tl)
+DEF_HELPER_0(evpe, tl)
 #endif /* !CONFIG_USER_ONLY */
 
 /* microMIPS functions */
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 41abd57..ec6864d 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -1554,40 +1554,28 @@ void helper_mttdsp(target_ulong arg1)
 }
 
 /* MIPS MT functions */
-target_ulong helper_dmt(target_ulong arg1)
+target_ulong helper_dmt(void)
 {
     // TODO
-    arg1 = 0;
-    // rt = arg1
-
-    return arg1;
+     return 0;
 }
 
-target_ulong helper_emt(target_ulong arg1)
+target_ulong helper_emt(void)
 {
     // TODO
-    arg1 = 0;
-    // rt = arg1
-
-    return arg1;
+    return 0;
 }
 
-target_ulong helper_dvpe(target_ulong arg1)
+target_ulong helper_dvpe(void)
 {
     // TODO
-    arg1 = 0;
-    // rt = arg1
-
-    return arg1;
+    return 0;
 }
 
-target_ulong helper_evpe(target_ulong arg1)
+target_ulong helper_evpe(void)
 {
     // TODO
-    arg1 = 0;
-    // rt = arg1
-
-    return arg1;
+    return 0;
 }
 #endif /* !CONFIG_USER_ONLY */
 
diff --git a/target-mips/translate.c b/target-mips/translate.c
index ba45eb0..cce77be 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -12033,22 +12033,22 @@ static void decode_opc (CPUState *env, DisasContext *ctx, int *is_branch)
                 switch (op2) {
                 case OPC_DMT:
                     check_insn(env, ctx, ASE_MT);
-                    gen_helper_dmt(t0, t0);
+                    gen_helper_dmt(t0);
                     gen_store_gpr(t0, rt);
                     break;
                 case OPC_EMT:
                     check_insn(env, ctx, ASE_MT);
-                    gen_helper_emt(t0, t0);
+                    gen_helper_emt(t0);
                     gen_store_gpr(t0, rt);
                     break;
                 case OPC_DVPE:
                     check_insn(env, ctx, ASE_MT);
-                    gen_helper_dvpe(t0, t0);
+                    gen_helper_dvpe(t0);
                     gen_store_gpr(t0, rt);
                     break;
                 case OPC_EVPE:
                     check_insn(env, ctx, ASE_MT);
-                    gen_helper_evpe(t0, t0);
+                    gen_helper_evpe(t0);
                     gen_store_gpr(t0, rt);
                     break;
                 case OPC_DI:
commit cbb608a5c8ff918188545edb28127f63db76bd1e
Author: Brad <brad at comstyle.com>
Date:   Mon Dec 20 21:25:40 2010 -0500

    Use mmap() within code_gen_alloc() for OpenBSD.
    
    Signed-off-by: Brad Smith <brad at comstyle.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/exec.c b/exec.c
index a338495..49c28b1 100644
--- a/exec.c
+++ b/exec.c
@@ -517,7 +517,8 @@ static void code_gen_alloc(unsigned long tb_size)
             exit(1);
         }
     }
-#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) \
+    || defined(__DragonFly__) || defined(__OpenBSD__)
     {
         int flags;
         void *addr = NULL;
commit 7ae63a517fb50fe32b8ce88bfc18a1a1ed056189
Author: Brad <brad at comstyle.com>
Date:   Mon Dec 20 21:24:32 2010 -0500

    Add OpenBSD to ifdef list since it has CLOCK_MONOTONIC.
    
    Signed-off-by: Brad Smith <brad at comstyle.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/qemu-timer-common.c b/qemu-timer-common.c
index fff4399..755e300 100644
--- a/qemu-timer-common.c
+++ b/qemu-timer-common.c
@@ -50,7 +50,8 @@ static void __attribute__((constructor)) init_get_clock(void)
 {
     use_rt_clock = 0;
 #if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 500000) \
-    || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
+    || defined(__DragonFly__) || defined(__FreeBSD_kernel__) \
+    || defined(__OpenBSD__)
     {
         struct timespec ts;
         if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
commit 5f668643dc6ef3e59d5bc9b86fdf6778c59c98f2
Author: Brad <brad at comstyle.com>
Date:   Mon Dec 20 21:23:15 2010 -0500

    Add support for OpenBSD to QEMU's tap driver.
    
    Signed-off-by: Brad Smith <brad at comstyle.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/net/tap-bsd.c b/net/tap-bsd.c
index efccfe0..2f3efde 100644
--- a/net/tap-bsd.c
+++ b/net/tap-bsd.c
@@ -43,8 +43,8 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required
     char *dev;
     struct stat s;
 
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
-    /* if no ifname is given, always start the search from tap0. */
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__)
+    /* if no ifname is given, always start the search from tap0/tun0. */
     int i;
     char dname[100];
 
@@ -52,7 +52,11 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required
         if (*ifname) {
             snprintf(dname, sizeof dname, "/dev/%s", ifname);
         } else {
+#if defined(__OpenBSD__)
+            snprintf(dname, sizeof dname, "/dev/tun%d", i);
+#else
             snprintf(dname, sizeof dname, "/dev/tap%d", i);
+#endif
         }
         TFR(fd = open(dname, O_RDWR));
         if (fd >= 0) {
commit 4a1e19ae05a3f03fdd0896e8f26efe94b2ff60a2
Author: Aurelien Jarno <aurelien at aurel32.net>
Date:   Tue Dec 21 19:32:49 2010 +0100

    tcg-arm: fix __clear_cache() warning
    
    Use __builtin___clear_cache() instead of __clear_cache() to avoid having
    to define the function as extern. Fix the following warning:
    
    | In file included from qemu/cpus.c:34:
    | qemu/exec-all.h: In function 'tb_set_jmp_target1':
    | qemu/exec-all.h:208: error: nested extern declaration of '__clear_cache'
    | make[1]: *** [cpus.o] Error 1
    | make: *** [subdir-i386-softmmu] Error 2
    
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/exec-all.h b/exec-all.h
index c457058..6821b17 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -204,9 +204,7 @@ static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr
 #elif defined(__arm__)
 static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr)
 {
-#if QEMU_GNUC_PREREQ(4, 1)
-    void __clear_cache(char *beg, char *end);
-#else
+#if !QEMU_GNUC_PREREQ(4, 1)
     register unsigned long _beg __asm ("a1");
     register unsigned long _end __asm ("a2");
     register unsigned long _flg __asm ("a3");
@@ -218,7 +216,7 @@ static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr
         | (((addr - (jmp_addr + 8)) >> 2) & 0xffffff);
 
 #if QEMU_GNUC_PREREQ(4, 1)
-    __clear_cache((char *) jmp_addr, (char *) jmp_addr + 4);
+    __builtin___clear_cache((char *) jmp_addr, (char *) jmp_addr + 4);
 #else
     /* flush icache */
     _beg = jmp_addr;
commit fcd61af6631fb98c4c12e865572d4d81d73728d0
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Thu Dec 16 19:33:22 2010 +0100

    qdev: sysbus_get_default must not return a NULL pointer (fix regression)
    
    Every system should have some sort of main system bus,
    so sysbus_get_default should always return a valid bus.
    
    Without this patch, at least mipssim and malta no longer
    start but raise a null pointer access exception (caused by
    commit ec990eb622ad46df5ddcb1e94c418c271894d416).
    
    Cc: Anthony Liguori <anthony at codemonkey.ws>
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Aurelien Jarno <aurelien at aurel32.net>

diff --git a/hw/qdev.c b/hw/qdev.c
index 10e28df..6fc9b02 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -107,10 +107,7 @@ DeviceState *qdev_create(BusState *bus, const char *name)
     DeviceInfo *info;
 
     if (!bus) {
-        if (!main_system_bus) {
-            main_system_bus = qbus_create(&system_bus_info, NULL, "main-system-bus");
-        }
-        bus = main_system_bus;
+        bus = sysbus_get_default();
     }
 
     info = qdev_find_info(bus->info, name);
@@ -311,6 +308,10 @@ 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");
+    }
     return main_system_bus;
 }
 
commit e0087e618552c7bc77485561ed96ec2a4f01404a
Author: Bob Breuer <breuerr at mc.net>
Date:   Mon Dec 20 11:55:33 2010 -0600

    sparc32: ledma extra registers need tracing too
    
    Also trace the extra registers, and update the comments with new
    info from Artyom Tarasenko.
    
    Signed-off-by: Bob Breuer <breuerr at mc.net>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c
index 56be8c8..e75694b 100644
--- a/hw/sparc32_dma.c
+++ b/hw/sparc32_dma.c
@@ -44,7 +44,7 @@
 /* We need the mask, because one instance of the device is not page
    aligned (ledma, start address 0x0010) */
 #define DMA_MASK (DMA_SIZE - 1)
-/* ledma has more than 4 registers, Solaris reads the 5th one */
+/* OBP says 0x20 bytes for ledma, the extras are aliased to espdma */
 #define DMA_ETH_SIZE (8 * sizeof(uint32_t))
 #define DMA_MAX_REG_OFFSET (2 * DMA_SIZE - 1)
 
@@ -170,7 +170,10 @@ static uint32_t dma_mem_readl(void *opaque, target_phys_addr_t addr)
     uint32_t saddr;
 
     if (s->is_ledma && (addr > DMA_MAX_REG_OFFSET)) {
-        return 0; /* extra mystery register(s) */
+        /* aliased to espdma, but we can't get there from here */
+        /* buggy driver if using undocumented behavior, just return 0 */
+        trace_sparc32_dma_mem_readl(addr, 0);
+        return 0;
     }
     saddr = (addr & DMA_MASK) >> 2;
     trace_sparc32_dma_mem_readl(addr, s->dmaregs[saddr]);
@@ -183,7 +186,9 @@ static void dma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
     uint32_t saddr;
 
     if (s->is_ledma && (addr > DMA_MAX_REG_OFFSET)) {
-        return; /* extra mystery register(s) */
+        /* aliased to espdma, but we can't get there from here */
+        trace_sparc32_dma_mem_writel(addr, 0, val);
+        return;
     }
     saddr = (addr & DMA_MASK) >> 2;
     trace_sparc32_dma_mem_writel(addr, s->dmaregs[saddr], val);
commit ac6c41204fd33116b8943682bffe47e113c1cc6b
Author: Andreas Färber <andreas.faerber at web.de>
Date:   Sun Dec 19 17:22:41 2010 +0100

    target-i386: Fix accidental use of SoftFloat uint64 type
    
    softfloat.h's uint64 type has least-width semantics.
    Use uint64_t instead since that is used in helpers.
    
    v4:
    * Summary change.
    
    v3:
    * Split off.
    
    Signed-off-by: Andreas Färber <andreas.faerber at web.de>
    Acked-by: Huang Ying <ying.huang at intel.com>
    Acked-by: Juan Quintela <quintela at redhat.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 06e40f3..f0c07cd 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -737,10 +737,10 @@ typedef struct CPUX86State {
        user */
     struct DeviceState *apic_state;
 
-    uint64 mcg_cap;
-    uint64 mcg_status;
-    uint64 mcg_ctl;
-    uint64 mce_banks[MCE_BANKS_DEF*4];
+    uint64_t mcg_cap;
+    uint64_t mcg_status;
+    uint64_t mcg_ctl;
+    uint64_t mce_banks[MCE_BANKS_DEF*4];
 
     uint64_t tsc_aux;
 
commit c910cf96dc8a2a1d3ee0a695979770d13538806f
Author: Andreas Färber <andreas.faerber at web.de>
Date:   Sun Dec 19 17:22:40 2010 +0100

    wdt_ib700: Fix accidental use of SoftFloat int64 type
    
    softfloat.h's int64 type has least-width semantics.
    Since we're assigning an int64_t, use plain int64_t.
    
    v4:
    * Summary change.
    
    v3:
    * Split off.
    
    Signed-off-by: Andreas Färber <andreas.faerber at web.de>
    Acked-by: Richard W.M. Jones <rjones at redhat.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/wdt_ib700.c b/hw/wdt_ib700.c
index b6235eb..1248464 100644
--- a/hw/wdt_ib700.c
+++ b/hw/wdt_ib700.c
@@ -53,7 +53,7 @@ static void ib700_write_enable_reg(void *vp, uint32_t addr, uint32_t data)
         30, 28, 26, 24, 22, 20, 18, 16,
         14, 12, 10,  8,  6,  4,  2,  0
     };
-    int64 timeout;
+    int64_t timeout;
 
     ib700_debug("addr = %x, data = %x\n", addr, data);
 
commit f5095c639fe2861b6401be6e26fa3ffb9d30eba4
Author: Andreas Färber <andreas.faerber at web.de>
Date:   Sun Dec 19 17:22:39 2010 +0100

    apic: Fix accidental use of SoftFloat uint32 type
    
    softfloat.h's uint32 type has least-width semantics.
    Surrounding code uses uint32_t, so use uint32_t here, too.
    
    v4:
    * Summary change.
    
    v3:
    * Split off.
    
    Signed-off-by: Andreas Färber <andreas.faerber at web.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/apic.c b/hw/apic.c
index a5a53fb..ff581f0 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -765,7 +765,7 @@ static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
     return val;
 }
 
-static void apic_send_msi(target_phys_addr_t addr, uint32 data)
+static void apic_send_msi(target_phys_addr_t addr, uint32_t data)
 {
     uint8_t dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
     uint8_t vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
commit 4fd37a98d1248bae54a9f71ee1c252d2b2f1efd5
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Dec 19 14:05:43 2010 +0000

    Avoid a warning from OpenBSD linker
    
    Avoid the warning below by using snprintf:
    ../libhw64/vl.o(.text+0x78d4): In function `get_boot_devices_list':
    /src/qemu/vl.c:763: warning: sprintf() is often misused, please use snprintf()
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/vl.c b/vl.c
index c4d3fc0..768dbf4 100644
--- a/vl.c
+++ b/vl.c
@@ -759,8 +759,10 @@ char *get_boot_devices_list(uint32_t *size)
         }
 
         if (i->suffix && devpath) {
-            bootpath = qemu_malloc(strlen(devpath) + strlen(i->suffix) + 1);
-            sprintf(bootpath, "%s%s", devpath, i->suffix);
+            size_t bootpathlen = strlen(devpath) + strlen(i->suffix) + 1;
+
+            bootpath = qemu_malloc(bootpathlen);
+            snprintf(bootpath, bootpathlen, "%s%s", devpath, i->suffix);
             qemu_free(devpath);
         } else if (devpath) {
             bootpath = devpath;
commit d41160a3e64b26c9d78ecfd78b0e7ef3e878d475
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Dec 19 13:42:56 2010 +0000

    Sparc: implement monitor command 'info tlb'
    
    Use existing dump_mmu() to implement monitor command 'info tlb'.
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hmp-commands.hx b/hmp-commands.hx
index dd3db36..4befbe2 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1190,7 +1190,7 @@ show i8259 (PIC) state
 @item info pci
 show emulated PCI device info
 @item info tlb
-show virtual to physical memory mappings (i386 only)
+show virtual to physical memory mappings (i386, SH4 and SPARC only)
 @item info mem
 show the active virtual memory mappings (i386 only)
 @item info jit
diff --git a/monitor.c b/monitor.c
index aae81bb..5d74fe3 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2272,6 +2272,15 @@ static void tlb_info(Monitor *mon)
 
 #endif
 
+#if defined(TARGET_SPARC)
+static void tlb_info(Monitor *mon)
+{
+    CPUState *env1 = mon_get_cpu();
+
+    dump_mmu((FILE*)mon, (fprintf_function)monitor_printf, env1);
+}
+#endif
+
 static void do_info_kvm_print(Monitor *mon, const QObject *data)
 {
     QDict *qdict;
@@ -2744,7 +2753,7 @@ static const mon_cmd_t info_cmds[] = {
         .user_print = do_pci_info_print,
         .mhandler.info_new = do_pci_info,
     },
-#if defined(TARGET_I386) || defined(TARGET_SH4)
+#if defined(TARGET_I386) || defined(TARGET_SH4) || defined(TARGET_SPARC)
     {
         .name       = "tlb",
         .args_type  = "",
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index 1be66e7..7225b2e 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -448,7 +448,7 @@ int cpu_sparc_handle_mmu_fault(CPUSPARCState *env1, target_ulong address, int rw
                                int mmu_idx, int is_softmmu);
 #define cpu_handle_mmu_fault cpu_sparc_handle_mmu_fault
 target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev);
-void dump_mmu(CPUSPARCState *env);
+void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env);
 
 /* translate.c */
 void gen_intermediate_code_init(CPUSPARCState *env);
diff --git a/target-sparc/helper.c b/target-sparc/helper.c
index 7e45d7a..6b337ca 100644
--- a/target-sparc/helper.c
+++ b/target-sparc/helper.c
@@ -320,47 +320,45 @@ target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev)
     return 0;
 }
 
-#ifdef DEBUG_MMU
-void dump_mmu(CPUState *env)
+void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
 {
     target_ulong va, va1, va2;
     unsigned int n, m, o;
     target_phys_addr_t pde_ptr, pa;
     uint32_t pde;
 
-    printf("MMU dump:\n");
     pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
     pde = ldl_phys(pde_ptr);
-    printf("Root ptr: " TARGET_FMT_plx ", ctx: %d\n",
-           (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]);
+    (*cpu_fprintf)(f, "Root ptr: " TARGET_FMT_plx ", ctx: %d\n",
+                   (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]);
     for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
         pde = mmu_probe(env, va, 2);
         if (pde) {
             pa = cpu_get_phys_page_debug(env, va);
-            printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
-                   " PDE: " TARGET_FMT_lx "\n", va, pa, pde);
+            (*cpu_fprintf)(f, "VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
+                           " PDE: " TARGET_FMT_lx "\n", va, pa, pde);
             for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
                 pde = mmu_probe(env, va1, 1);
                 if (pde) {
                     pa = cpu_get_phys_page_debug(env, va1);
-                    printf(" VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
-                           " PDE: " TARGET_FMT_lx "\n", va1, pa, pde);
+                    (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: "
+                                   TARGET_FMT_plx " PDE: " TARGET_FMT_lx "\n",
+                                   va1, pa, pde);
                     for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
                         pde = mmu_probe(env, va2, 0);
                         if (pde) {
                             pa = cpu_get_phys_page_debug(env, va2);
-                            printf("  VA: " TARGET_FMT_lx ", PA: "
-                                   TARGET_FMT_plx " PTE: " TARGET_FMT_lx "\n",
-                                   va2, pa, pde);
+                            (*cpu_fprintf)(f, "  VA: " TARGET_FMT_lx ", PA: "
+                                           TARGET_FMT_plx " PTE: "
+                                           TARGET_FMT_lx "\n",
+                                           va2, pa, pde);
                         }
                     }
                 }
             }
         }
     }
-    printf("MMU dump ends\n");
 }
-#endif /* DEBUG_MMU */
 
 #else /* !TARGET_SPARC64 */
 
@@ -622,18 +620,19 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
     return 1;
 }
 
-#ifdef DEBUG_MMU
-void dump_mmu(CPUState *env)
+void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
 {
     unsigned int i;
     const char *mask;
 
-    printf("MMU contexts: Primary: %" PRId64 ", Secondary: %" PRId64 "\n",
-           env->dmmu.mmu_primary_context, env->dmmu.mmu_secondary_context);
+    (*cpu_fprintf)(f, "MMU contexts: Primary: %" PRId64 ", Secondary: %"
+                   PRId64 "\n",
+                   env->dmmu.mmu_primary_context,
+                   env->dmmu.mmu_secondary_context);
     if ((env->lsu & DMMU_E) == 0) {
-        printf("DMMU disabled\n");
+        (*cpu_fprintf)(f, "DMMU disabled\n");
     } else {
-        printf("DMMU dump:\n");
+        (*cpu_fprintf)(f, "DMMU dump\n");
         for (i = 0; i < 64; i++) {
             switch ((env->dtlb[i].tte >> 61) & 3) {
             default:
@@ -651,24 +650,25 @@ void dump_mmu(CPUState *env)
                 break;
             }
             if ((env->dtlb[i].tte & 0x8000000000000000ULL) != 0) {
-                printf("[%02u] VA: %" PRIx64 ", PA: %" PRIx64
-                       ", %s, %s, %s, %s, ctx %" PRId64 " %s\n",
-                       i,
-                       env->dtlb[i].tag & (uint64_t)~0x1fffULL,
-                       env->dtlb[i].tte & (uint64_t)0x1ffffffe000ULL,
-                       mask,
-                       env->dtlb[i].tte & 0x4? "priv": "user",
-                       env->dtlb[i].tte & 0x2? "RW": "RO",
-                       env->dtlb[i].tte & 0x40? "locked": "unlocked",
-                       env->dtlb[i].tag & (uint64_t)0x1fffULL,
-                       TTE_IS_GLOBAL(env->dtlb[i].tte)? "global" : "local");
+                (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %" PRIx64
+                               ", %s, %s, %s, %s, ctx %" PRId64 " %s\n",
+                               i,
+                               env->dtlb[i].tag & (uint64_t)~0x1fffULL,
+                               env->dtlb[i].tte & (uint64_t)0x1ffffffe000ULL,
+                               mask,
+                               env->dtlb[i].tte & 0x4? "priv": "user",
+                               env->dtlb[i].tte & 0x2? "RW": "RO",
+                               env->dtlb[i].tte & 0x40? "locked": "unlocked",
+                               env->dtlb[i].tag & (uint64_t)0x1fffULL,
+                               TTE_IS_GLOBAL(env->dtlb[i].tte)?
+                               "global" : "local");
             }
         }
     }
     if ((env->lsu & IMMU_E) == 0) {
-        printf("IMMU disabled\n");
+        (*cpu_fprintf)(f, "IMMU disabled\n");
     } else {
-        printf("IMMU dump:\n");
+        (*cpu_fprintf)(f, "IMMU dump\n");
         for (i = 0; i < 64; i++) {
             switch ((env->itlb[i].tte >> 61) & 3) {
             default:
@@ -686,21 +686,21 @@ void dump_mmu(CPUState *env)
                 break;
             }
             if ((env->itlb[i].tte & 0x8000000000000000ULL) != 0) {
-                printf("[%02u] VA: %" PRIx64 ", PA: %" PRIx64
-                       ", %s, %s, %s, ctx %" PRId64 " %s\n",
-                       i,
-                       env->itlb[i].tag & (uint64_t)~0x1fffULL,
-                       env->itlb[i].tte & (uint64_t)0x1ffffffe000ULL,
-                       mask,
-                       env->itlb[i].tte & 0x4? "priv": "user",
-                       env->itlb[i].tte & 0x40? "locked": "unlocked",
-                       env->itlb[i].tag & (uint64_t)0x1fffULL,
-                       TTE_IS_GLOBAL(env->itlb[i].tte)? "global" : "local");
+                (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %" PRIx64
+                               ", %s, %s, %s, ctx %" PRId64 " %s\n",
+                               i,
+                               env->itlb[i].tag & (uint64_t)~0x1fffULL,
+                               env->itlb[i].tte & (uint64_t)0x1ffffffe000ULL,
+                               mask,
+                               env->itlb[i].tte & 0x4? "priv": "user",
+                               env->itlb[i].tte & 0x40? "locked": "unlocked",
+                               env->itlb[i].tag & (uint64_t)0x1fffULL,
+                               TTE_IS_GLOBAL(env->itlb[i].tte)?
+                               "global" : "local");
             }
         }
     }
 }
-#endif /* DEBUG_MMU */
 
 #endif /* TARGET_SPARC64 */
 #endif /* !CONFIG_USER_ONLY */
diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
index be3c1e0..4f753ba 100644
--- a/target-sparc/op_helper.c
+++ b/target-sparc/op_helper.c
@@ -180,7 +180,7 @@ static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr,
             replace_tlb_entry(&tlb[i], 0, 0, env1);
 #ifdef DEBUG_MMU
             DPRINTF_MMU("%s demap invalidated entry [%02u]\n", strmmu, i);
-            dump_mmu(env1);
+            dump_mmu(stdout, fprintf, env1);
 #endif
         }
     }
@@ -198,7 +198,7 @@ static void replace_tlb_1bit_lru(SparcTLBEntry *tlb,
             replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1);
 #ifdef DEBUG_MMU
             DPRINTF_MMU("%s lru replaced invalid entry [%i]\n", strmmu, i);
-            dump_mmu(env1);
+            dump_mmu(stdout, fprintf, env1);
 #endif
             return;
         }
@@ -217,7 +217,7 @@ static void replace_tlb_1bit_lru(SparcTLBEntry *tlb,
 #ifdef DEBUG_MMU
                 DPRINTF_MMU("%s lru replaced unlocked %s entry [%i]\n",
                             strmmu, (replace_used?"used":"unused"), i);
-                dump_mmu(env1);
+                dump_mmu(stdout, fprintf, env1);
 #endif
                 return;
             }
@@ -1959,7 +1959,7 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
                 break;
             }
 #ifdef DEBUG_MMU
-            dump_mmu(env);
+            dump_mmu(stdout, fprintf, env);
 #endif
         }
         break;
@@ -2011,7 +2011,7 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
                             reg, oldreg, env->mmuregs[reg]);
             }
 #ifdef DEBUG_MMU
-            dump_mmu(env);
+            dump_mmu(stdout, fprintf, env);
 #endif
         }
         break;
@@ -2912,7 +2912,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
                 DPRINTF_MMU("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n",
                             oldreg, env->lsu);
 #ifdef DEBUG_MMU
-                dump_mmu(env);
+                dump_mmu(stdout, fprintf, env1);
 #endif
                 tlb_flush(env, 1);
             }
@@ -2957,7 +2957,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
                             PRIx64 "\n", reg, oldreg, env->immuregs[reg]);
             }
 #ifdef DEBUG_MMU
-            dump_mmu(env);
+            dump_mmu(stdout, fprintf, env);
 #endif
             return;
         }
@@ -2974,7 +2974,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
 
 #ifdef DEBUG_MMU
             DPRINTF_MMU("immu data access replaced entry [%i]\n", i);
-            dump_mmu(env);
+            dump_mmu(stdout, fprintf, env);
 #endif
             return;
         }
@@ -3030,7 +3030,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
                             PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]);
             }
 #ifdef DEBUG_MMU
-            dump_mmu(env);
+            dump_mmu(stdout, fprintf, env);
 #endif
             return;
         }
@@ -3045,7 +3045,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
 
 #ifdef DEBUG_MMU
             DPRINTF_MMU("dmmu data access replaced entry [%i]\n", i);
-            dump_mmu(env);
+            dump_mmu(stdout, fprintf, env);
 #endif
             return;
         }
commit cdfe17df88b335269ddabc7ade7a6148a1a20f0d
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Dec 19 10:43:09 2010 +0000

    ahci: delete write-only variables (v2)
    
    Avoid these warnings with GCC 4.6.0:
    /src/qemu/hw/ide/ahci.c: In function 'ahci_reset_port':
    /src/qemu/hw/ide/ahci.c:810:14: error: variable 'tfd' set but not used [-Werror=unused-but-set-variable]
    /src/qemu/hw/ide/ahci.c: In function 'handle_cmd':
    /src/qemu/hw/ide/ahci.c:1103:19: error: variable 'pr' set but not used [-Werror=unused-but-set-variable]
    
    In the tfd variable case, fix the logic also.
    
    CC: Alexander Graf <agraf at suse.de>
    CC: Kevin Wolf <kwolf at redhat.com>
    Acked-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 8ae236a..968fdce 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -807,7 +807,6 @@ static void ahci_reset_port(AHCIState *s, int port)
     AHCIPortRegs *pr = &d->port_regs;
     IDEState *ide_state = &d->port.ifs[0];
     uint8_t init_fis[0x20];
-    uint32_t tfd;
     int i;
 
     DPRINTF(port, "reset port\n");
@@ -848,7 +847,7 @@ static void ahci_reset_port(AHCIState *s, int port)
     s->dev[port].port_state = STATE_RUN;
     if (!ide_state->bs) {
         s->dev[port].port_regs.sig = 0;
-        tfd = (1 << 8) | SEEK_STAT | WRERR_STAT;
+        ide_state->status = SEEK_STAT | WRERR_STAT;
     } else if (ide_state->drive_kind == IDE_CD) {
         s->dev[port].port_regs.sig = SATA_SIGNATURE_CDROM;
         ide_state->lcyl = 0x14;
@@ -1100,7 +1099,6 @@ static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis,
 static int handle_cmd(AHCIState *s, int port, int slot)
 {
     IDEState *ide_state;
-    AHCIPortRegs *pr;
     uint32_t opts;
     uint64_t tbl_addr;
     AHCICmdHdr *cmd;
@@ -1113,7 +1111,6 @@ static int handle_cmd(AHCIState *s, int port, int slot)
         return -1;
     }
 
-    pr = &s->dev[port].port_regs;
     cmd = &((AHCICmdHdr *)s->dev[port].lst)[slot];
 
     if (!s->dev[port].lst) {
commit 6a0ee36a47f5b0d090316fe10ceada83136338da
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Dec 19 10:04:04 2010 +0000

    vga: Declare as little endian
    
    This patch replaces explicit bswaps with endianness hints to the
    mmio layer.
    
    CC: Alexander Graf <agraf at suse.de>
    Acked-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/vga.c b/hw/vga.c
index b5c8741..c632fd7 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -767,30 +767,18 @@ uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr)
 static uint32_t vga_mem_readw(void *opaque, target_phys_addr_t addr)
 {
     uint32_t v;
-#ifdef TARGET_WORDS_BIGENDIAN
-    v = vga_mem_readb(opaque, addr) << 8;
-    v |= vga_mem_readb(opaque, addr + 1);
-#else
     v = vga_mem_readb(opaque, addr);
     v |= vga_mem_readb(opaque, addr + 1) << 8;
-#endif
     return v;
 }
 
 static uint32_t vga_mem_readl(void *opaque, target_phys_addr_t addr)
 {
     uint32_t v;
-#ifdef TARGET_WORDS_BIGENDIAN
-    v = vga_mem_readb(opaque, addr) << 24;
-    v |= vga_mem_readb(opaque, addr + 1) << 16;
-    v |= vga_mem_readb(opaque, addr + 2) << 8;
-    v |= vga_mem_readb(opaque, addr + 3);
-#else
     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;
-#endif
     return v;
 }
 
@@ -931,28 +919,16 @@ 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)
 {
-#ifdef TARGET_WORDS_BIGENDIAN
-    vga_mem_writeb(opaque, addr, (val >> 8) & 0xff);
-    vga_mem_writeb(opaque, addr + 1, val & 0xff);
-#else
     vga_mem_writeb(opaque, addr, val & 0xff);
     vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-#endif
 }
 
 static void vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
-#ifdef TARGET_WORDS_BIGENDIAN
-    vga_mem_writeb(opaque, addr, (val >> 24) & 0xff);
-    vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
-    vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
-    vga_mem_writeb(opaque, addr + 3, val & 0xff);
-#else
     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);
-#endif
 }
 
 typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
@@ -2321,7 +2297,7 @@ void vga_init(VGACommonState *s)
 #endif /* CONFIG_BOCHS_VBE */
 
     vga_io_memory = cpu_register_io_memory(vga_mem_read, vga_mem_write, s,
-                                           DEVICE_NATIVE_ENDIAN);
+                                           DEVICE_LITTLE_ENDIAN);
     cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
                                  vga_io_memory);
     qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000);
commit 5d6b423c5cd6f9dfac30959ff1d5c088996719c3
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Sat Dec 18 17:34:26 2010 +0100

    win32: Fix CRLF problem in make_device_config.sh
    
    QEMU source code with CRLF line endings
    which is quite common on windows hosts
    fails with current make_device_config.sh.
    
    The awk script gets the name of the included
    file with \r, so instead of pci.mak it will
    search for pci.mak\r which of course does
    not work.
    
    Fix this by removing any \r.
    
    v2:
        Avoid using sub() and \r with awk because they are unsupported
        on some platforms. Use tr to remove \r. This new solution
        improves portability and was suggested by Paolo Bonzini.
    
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Acked-by: Andreas Färber <andreas.faerber at web.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/make_device_config.sh b/make_device_config.sh
index 8abadfe..596fc5b 100644
--- a/make_device_config.sh
+++ b/make_device_config.sh
@@ -18,7 +18,7 @@ process_includes () {
 
 f=$src
 while [ -n "$f" ] ; do
-  f=`awk '/^include / {ORS=" " ; print "'$src_dir'/" $2}' $f`
+  f=`tr -d '\r' < $f | awk '/^include / {ORS=" "; print "'$src_dir'/" $2}'`
   [ $? = 0 ] || exit 1
   all_includes="$all_includes $f"
 done
commit 86d1c3887f8665204e2c7454003ac71a6a52e806
Author: Bob Breuer <breuerr at mc.net>
Date:   Sat Dec 18 11:09:04 2010 -0600

    sparc32: ledma extra registers
    
    ledma has 0x20 bytes of registers according to OBP, and at least Solaris9
    reads the 5th register which is beyond what we've mapped.  So let's setup
    a flag (inspired by a previous patch from Blue Swirl) to identify ledma
    from espdma, and map another 16 bytes of registers which return 0.
    
    Signed-off-by: Bob Breuer <breuerr at mc.net>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c
index e78f025..56be8c8 100644
--- a/hw/sparc32_dma.c
+++ b/hw/sparc32_dma.c
@@ -44,6 +44,9 @@
 /* We need the mask, because one instance of the device is not page
    aligned (ledma, start address 0x0010) */
 #define DMA_MASK (DMA_SIZE - 1)
+/* ledma has more than 4 registers, Solaris reads the 5th one */
+#define DMA_ETH_SIZE (8 * sizeof(uint32_t))
+#define DMA_MAX_REG_OFFSET (2 * DMA_SIZE - 1)
 
 #define DMA_VER 0xa0000000
 #define DMA_INTR 1
@@ -65,6 +68,7 @@ struct DMAState {
     qemu_irq irq;
     void *iommu;
     qemu_irq gpio[2];
+    uint32_t is_ledma;
 };
 
 enum {
@@ -165,6 +169,9 @@ static uint32_t dma_mem_readl(void *opaque, target_phys_addr_t addr)
     DMAState *s = opaque;
     uint32_t saddr;
 
+    if (s->is_ledma && (addr > DMA_MAX_REG_OFFSET)) {
+        return 0; /* extra mystery register(s) */
+    }
     saddr = (addr & DMA_MASK) >> 2;
     trace_sparc32_dma_mem_readl(addr, s->dmaregs[saddr]);
     return s->dmaregs[saddr];
@@ -175,6 +182,9 @@ static void dma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
     DMAState *s = opaque;
     uint32_t saddr;
 
+    if (s->is_ledma && (addr > DMA_MAX_REG_OFFSET)) {
+        return; /* extra mystery register(s) */
+    }
     saddr = (addr & DMA_MASK) >> 2;
     trace_sparc32_dma_mem_writel(addr, s->dmaregs[saddr], val);
     switch (saddr) {
@@ -254,12 +264,14 @@ static int sparc32_dma_init1(SysBusDevice *dev)
 {
     DMAState *s = FROM_SYSBUS(DMAState, dev);
     int dma_io_memory;
+    int reg_size;
 
     sysbus_init_irq(dev, &s->irq);
 
     dma_io_memory = cpu_register_io_memory(dma_mem_read, dma_mem_write, s,
                                            DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, DMA_SIZE, dma_io_memory);
+    reg_size = s->is_ledma ? DMA_ETH_SIZE : DMA_SIZE;
+    sysbus_init_mmio(dev, reg_size, dma_io_memory);
 
     qdev_init_gpio_in(&dev->qdev, dma_set_irq, 1);
     qdev_init_gpio_out(&dev->qdev, s->gpio, 2);
@@ -275,6 +287,7 @@ static SysBusDeviceInfo sparc32_dma_info = {
     .qdev.reset = dma_reset,
     .qdev.props = (Property[]) {
         DEFINE_PROP_PTR("iommu_opaque", DMAState, iommu),
+        DEFINE_PROP_UINT32("is_ledma", DMAState, is_ledma, 0),
         DEFINE_PROP_END_OF_LIST(),
     }
 };
diff --git a/hw/sun4m.c b/hw/sun4m.c
index 4795b3f..30e8a21 100644
--- a/hw/sun4m.c
+++ b/hw/sun4m.c
@@ -378,13 +378,14 @@ static void *iommu_init(target_phys_addr_t addr, uint32_t version, qemu_irq irq)
 }
 
 static void *sparc32_dma_init(target_phys_addr_t daddr, qemu_irq parent_irq,
-                              void *iommu, qemu_irq *dev_irq)
+                              void *iommu, qemu_irq *dev_irq, int is_ledma)
 {
     DeviceState *dev;
     SysBusDevice *s;
 
     dev = qdev_create(NULL, "sparc32_dma");
     qdev_prop_set_ptr(dev, "iommu_opaque", iommu);
+    qdev_prop_set_uint32(dev, "is_ledma", is_ledma);
     qdev_init_nofail(dev);
     s = sysbus_from_qdev(dev);
     sysbus_connect_irq(s, 0, parent_irq);
@@ -862,10 +863,10 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size,
     }
 
     espdma = sparc32_dma_init(hwdef->dma_base, slavio_irq[18],
-                              iommu, &espdma_irq);
+                              iommu, &espdma_irq, 0);
 
     ledma = sparc32_dma_init(hwdef->dma_base + 16ULL,
-                             slavio_irq[16], iommu, &ledma_irq);
+                             slavio_irq[16], iommu, &ledma_irq, 1);
 
     if (graphic_depth != 8 && graphic_depth != 24) {
         fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth);
@@ -1524,10 +1525,11 @@ static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, ram_addr_t RAM_size,
                                     sbi_irq[0]);
 
     espdma = sparc32_dma_init(hwdef->espdma_base, sbi_irq[3],
-                              iounits[0], &espdma_irq);
+                              iounits[0], &espdma_irq, 0);
 
+    /* should be lebuffer instead */
     ledma = sparc32_dma_init(hwdef->ledma_base, sbi_irq[4],
-                             iounits[0], &ledma_irq);
+                             iounits[0], &ledma_irq, 0);
 
     if (graphic_depth != 8 && graphic_depth != 24) {
         fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth);
@@ -1707,10 +1709,10 @@ static void sun4c_hw_init(const struct sun4c_hwdef *hwdef, ram_addr_t RAM_size,
                        slavio_irq[1]);
 
     espdma = sparc32_dma_init(hwdef->dma_base, slavio_irq[2],
-                              iommu, &espdma_irq);
+                              iommu, &espdma_irq, 0);
 
     ledma = sparc32_dma_init(hwdef->dma_base + 16ULL,
-                             slavio_irq[3], iommu, &ledma_irq);
+                             slavio_irq[3], iommu, &ledma_irq, 1);
 
     if (graphic_depth != 8 && graphic_depth != 24) {
         fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth);
commit 4d22c6c2eef69f20e1f4a398e277d6c8dbc4e5b9
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Fri Dec 17 21:03:00 2010 +0000

    Fix warning on mingw32
    
    Avoid this warning like other uses of setsockopt:
    /src/qemu/net/socket.c: In function 'net_socket_mcast_create':
    /src/qemu/net/socket.c:210: warning: passing argument 4 of 'setsockopt' from incompatible pointer type
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/net/socket.c b/net/socket.c
index 916c2a8..3182b37 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -207,7 +207,8 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr
 
     /* If a bind address is given, only send packets from that address */
     if (localaddr != NULL) {
-        ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, localaddr, sizeof(*localaddr));
+        ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
+                         (const char *)localaddr, sizeof(*localaddr));
         if (ret < 0) {
             perror("setsockopt(IP_MULTICAST_IF)");
             goto fail;
commit 653af235c8df7516a94762fc81e639fc08e9f6d9
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Fri Dec 17 19:49:18 2010 +0100

    ide: Build fix for via.c
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/ide/via.c b/hw/ide/via.c
index 5b70bd2..0e90679 100644
--- a/hw/ide/via.c
+++ b/hw/ide/via.c
@@ -150,7 +150,7 @@ static void vt82c686b_init_ports(PCIIDEState *d) {
         bmdma_init(&d->bus[i], &d->bmdma[i]);
         d->bmdma[i].bus = &d->bus[i];
         qemu_add_vm_change_state_handler(d->bus[i].dma->ops->restart_cb,
-                                         &d->bmdma[i]->dma);
+                                         &d->bmdma[i].dma);
     }
 }
 
commit f56b18c08cd29bb47e4d6a72f97c44616bd0611e
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Fri Dec 17 19:43:41 2010 +0100

    ide: Fix build for cmd646.c
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>
    Acked-by: Andreas Färber <andreas.faerber at web.de>

diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c
index 89ba836..5d5464a 100644
--- a/hw/ide/cmd646.c
+++ b/hw/ide/cmd646.c
@@ -255,9 +255,9 @@ static int pci_cmd646_ide_initfn(PCIDevice *dev)
         ide_init2(&d->bus[i], irq[i]);
 
         bmdma_init(&d->bus[i], &d->bmdma[i]);
-        bm->bus = &d->bus[i];
+        d->bmdma[i].bus = &d->bus[i];
         qemu_add_vm_change_state_handler(d->bus[i].dma->ops->restart_cb,
-                                         &d->bmdma[i]->dma);
+                                         &d->bmdma[i].dma);
     }
 
     vmstate_register(&dev->qdev, 0, &vmstate_ide_pci, d);
commit e59d688ad112719cb264f395b1f5895866ebf309
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Fri Dec 17 15:58:20 2010 +0000

    docs: Fix missing carets in QED specification
    
    For some reason the carets ('^') in the QED specification disappeared.
    This patch puts them back.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/docs/specs/qed_spec.txt b/docs/specs/qed_spec.txt
index 446b5a2..1d5fa87 100644
--- a/docs/specs/qed_spec.txt
+++ b/docs/specs/qed_spec.txt
@@ -33,7 +33,7 @@ All fields are little-endian.
  }
 
 Field descriptions:
-* ''cluster_size'' must be a power of 2 in range [212, 226].
+* ''cluster_size'' must be a power of 2 in range [2^12, 2^26].
 * ''table_size'' must be a power of 2 in range [1, 16].
 * ''header_size'' is the number of clusters used by the header and any additional information stored before regular clusters.
 * ''features'', ''compat_features'', and ''autoclear_features'' are file format extension bitmaps.  They work as follows:
@@ -90,7 +90,7 @@ L1, L2, and data cluster offsets must be aligned to header.cluster_size.  The fo
 ===Data cluster offsets===
 * 0 - unallocated.  The data cluster is not yet allocated.
 
-Future format extensions may wish to store per-offset information.  The least significant 12 bits of an offset are reserved for this purpose and must be set to zero.  Image files with cluster_size > 212 will have more unused bits which should also be zeroed.
+Future format extensions may wish to store per-offset information.  The least significant 12 bits of an offset are reserved for this purpose and must be set to zero.  Image files with cluster_size > 2^12 will have more unused bits which should also be zeroed.
 
 ===Unallocated L2 tables and data clusters===
 Reads to an unallocated area of the image file access the backing file.  If there is no backing file, then zeroes are produced.  The backing file may be smaller than the image file and reads of unallocated areas beyond the end of the backing file produce zeroes.
commit 6d85a57e20825e72895c31eb69080df8d476edb2
Author: Jes Sorensen <Jes.Sorensen at redhat.com>
Date:   Fri Dec 17 16:02:40 2010 +0100

    Add proper -errno error return values to qcow2_open()
    
    In addition this adds missing braces to the function to be consistent
    with the coding style.
    
    Signed-off-by: Jes Sorensen <Jes.Sorensen at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/qcow2.c b/block/qcow2.c
index 4b41190..b6b094c 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -140,12 +140,14 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
 static int qcow2_open(BlockDriverState *bs, int flags)
 {
     BDRVQcowState *s = bs->opaque;
-    int len, i;
+    int len, i, ret = 0;
     QCowHeader header;
     uint64_t ext_end;
 
-    if (bdrv_pread(bs->file, 0, &header, sizeof(header)) != sizeof(header))
+    ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
+    if (ret < 0) {
         goto fail;
+    }
     be32_to_cpus(&header.magic);
     be32_to_cpus(&header.version);
     be64_to_cpus(&header.backing_file_offset);
@@ -160,16 +162,23 @@ static int qcow2_open(BlockDriverState *bs, int flags)
     be64_to_cpus(&header.snapshots_offset);
     be32_to_cpus(&header.nb_snapshots);
 
-    if (header.magic != QCOW_MAGIC || header.version != QCOW_VERSION)
+    if (header.magic != QCOW_MAGIC || header.version != QCOW_VERSION) {
+        ret = -EINVAL;
         goto fail;
+    }
     if (header.cluster_bits < MIN_CLUSTER_BITS ||
-        header.cluster_bits > MAX_CLUSTER_BITS)
+        header.cluster_bits > MAX_CLUSTER_BITS) {
+        ret = -EINVAL;
         goto fail;
-    if (header.crypt_method > QCOW_CRYPT_AES)
+    }
+    if (header.crypt_method > QCOW_CRYPT_AES) {
+        ret = -EINVAL;
         goto fail;
+    }
     s->crypt_method_header = header.crypt_method;
-    if (s->crypt_method_header)
+    if (s->crypt_method_header) {
         bs->encrypted = 1;
+    }
     s->cluster_bits = header.cluster_bits;
     s->cluster_size = 1 << s->cluster_bits;
     s->cluster_sectors = 1 << (s->cluster_bits - 9);
@@ -191,15 +200,19 @@ static int qcow2_open(BlockDriverState *bs, int flags)
     s->l1_vm_state_index = size_to_l1(s, header.size);
     /* the L1 table must contain at least enough entries to put
        header.size bytes */
-    if (s->l1_size < s->l1_vm_state_index)
+    if (s->l1_size < s->l1_vm_state_index) {
+        ret = -EINVAL;
         goto fail;
+    }
     s->l1_table_offset = header.l1_table_offset;
     if (s->l1_size > 0) {
         s->l1_table = qemu_mallocz(
             align_offset(s->l1_size * sizeof(uint64_t), 512));
-        if (bdrv_pread(bs->file, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)) !=
-            s->l1_size * sizeof(uint64_t))
+        ret = bdrv_pread(bs->file, s->l1_table_offset, s->l1_table,
+                         s->l1_size * sizeof(uint64_t));
+        if (ret < 0) {
             goto fail;
+        }
         for(i = 0;i < s->l1_size; i++) {
             be64_to_cpus(&s->l1_table[i]);
         }
@@ -212,35 +225,46 @@ static int qcow2_open(BlockDriverState *bs, int flags)
                                   + 512);
     s->cluster_cache_offset = -1;
 
-    if (qcow2_refcount_init(bs) < 0)
+    ret = qcow2_refcount_init(bs);
+    if (ret != 0) {
         goto fail;
+    }
 
     QLIST_INIT(&s->cluster_allocs);
 
     /* read qcow2 extensions */
-    if (header.backing_file_offset)
+    if (header.backing_file_offset) {
         ext_end = header.backing_file_offset;
-    else
+    } else {
         ext_end = s->cluster_size;
-    if (qcow2_read_extensions(bs, sizeof(header), ext_end))
+    }
+    if (qcow2_read_extensions(bs, sizeof(header), ext_end)) {
+        ret = -EINVAL;
         goto fail;
+    }
 
     /* read the backing file name */
     if (header.backing_file_offset != 0) {
         len = header.backing_file_size;
-        if (len > 1023)
+        if (len > 1023) {
             len = 1023;
-        if (bdrv_pread(bs->file, header.backing_file_offset, bs->backing_file, len) != len)
+        }
+        ret = bdrv_pread(bs->file, header.backing_file_offset,
+                         bs->backing_file, len);
+        if (ret < 0) {
             goto fail;
+        }
         bs->backing_file[len] = '\0';
     }
-    if (qcow2_read_snapshots(bs) < 0)
+    if (qcow2_read_snapshots(bs) < 0) {
+        ret = -EINVAL;
         goto fail;
+    }
 
 #ifdef DEBUG_ALLOC
     qcow2_check_refcounts(bs);
 #endif
-    return 0;
+    return ret;
 
  fail:
     qcow2_free_snapshots(bs);
@@ -249,7 +273,7 @@ static int qcow2_open(BlockDriverState *bs, int flags)
     qemu_free(s->l2_cache);
     qemu_free(s->cluster_cache);
     qemu_free(s->cluster_data);
-    return -1;
+    return ret;
 }
 
 static int qcow2_set_key(BlockDriverState *bs, const char *key)
commit 7c80ab3f21f0b1342f23057d4345ae266c7348d9
Author: Jes Sorensen <Jes.Sorensen at redhat.com>
Date:   Fri Dec 17 16:02:39 2010 +0100

    block/qcow2.c: rename qcow_ functions to qcow2_
    
    It doesn't really make sense for functions in qcow2.c to be named
    qcow_ so convert the names to match correctly.
    
    Signed-off-by: Jes Sorensen <Jes.Sorensen at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index b040208..6928c63 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -352,8 +352,8 @@ void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
 }
 
 
-static int qcow_read(BlockDriverState *bs, int64_t sector_num,
-                     uint8_t *buf, int nb_sectors)
+static int qcow2_read(BlockDriverState *bs, int64_t sector_num,
+                      uint8_t *buf, int nb_sectors)
 {
     BDRVQcowState *s = bs->opaque;
     int ret, index_in_cluster, n, n1;
@@ -419,7 +419,7 @@ static int copy_sectors(BlockDriverState *bs, uint64_t start_sect,
     if (n <= 0)
         return 0;
     BLKDBG_EVENT(bs->file, BLKDBG_COW_READ);
-    ret = qcow_read(bs, start_sect + n_start, s->cluster_data, n);
+    ret = qcow2_read(bs, start_sect + n_start, s->cluster_data, n);
     if (ret < 0)
         return ret;
     if (s->crypt_method) {
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
index aacf357..74823a5 100644
--- a/block/qcow2-snapshot.c
+++ b/block/qcow2-snapshot.c
@@ -116,7 +116,7 @@ int qcow2_read_snapshots(BlockDriverState *bs)
 }
 
 /* add at the end of the file a new list of snapshots */
-static int qcow_write_snapshots(BlockDriverState *bs)
+static int qcow2_write_snapshots(BlockDriverState *bs)
 {
     BDRVQcowState *s = bs->opaque;
     QCowSnapshot *sn;
@@ -300,7 +300,7 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
     s->snapshots = snapshots1;
     s->snapshots[s->nb_snapshots++] = *sn;
 
-    if (qcow_write_snapshots(bs) < 0)
+    if (qcow2_write_snapshots(bs) < 0)
         goto fail;
 #ifdef DEBUG_ALLOC
     qcow2_check_refcounts(bs);
@@ -378,7 +378,7 @@ int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
     qemu_free(sn->name);
     memmove(sn, sn + 1, (s->nb_snapshots - snapshot_index - 1) * sizeof(*sn));
     s->nb_snapshots--;
-    ret = qcow_write_snapshots(bs);
+    ret = qcow2_write_snapshots(bs);
     if (ret < 0) {
         /* XXX: restore snapshot if error ? */
         return ret;
diff --git a/block/qcow2.c b/block/qcow2.c
index 537c479..4b41190 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -50,10 +50,10 @@ typedef struct {
     uint32_t magic;
     uint32_t len;
 } QCowExtension;
-#define  QCOW_EXT_MAGIC_END 0
-#define  QCOW_EXT_MAGIC_BACKING_FORMAT 0xE2792ACA
+#define  QCOW2_EXT_MAGIC_END 0
+#define  QCOW2_EXT_MAGIC_BACKING_FORMAT 0xE2792ACA
 
-static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
+static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename)
 {
     const QCowHeader *cow_header = (const void *)buf;
 
@@ -73,14 +73,14 @@ static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
  * unknown magic is skipped (future extension this version knows nothing about)
  * return 0 upon success, non-0 otherwise
  */
-static int qcow_read_extensions(BlockDriverState *bs, uint64_t start_offset,
-                                uint64_t end_offset)
+static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
+                                 uint64_t end_offset)
 {
     QCowExtension ext;
     uint64_t offset;
 
 #ifdef DEBUG_EXT
-    printf("qcow_read_extensions: start=%ld end=%ld\n", start_offset, end_offset);
+    printf("qcow2_read_extensions: start=%ld end=%ld\n", start_offset, end_offset);
 #endif
     offset = start_offset;
     while (offset < end_offset) {
@@ -88,13 +88,13 @@ static int qcow_read_extensions(BlockDriverState *bs, uint64_t start_offset,
 #ifdef DEBUG_EXT
         /* Sanity check */
         if (offset > s->cluster_size)
-            printf("qcow_handle_extension: suspicious offset %lu\n", offset);
+            printf("qcow2_read_extension: suspicious offset %lu\n", offset);
 
         printf("attemting to read extended header in offset %lu\n", offset);
 #endif
 
         if (bdrv_pread(bs->file, offset, &ext, sizeof(ext)) != sizeof(ext)) {
-            fprintf(stderr, "qcow_handle_extension: ERROR: "
+            fprintf(stderr, "qcow2_read_extension: ERROR: "
                     "pread fail from offset %" PRIu64 "\n",
                     offset);
             return 1;
@@ -106,10 +106,10 @@ static int qcow_read_extensions(BlockDriverState *bs, uint64_t start_offset,
         printf("ext.magic = 0x%x\n", ext.magic);
 #endif
         switch (ext.magic) {
-        case QCOW_EXT_MAGIC_END:
+        case QCOW2_EXT_MAGIC_END:
             return 0;
 
-        case QCOW_EXT_MAGIC_BACKING_FORMAT:
+        case QCOW2_EXT_MAGIC_BACKING_FORMAT:
             if (ext.len >= sizeof(bs->backing_format)) {
                 fprintf(stderr, "ERROR: ext_backing_format: len=%u too large"
                         " (>=%zu)\n",
@@ -137,7 +137,7 @@ static int qcow_read_extensions(BlockDriverState *bs, uint64_t start_offset,
 }
 
 
-static int qcow_open(BlockDriverState *bs, int flags)
+static int qcow2_open(BlockDriverState *bs, int flags)
 {
     BDRVQcowState *s = bs->opaque;
     int len, i;
@@ -222,7 +222,7 @@ static int qcow_open(BlockDriverState *bs, int flags)
         ext_end = header.backing_file_offset;
     else
         ext_end = s->cluster_size;
-    if (qcow_read_extensions(bs, sizeof(header), ext_end))
+    if (qcow2_read_extensions(bs, sizeof(header), ext_end))
         goto fail;
 
     /* read the backing file name */
@@ -252,7 +252,7 @@ static int qcow_open(BlockDriverState *bs, int flags)
     return -1;
 }
 
-static int qcow_set_key(BlockDriverState *bs, const char *key)
+static int qcow2_set_key(BlockDriverState *bs, const char *key)
 {
     BDRVQcowState *s = bs->opaque;
     uint8_t keybuf[16];
@@ -294,8 +294,8 @@ static int qcow_set_key(BlockDriverState *bs, const char *key)
     return 0;
 }
 
-static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num,
-                             int nb_sectors, int *pnum)
+static int qcow2_is_allocated(BlockDriverState *bs, int64_t sector_num,
+                              int nb_sectors, int *pnum)
 {
     uint64_t cluster_offset;
     int ret;
@@ -344,7 +344,7 @@ typedef struct QCowAIOCB {
     QLIST_ENTRY(QCowAIOCB) next_depend;
 } QCowAIOCB;
 
-static void qcow_aio_cancel(BlockDriverAIOCB *blockacb)
+static void qcow2_aio_cancel(BlockDriverAIOCB *blockacb)
 {
     QCowAIOCB *acb = container_of(blockacb, QCowAIOCB, common);
     if (acb->hd_aiocb)
@@ -352,21 +352,21 @@ static void qcow_aio_cancel(BlockDriverAIOCB *blockacb)
     qemu_aio_release(acb);
 }
 
-static AIOPool qcow_aio_pool = {
+static AIOPool qcow2_aio_pool = {
     .aiocb_size         = sizeof(QCowAIOCB),
-    .cancel             = qcow_aio_cancel,
+    .cancel             = qcow2_aio_cancel,
 };
 
-static void qcow_aio_read_cb(void *opaque, int ret);
-static void qcow_aio_read_bh(void *opaque)
+static void qcow2_aio_read_cb(void *opaque, int ret);
+static void qcow2_aio_read_bh(void *opaque)
 {
     QCowAIOCB *acb = opaque;
     qemu_bh_delete(acb->bh);
     acb->bh = NULL;
-    qcow_aio_read_cb(opaque, 0);
+    qcow2_aio_read_cb(opaque, 0);
 }
 
-static int qcow_schedule_bh(QEMUBHFunc *cb, QCowAIOCB *acb)
+static int qcow2_schedule_bh(QEMUBHFunc *cb, QCowAIOCB *acb)
 {
     if (acb->bh)
         return -EIO;
@@ -380,7 +380,7 @@ static int qcow_schedule_bh(QEMUBHFunc *cb, QCowAIOCB *acb)
     return 0;
 }
 
-static void qcow_aio_read_cb(void *opaque, int ret)
+static void qcow2_aio_read_cb(void *opaque, int ret)
 {
     QCowAIOCB *acb = opaque;
     BlockDriverState *bs = acb->common.bs;
@@ -447,18 +447,18 @@ static void qcow_aio_read_cb(void *opaque, int ret)
                 BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
                 acb->hd_aiocb = bdrv_aio_readv(bs->backing_hd, acb->sector_num,
                                     &acb->hd_qiov, acb->cur_nr_sectors,
-				    qcow_aio_read_cb, acb);
+				    qcow2_aio_read_cb, acb);
                 if (acb->hd_aiocb == NULL)
                     goto done;
             } else {
-                ret = qcow_schedule_bh(qcow_aio_read_bh, acb);
+                ret = qcow2_schedule_bh(qcow2_aio_read_bh, acb);
                 if (ret < 0)
                     goto done;
             }
         } else {
             /* Note: in this case, no need to wait */
             qemu_iovec_memset(&acb->hd_qiov, 0, 512 * acb->cur_nr_sectors);
-            ret = qcow_schedule_bh(qcow_aio_read_bh, acb);
+            ret = qcow2_schedule_bh(qcow2_aio_read_bh, acb);
             if (ret < 0)
                 goto done;
         }
@@ -471,7 +471,7 @@ static void qcow_aio_read_cb(void *opaque, int ret)
             s->cluster_cache + index_in_cluster * 512,
             512 * acb->cur_nr_sectors);
 
-        ret = qcow_schedule_bh(qcow_aio_read_bh, acb);
+        ret = qcow2_schedule_bh(qcow2_aio_read_bh, acb);
         if (ret < 0)
             goto done;
     } else {
@@ -501,7 +501,7 @@ static void qcow_aio_read_cb(void *opaque, int ret)
         acb->hd_aiocb = bdrv_aio_readv(bs->file,
                             (acb->cluster_offset >> 9) + index_in_cluster,
                             &acb->hd_qiov, acb->cur_nr_sectors,
-                            qcow_aio_read_cb, acb);
+                            qcow2_aio_read_cb, acb);
         if (acb->hd_aiocb == NULL) {
             ret = -EIO;
             goto done;
@@ -515,13 +515,14 @@ done:
     qemu_aio_release(acb);
 }
 
-static QCowAIOCB *qcow_aio_setup(BlockDriverState *bs,
-        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque, int is_write)
+static QCowAIOCB *qcow2_aio_setup(BlockDriverState *bs, int64_t sector_num,
+                                  QEMUIOVector *qiov, int nb_sectors,
+                                  BlockDriverCompletionFunc *cb,
+                                  void *opaque, int is_write)
 {
     QCowAIOCB *acb;
 
-    acb = qemu_aio_get(&qcow_aio_pool, bs, cb, opaque);
+    acb = qemu_aio_get(&qcow2_aio_pool, bs, cb, opaque);
     if (!acb)
         return NULL;
     acb->hd_aiocb = NULL;
@@ -539,21 +540,23 @@ static QCowAIOCB *qcow_aio_setup(BlockDriverState *bs,
     return acb;
 }
 
-static BlockDriverAIOCB *qcow_aio_readv(BlockDriverState *bs,
-        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque)
+static BlockDriverAIOCB *qcow2_aio_readv(BlockDriverState *bs,
+                                         int64_t sector_num,
+                                         QEMUIOVector *qiov, int nb_sectors,
+                                         BlockDriverCompletionFunc *cb,
+                                         void *opaque)
 {
     QCowAIOCB *acb;
 
-    acb = qcow_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
+    acb = qcow2_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
     if (!acb)
         return NULL;
 
-    qcow_aio_read_cb(acb, 0);
+    qcow2_aio_read_cb(acb, 0);
     return &acb->common;
 }
 
-static void qcow_aio_write_cb(void *opaque, int ret);
+static void qcow2_aio_write_cb(void *opaque, int ret);
 
 static void run_dependent_requests(QCowL2Meta *m)
 {
@@ -567,14 +570,14 @@ static void run_dependent_requests(QCowL2Meta *m)
 
     /* Restart all dependent requests */
     QLIST_FOREACH_SAFE(req, &m->dependent_requests, next_depend, next) {
-        qcow_aio_write_cb(req, 0);
+        qcow2_aio_write_cb(req, 0);
     }
 
     /* Empty the list for the next part of the request */
     QLIST_INIT(&m->dependent_requests);
 }
 
-static void qcow_aio_write_cb(void *opaque, int ret)
+static void qcow2_aio_write_cb(void *opaque, int ret)
 {
     QCowAIOCB *acb = opaque;
     BlockDriverState *bs = acb->common.bs;
@@ -651,7 +654,7 @@ static void qcow_aio_write_cb(void *opaque, int ret)
     acb->hd_aiocb = bdrv_aio_writev(bs->file,
                                     (acb->cluster_offset >> 9) + index_in_cluster,
                                     &acb->hd_qiov, acb->cur_nr_sectors,
-                                    qcow_aio_write_cb, acb);
+                                    qcow2_aio_write_cb, acb);
     if (acb->hd_aiocb == NULL) {
         ret = -EIO;
         goto fail;
@@ -669,24 +672,26 @@ done:
     qemu_aio_release(acb);
 }
 
-static BlockDriverAIOCB *qcow_aio_writev(BlockDriverState *bs,
-        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque)
+static BlockDriverAIOCB *qcow2_aio_writev(BlockDriverState *bs,
+                                          int64_t sector_num,
+                                          QEMUIOVector *qiov, int nb_sectors,
+                                          BlockDriverCompletionFunc *cb,
+                                          void *opaque)
 {
     BDRVQcowState *s = bs->opaque;
     QCowAIOCB *acb;
 
     s->cluster_cache_offset = -1; /* disable compressed cache */
 
-    acb = qcow_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
+    acb = qcow2_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
     if (!acb)
         return NULL;
 
-    qcow_aio_write_cb(acb, 0);
+    qcow2_aio_write_cb(acb, 0);
     return &acb->common;
 }
 
-static void qcow_close(BlockDriverState *bs)
+static void qcow2_close(BlockDriverState *bs)
 {
     BDRVQcowState *s = bs->opaque;
     qemu_free(s->l1_table);
@@ -721,7 +726,7 @@ static int qcow2_update_ext_header(BlockDriverState *bs,
     /* Prepare the backing file format extension if needed */
     if (backing_fmt) {
         ext_backing_fmt.len = cpu_to_be32(strlen(backing_fmt));
-        ext_backing_fmt.magic = cpu_to_be32(QCOW_EXT_MAGIC_BACKING_FORMAT);
+        ext_backing_fmt.magic = cpu_to_be32(QCOW2_EXT_MAGIC_BACKING_FORMAT);
         backing_fmt_len = ((sizeof(ext_backing_fmt)
             + strlen(backing_fmt) + 7) & ~7);
     }
@@ -848,10 +853,10 @@ static int preallocate(BlockDriverState *bs)
     return 0;
 }
 
-static int qcow_create2(const char *filename, int64_t total_size,
-                        const char *backing_file, const char *backing_format,
-                        int flags, size_t cluster_size, int prealloc,
-                        QEMUOptionParameter *options)
+static int qcow2_create2(const char *filename, int64_t total_size,
+                         const char *backing_file, const char *backing_format,
+                         int flags, size_t cluster_size, int prealloc,
+                         QEMUOptionParameter *options)
 {
     /* Calulate cluster_bits */
     int cluster_bits;
@@ -974,7 +979,7 @@ out:
     return ret;
 }
 
-static int qcow_create(const char *filename, QEMUOptionParameter *options)
+static int qcow2_create(const char *filename, QEMUOptionParameter *options)
 {
     const char *backing_file = NULL;
     const char *backing_fmt = NULL;
@@ -1017,11 +1022,11 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options)
         return -EINVAL;
     }
 
-    return qcow_create2(filename, sectors, backing_file, backing_fmt, flags,
-        cluster_size, prealloc, options);
+    return qcow2_create2(filename, sectors, backing_file, backing_fmt, flags,
+                         cluster_size, prealloc, options);
 }
 
-static int qcow_make_empty(BlockDriverState *bs)
+static int qcow2_make_empty(BlockDriverState *bs)
 {
 #if 0
     /* XXX: not correct */
@@ -1080,8 +1085,8 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset)
 
 /* XXX: put compressed sectors first, then all the cluster aligned
    tables to avoid losing bytes in alignment */
-static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
-                                 const uint8_t *buf, int nb_sectors)
+static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num,
+                                  const uint8_t *buf, int nb_sectors)
 {
     BDRVQcowState *s = bs->opaque;
     z_stream strm;
@@ -1148,32 +1153,33 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
     return 0;
 }
 
-static int qcow_flush(BlockDriverState *bs)
+static int qcow2_flush(BlockDriverState *bs)
 {
     return bdrv_flush(bs->file);
 }
 
-static BlockDriverAIOCB *qcow_aio_flush(BlockDriverState *bs,
-         BlockDriverCompletionFunc *cb, void *opaque)
+static BlockDriverAIOCB *qcow2_aio_flush(BlockDriverState *bs,
+                                         BlockDriverCompletionFunc *cb,
+                                         void *opaque)
 {
     return bdrv_aio_flush(bs->file, cb, opaque);
 }
 
-static int64_t qcow_vm_state_offset(BDRVQcowState *s)
+static int64_t qcow2_vm_state_offset(BDRVQcowState *s)
 {
 	return (int64_t)s->l1_vm_state_index << (s->cluster_bits + s->l2_bits);
 }
 
-static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
+static int qcow2_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
 {
     BDRVQcowState *s = bs->opaque;
     bdi->cluster_size = s->cluster_size;
-    bdi->vm_state_offset = qcow_vm_state_offset(s);
+    bdi->vm_state_offset = qcow2_vm_state_offset(s);
     return 0;
 }
 
 
-static int qcow_check(BlockDriverState *bs, BdrvCheckResult *result)
+static int qcow2_check(BlockDriverState *bs, BdrvCheckResult *result)
 {
     return qcow2_check_refcounts(bs, result);
 }
@@ -1199,8 +1205,8 @@ static void dump_refcounts(BlockDriverState *bs)
 }
 #endif
 
-static int qcow_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
-                           int64_t pos, int size)
+static int qcow2_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
+                              int64_t pos, int size)
 {
     BDRVQcowState *s = bs->opaque;
     int growable = bs->growable;
@@ -1208,14 +1214,14 @@ static int qcow_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
 
     BLKDBG_EVENT(bs->file, BLKDBG_VMSTATE_SAVE);
     bs->growable = 1;
-    ret = bdrv_pwrite(bs, qcow_vm_state_offset(s) + pos, buf, size);
+    ret = bdrv_pwrite(bs, qcow2_vm_state_offset(s) + pos, buf, size);
     bs->growable = growable;
 
     return ret;
 }
 
-static int qcow_load_vmstate(BlockDriverState *bs, uint8_t *buf,
-                           int64_t pos, int size)
+static int qcow2_load_vmstate(BlockDriverState *bs, uint8_t *buf,
+                              int64_t pos, int size)
 {
     BDRVQcowState *s = bs->opaque;
     int growable = bs->growable;
@@ -1223,13 +1229,13 @@ static int qcow_load_vmstate(BlockDriverState *bs, uint8_t *buf,
 
     BLKDBG_EVENT(bs->file, BLKDBG_VMSTATE_LOAD);
     bs->growable = 1;
-    ret = bdrv_pread(bs, qcow_vm_state_offset(s) + pos, buf, size);
+    ret = bdrv_pread(bs, qcow2_vm_state_offset(s) + pos, buf, size);
     bs->growable = growable;
 
     return ret;
 }
 
-static QEMUOptionParameter qcow_create_options[] = {
+static QEMUOptionParameter qcow2_create_options[] = {
     {
         .name = BLOCK_OPT_SIZE,
         .type = OPT_SIZE,
@@ -1264,38 +1270,38 @@ static QEMUOptionParameter qcow_create_options[] = {
 };
 
 static BlockDriver bdrv_qcow2 = {
-    .format_name	= "qcow2",
-    .instance_size	= sizeof(BDRVQcowState),
-    .bdrv_probe		= qcow_probe,
-    .bdrv_open		= qcow_open,
-    .bdrv_close		= qcow_close,
-    .bdrv_create	= qcow_create,
-    .bdrv_flush		= qcow_flush,
-    .bdrv_is_allocated	= qcow_is_allocated,
-    .bdrv_set_key	= qcow_set_key,
-    .bdrv_make_empty	= qcow_make_empty,
-
-    .bdrv_aio_readv	= qcow_aio_readv,
-    .bdrv_aio_writev	= qcow_aio_writev,
-    .bdrv_aio_flush	= qcow_aio_flush,
+    .format_name        = "qcow2",
+    .instance_size      = sizeof(BDRVQcowState),
+    .bdrv_probe         = qcow2_probe,
+    .bdrv_open          = qcow2_open,
+    .bdrv_close         = qcow2_close,
+    .bdrv_create        = qcow2_create,
+    .bdrv_flush         = qcow2_flush,
+    .bdrv_is_allocated  = qcow2_is_allocated,
+    .bdrv_set_key       = qcow2_set_key,
+    .bdrv_make_empty    = qcow2_make_empty,
+
+    .bdrv_aio_readv     = qcow2_aio_readv,
+    .bdrv_aio_writev    = qcow2_aio_writev,
+    .bdrv_aio_flush     = qcow2_aio_flush,
 
     .bdrv_truncate          = qcow2_truncate,
-    .bdrv_write_compressed  = qcow_write_compressed,
+    .bdrv_write_compressed  = qcow2_write_compressed,
 
     .bdrv_snapshot_create   = qcow2_snapshot_create,
     .bdrv_snapshot_goto     = qcow2_snapshot_goto,
     .bdrv_snapshot_delete   = qcow2_snapshot_delete,
     .bdrv_snapshot_list     = qcow2_snapshot_list,
     .bdrv_snapshot_load_tmp     = qcow2_snapshot_load_tmp,
-    .bdrv_get_info	= qcow_get_info,
+    .bdrv_get_info      = qcow2_get_info,
 
-    .bdrv_save_vmstate    = qcow_save_vmstate,
-    .bdrv_load_vmstate    = qcow_load_vmstate,
+    .bdrv_save_vmstate    = qcow2_save_vmstate,
+    .bdrv_load_vmstate    = qcow2_load_vmstate,
 
     .bdrv_change_backing_file   = qcow2_change_backing_file,
 
-    .create_options = qcow_create_options,
-    .bdrv_check = qcow_check,
+    .create_options = qcow2_create_options,
+    .bdrv_check = qcow2_check,
 };
 
 static void bdrv_qcow2_init(void)
commit 01979a98d75b49c2acbbbb71521c285f8d8f9fb7
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Mon Dec 6 16:08:03 2010 +0000

    qed: Consistency check support
    
    This patch adds support for the qemu-img check command.  It also
    introduces a dirty bit in the qed header to mark modified images as
    needing a check.  This bit is cleared when the image file is closed
    cleanly.
    
    If an image file is opened and it has the dirty bit set, a consistency
    check will run and try to fix corrupted table offsets.  These
    corruptions may occur if there is power loss while an allocating write
    is performed.  Once the image is fixed it opens as normal again.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/qed-check.c b/block/qed-check.c
new file mode 100644
index 0000000..4600932
--- /dev/null
+++ b/block/qed-check.c
@@ -0,0 +1,210 @@
+/*
+ * QEMU Enhanced Disk Format Consistency Check
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * 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 "qed.h"
+
+typedef struct {
+    BDRVQEDState *s;
+    BdrvCheckResult *result;
+    bool fix;                           /* whether to fix invalid offsets */
+
+    size_t nclusters;
+    uint32_t *used_clusters;            /* referenced cluster bitmap */
+
+    QEDRequest request;
+} QEDCheck;
+
+static bool qed_test_bit(uint32_t *bitmap, uint64_t n) {
+    return !!(bitmap[n / 32] & (1 << (n % 32)));
+}
+
+static void qed_set_bit(uint32_t *bitmap, uint64_t n) {
+    bitmap[n / 32] |= 1 << (n % 32);
+}
+
+/**
+ * Set bitmap bits for clusters
+ *
+ * @check:          Check structure
+ * @offset:         Starting offset in bytes
+ * @n:              Number of clusters
+ */
+static bool qed_set_used_clusters(QEDCheck *check, uint64_t offset,
+                                  unsigned int n)
+{
+    uint64_t cluster = qed_bytes_to_clusters(check->s, offset);
+    unsigned int corruptions = 0;
+
+    while (n-- != 0) {
+        /* Clusters should only be referenced once */
+        if (qed_test_bit(check->used_clusters, cluster)) {
+            corruptions++;
+        }
+
+        qed_set_bit(check->used_clusters, cluster);
+        cluster++;
+    }
+
+    check->result->corruptions += corruptions;
+    return corruptions == 0;
+}
+
+/**
+ * Check an L2 table
+ *
+ * @ret:            Number of invalid cluster offsets
+ */
+static unsigned int qed_check_l2_table(QEDCheck *check, QEDTable *table)
+{
+    BDRVQEDState *s = check->s;
+    unsigned int i, num_invalid = 0;
+
+    for (i = 0; i < s->table_nelems; i++) {
+        uint64_t offset = table->offsets[i];
+
+        if (!offset) {
+            continue;
+        }
+
+        /* Detect invalid cluster offset */
+        if (!qed_check_cluster_offset(s, offset)) {
+            if (check->fix) {
+                table->offsets[i] = 0;
+            } else {
+                check->result->corruptions++;
+            }
+
+            num_invalid++;
+            continue;
+        }
+
+        qed_set_used_clusters(check, offset, 1);
+    }
+
+    return num_invalid;
+}
+
+/**
+ * Descend tables and check each cluster is referenced once only
+ */
+static int qed_check_l1_table(QEDCheck *check, QEDTable *table)
+{
+    BDRVQEDState *s = check->s;
+    unsigned int i, num_invalid_l1 = 0;
+    int ret, last_error = 0;
+
+    /* Mark L1 table clusters used */
+    qed_set_used_clusters(check, s->header.l1_table_offset,
+                          s->header.table_size);
+
+    for (i = 0; i < s->table_nelems; i++) {
+        unsigned int num_invalid_l2;
+        uint64_t offset = table->offsets[i];
+
+        if (!offset) {
+            continue;
+        }
+
+        /* Detect invalid L2 offset */
+        if (!qed_check_table_offset(s, offset)) {
+            /* Clear invalid offset */
+            if (check->fix) {
+                table->offsets[i] = 0;
+            } else {
+                check->result->corruptions++;
+            }
+
+            num_invalid_l1++;
+            continue;
+        }
+
+        if (!qed_set_used_clusters(check, offset, s->header.table_size)) {
+            continue; /* skip an invalid table */
+        }
+
+        ret = qed_read_l2_table_sync(s, &check->request, offset);
+        if (ret) {
+            check->result->check_errors++;
+            last_error = ret;
+            continue;
+        }
+
+        num_invalid_l2 = qed_check_l2_table(check,
+                                            check->request.l2_table->table);
+
+        /* Write out fixed L2 table */
+        if (num_invalid_l2 > 0 && check->fix) {
+            ret = qed_write_l2_table_sync(s, &check->request, 0,
+                                          s->table_nelems, false);
+            if (ret) {
+                check->result->check_errors++;
+                last_error = ret;
+                continue;
+            }
+        }
+    }
+
+    /* Drop reference to final table */
+    qed_unref_l2_cache_entry(check->request.l2_table);
+    check->request.l2_table = NULL;
+
+    /* Write out fixed L1 table */
+    if (num_invalid_l1 > 0 && check->fix) {
+        ret = qed_write_l1_table_sync(s, 0, s->table_nelems);
+        if (ret) {
+            check->result->check_errors++;
+            last_error = ret;
+        }
+    }
+
+    return last_error;
+}
+
+/**
+ * Check for unreferenced (leaked) clusters
+ */
+static void qed_check_for_leaks(QEDCheck *check)
+{
+    BDRVQEDState *s = check->s;
+    size_t i;
+
+    for (i = s->header.header_size; i < check->nclusters; i++) {
+        if (!qed_test_bit(check->used_clusters, i)) {
+            check->result->leaks++;
+        }
+    }
+}
+
+int qed_check(BDRVQEDState *s, BdrvCheckResult *result, bool fix)
+{
+    QEDCheck check = {
+        .s = s,
+        .result = result,
+        .nclusters = qed_bytes_to_clusters(s, s->file_size),
+        .request = { .l2_table = NULL },
+        .fix = fix,
+    };
+    int ret;
+
+    check.used_clusters = qemu_mallocz(((check.nclusters + 31) / 32) *
+                                       sizeof(check.used_clusters[0]));
+
+    ret = qed_check_l1_table(&check, s->l1_table);
+    if (ret == 0) {
+        /* Only check for leaks if entire image was scanned successfully */
+        qed_check_for_leaks(&check);
+    }
+
+    qemu_free(check.used_clusters);
+    return ret;
+}
diff --git a/block/qed.c b/block/qed.c
index 8e65d18..085c4f2 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -99,6 +99,81 @@ static int qed_write_header_sync(BDRVQEDState *s)
     return 0;
 }
 
+typedef struct {
+    GenericCB gencb;
+    BDRVQEDState *s;
+    struct iovec iov;
+    QEMUIOVector qiov;
+    int nsectors;
+    uint8_t *buf;
+} QEDWriteHeaderCB;
+
+static void qed_write_header_cb(void *opaque, int ret)
+{
+    QEDWriteHeaderCB *write_header_cb = opaque;
+
+    qemu_vfree(write_header_cb->buf);
+    gencb_complete(write_header_cb, ret);
+}
+
+static void qed_write_header_read_cb(void *opaque, int ret)
+{
+    QEDWriteHeaderCB *write_header_cb = opaque;
+    BDRVQEDState *s = write_header_cb->s;
+    BlockDriverAIOCB *acb;
+
+    if (ret) {
+        qed_write_header_cb(write_header_cb, ret);
+        return;
+    }
+
+    /* Update header */
+    qed_header_cpu_to_le(&s->header, (QEDHeader *)write_header_cb->buf);
+
+    acb = bdrv_aio_writev(s->bs->file, 0, &write_header_cb->qiov,
+                          write_header_cb->nsectors, qed_write_header_cb,
+                          write_header_cb);
+    if (!acb) {
+        qed_write_header_cb(write_header_cb, -EIO);
+    }
+}
+
+/**
+ * Update header in-place (does not rewrite backing filename or other strings)
+ *
+ * This function only updates known header fields in-place and does not affect
+ * extra data after the QED header.
+ */
+static void qed_write_header(BDRVQEDState *s, BlockDriverCompletionFunc cb,
+                             void *opaque)
+{
+    /* We must write full sectors for O_DIRECT but cannot necessarily generate
+     * the data following the header if an unrecognized compat feature is
+     * active.  Therefore, first read the sectors containing the header, update
+     * them, and write back.
+     */
+
+    BlockDriverAIOCB *acb;
+    int nsectors = (sizeof(QEDHeader) + BDRV_SECTOR_SIZE - 1) /
+                   BDRV_SECTOR_SIZE;
+    size_t len = nsectors * BDRV_SECTOR_SIZE;
+    QEDWriteHeaderCB *write_header_cb = gencb_alloc(sizeof(*write_header_cb),
+                                                    cb, opaque);
+
+    write_header_cb->s = s;
+    write_header_cb->nsectors = nsectors;
+    write_header_cb->buf = qemu_blockalign(s->bs, len);
+    write_header_cb->iov.iov_base = write_header_cb->buf;
+    write_header_cb->iov.iov_len = len;
+    qemu_iovec_init_external(&write_header_cb->qiov, &write_header_cb->iov, 1);
+
+    acb = bdrv_aio_readv(s->bs->file, 0, &write_header_cb->qiov, nsectors,
+                         qed_write_header_read_cb, write_header_cb);
+    if (!acb) {
+        qed_write_header_cb(write_header_cb, -EIO);
+    }
+}
+
 static uint64_t qed_max_image_size(uint32_t cluster_size, uint32_t table_size)
 {
     uint64_t table_entries;
@@ -310,6 +385,32 @@ static int bdrv_qed_open(BlockDriverState *bs, int flags)
 
     ret = qed_read_l1_table_sync(s);
     if (ret) {
+        goto out;
+    }
+
+    /* If image was not closed cleanly, check consistency */
+    if (s->header.features & QED_F_NEED_CHECK) {
+        /* Read-only images cannot be fixed.  There is no risk of corruption
+         * since write operations are not possible.  Therefore, allow
+         * potentially inconsistent images to be opened read-only.  This can
+         * aid data recovery from an otherwise inconsistent image.
+         */
+        if (!bdrv_is_read_only(bs->file)) {
+            BdrvCheckResult result = {0};
+
+            ret = qed_check(s, &result, true);
+            if (!ret && !result.corruptions && !result.check_errors) {
+                /* Ensure fixes reach storage before clearing check bit */
+                bdrv_flush(s->bs);
+
+                s->header.features &= ~QED_F_NEED_CHECK;
+                qed_write_header_sync(s);
+            }
+        }
+    }
+
+out:
+    if (ret) {
         qed_free_l2_cache(&s->l2_cache);
         qemu_vfree(s->l1_table);
     }
@@ -320,6 +421,15 @@ static void bdrv_qed_close(BlockDriverState *bs)
 {
     BDRVQEDState *s = bs->opaque;
 
+    /* Ensure writes reach stable storage */
+    bdrv_flush(bs->file);
+
+    /* Clean shutdown, no check required on next open */
+    if (s->header.features & QED_F_NEED_CHECK) {
+        s->header.features &= ~QED_F_NEED_CHECK;
+        qed_write_header_sync(s);
+    }
+
     qed_free_l2_cache(&s->l2_cache);
     qemu_vfree(s->l1_table);
 }
@@ -885,8 +995,15 @@ static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
     acb->cur_cluster = qed_alloc_clusters(s, acb->cur_nclusters);
     qemu_iovec_copy(&acb->cur_qiov, acb->qiov, acb->qiov_offset, len);
 
-    /* Write new cluster */
-    qed_aio_write_prefill(acb, 0);
+    /* Write new cluster if the image is already marked dirty */
+    if (s->header.features & QED_F_NEED_CHECK) {
+        qed_aio_write_prefill(acb, 0);
+        return;
+    }
+
+    /* Mark the image dirty before writing the new cluster */
+    s->header.features |= QED_F_NEED_CHECK;
+    qed_write_header(s, qed_aio_write_prefill, acb);
 }
 
 /**
@@ -1172,7 +1289,9 @@ static int bdrv_qed_change_backing_file(BlockDriverState *bs,
 
 static int bdrv_qed_check(BlockDriverState *bs, BdrvCheckResult *result)
 {
-    return -ENOTSUP;
+    BDRVQEDState *s = bs->opaque;
+
+    return qed_check(s, result, false);
 }
 
 static QEMUOptionParameter qed_create_options[] = {
diff --git a/block/qed.h b/block/qed.h
index 046a410..2925e37 100644
--- a/block/qed.h
+++ b/block/qed.h
@@ -50,11 +50,15 @@ enum {
     /* The image supports a backing file */
     QED_F_BACKING_FILE = 0x01,
 
+    /* The image needs a consistency check before use */
+    QED_F_NEED_CHECK = 0x02,
+
     /* The backing file format must not be probed, treat as raw image */
     QED_F_BACKING_FORMAT_NO_PROBE = 0x04,
 
     /* Feature bits must be used when the on-disk format changes */
     QED_FEATURE_MASK = QED_F_BACKING_FILE | /* supported feature bits */
+                       QED_F_NEED_CHECK |
                        QED_F_BACKING_FORMAT_NO_PROBE,
     QED_COMPAT_FEATURE_MASK = 0,            /* supported compat feature bits */
     QED_AUTOCLEAR_FEATURE_MASK = 0,         /* supported autoclear feature bits */
commit eabba580e6bb8d6b969c1368c6f90d72b4cde4f4
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Mon Dec 6 16:08:02 2010 +0000

    qed: Read/write support
    
    This patch implements the read/write state machine.  Operations are
    fully asynchronous and multiple operations may be active at any time.
    
    Allocating writes lock tables to ensure metadata updates do not
    interfere with each other.  If two allocating writes need to update the
    same L2 table they will run sequentially.  If two allocating writes need
    to update different L2 tables they will run in parallel.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/Makefile.objs b/Makefile.objs
index 1860152..d6b3d60 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -21,6 +21,7 @@ block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
 block-nested-y += raw.o cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o
 block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o
 block-nested-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
+block-nested-y += qed-check.o
 block-nested-y += parallels.o nbd.o blkdebug.o sheepdog.o blkverify.o
 block-nested-$(CONFIG_WIN32) += raw-win32.o
 block-nested-$(CONFIG_POSIX) += raw-posix.o
diff --git a/block/qed.c b/block/qed.c
index cd1bead..8e65d18 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -12,8 +12,26 @@
  *
  */
 
+#include "trace.h"
 #include "qed.h"
 
+static void qed_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+    QEDAIOCB *acb = (QEDAIOCB *)blockacb;
+    bool finished = false;
+
+    /* Wait for the request to finish */
+    acb->finished = &finished;
+    while (!finished) {
+        qemu_aio_wait();
+    }
+}
+
+static AIOPool qed_aio_pool = {
+    .aiocb_size         = sizeof(QEDAIOCB),
+    .cancel             = qed_aio_cancel,
+};
+
 static int bdrv_qed_probe(const uint8_t *buf, int buf_size,
                           const char *filename)
 {
@@ -155,6 +173,24 @@ static int qed_read_string(BlockDriverState *file, uint64_t offset, size_t n,
     return 0;
 }
 
+/**
+ * Allocate new clusters
+ *
+ * @s:          QED state
+ * @n:          Number of contiguous clusters to allocate
+ * @ret:        Offset of first allocated cluster
+ *
+ * This function only produces the offset where the new clusters should be
+ * written.  It updates BDRVQEDState but does not make any changes to the image
+ * file.
+ */
+static uint64_t qed_alloc_clusters(BDRVQEDState *s, unsigned int n)
+{
+    uint64_t offset = s->file_size;
+    s->file_size += n * s->header.cluster_size;
+    return offset;
+}
+
 QEDTable *qed_alloc_table(BDRVQEDState *s)
 {
     /* Honor O_DIRECT memory alignment requirements */
@@ -162,6 +198,23 @@ QEDTable *qed_alloc_table(BDRVQEDState *s)
                            s->header.cluster_size * s->header.table_size);
 }
 
+/**
+ * Allocate a new zeroed L2 table
+ */
+static CachedL2Table *qed_new_l2_table(BDRVQEDState *s)
+{
+    CachedL2Table *l2_table = qed_alloc_l2_cache_entry(&s->l2_cache);
+
+    l2_table->table = qed_alloc_table(s);
+    l2_table->offset = qed_alloc_clusters(s, s->header.table_size);
+
+    memset(l2_table->table->offsets, 0,
+           s->header.cluster_size * s->header.table_size);
+    return l2_table;
+}
+
+static void qed_aio_next_io(void *opaque, int ret);
+
 static int bdrv_qed_open(BlockDriverState *bs, int flags)
 {
     BDRVQEDState *s = bs->opaque;
@@ -170,6 +223,7 @@ static int bdrv_qed_open(BlockDriverState *bs, int flags)
     int ret;
 
     s->bs = bs;
+    QSIMPLEQ_INIT(&s->allocating_write_reqs);
 
     ret = bdrv_pread(bs->file, 0, &le_header, sizeof(le_header));
     if (ret < 0) {
@@ -431,13 +485,583 @@ static int bdrv_qed_make_empty(BlockDriverState *bs)
     return -ENOTSUP;
 }
 
+static BDRVQEDState *acb_to_s(QEDAIOCB *acb)
+{
+    return acb->common.bs->opaque;
+}
+
+/**
+ * Read from the backing file or zero-fill if no backing file
+ *
+ * @s:          QED state
+ * @pos:        Byte position in device
+ * @qiov:       Destination I/O vector
+ * @cb:         Completion function
+ * @opaque:     User data for completion function
+ *
+ * This function reads qiov->size bytes starting at pos from the backing file.
+ * If there is no backing file then zeroes are read.
+ */
+static void qed_read_backing_file(BDRVQEDState *s, uint64_t pos,
+                                  QEMUIOVector *qiov,
+                                  BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BlockDriverAIOCB *aiocb;
+    uint64_t backing_length = 0;
+    size_t size;
+
+    /* If there is a backing file, get its length.  Treat the absence of a
+     * backing file like a zero length backing file.
+     */
+    if (s->bs->backing_hd) {
+        int64_t l = bdrv_getlength(s->bs->backing_hd);
+        if (l < 0) {
+            cb(opaque, l);
+            return;
+        }
+        backing_length = l;
+    }
+
+    /* Zero all sectors if reading beyond the end of the backing file */
+    if (pos >= backing_length ||
+        pos + qiov->size > backing_length) {
+        qemu_iovec_memset(qiov, 0, qiov->size);
+    }
+
+    /* Complete now if there are no backing file sectors to read */
+    if (pos >= backing_length) {
+        cb(opaque, 0);
+        return;
+    }
+
+    /* If the read straddles the end of the backing file, shorten it */
+    size = MIN((uint64_t)backing_length - pos, qiov->size);
+
+    BLKDBG_EVENT(s->bs->file, BLKDBG_READ_BACKING);
+    aiocb = bdrv_aio_readv(s->bs->backing_hd, pos / BDRV_SECTOR_SIZE,
+                           qiov, size / BDRV_SECTOR_SIZE, cb, opaque);
+    if (!aiocb) {
+        cb(opaque, -EIO);
+    }
+}
+
+typedef struct {
+    GenericCB gencb;
+    BDRVQEDState *s;
+    QEMUIOVector qiov;
+    struct iovec iov;
+    uint64_t offset;
+} CopyFromBackingFileCB;
+
+static void qed_copy_from_backing_file_cb(void *opaque, int ret)
+{
+    CopyFromBackingFileCB *copy_cb = opaque;
+    qemu_vfree(copy_cb->iov.iov_base);
+    gencb_complete(&copy_cb->gencb, ret);
+}
+
+static void qed_copy_from_backing_file_write(void *opaque, int ret)
+{
+    CopyFromBackingFileCB *copy_cb = opaque;
+    BDRVQEDState *s = copy_cb->s;
+    BlockDriverAIOCB *aiocb;
+
+    if (ret) {
+        qed_copy_from_backing_file_cb(copy_cb, ret);
+        return;
+    }
+
+    BLKDBG_EVENT(s->bs->file, BLKDBG_COW_WRITE);
+    aiocb = bdrv_aio_writev(s->bs->file, copy_cb->offset / BDRV_SECTOR_SIZE,
+                            &copy_cb->qiov,
+                            copy_cb->qiov.size / BDRV_SECTOR_SIZE,
+                            qed_copy_from_backing_file_cb, copy_cb);
+    if (!aiocb) {
+        qed_copy_from_backing_file_cb(copy_cb, -EIO);
+    }
+}
+
+/**
+ * Copy data from backing file into the image
+ *
+ * @s:          QED state
+ * @pos:        Byte position in device
+ * @len:        Number of bytes
+ * @offset:     Byte offset in image file
+ * @cb:         Completion function
+ * @opaque:     User data for completion function
+ */
+static void qed_copy_from_backing_file(BDRVQEDState *s, uint64_t pos,
+                                       uint64_t len, uint64_t offset,
+                                       BlockDriverCompletionFunc *cb,
+                                       void *opaque)
+{
+    CopyFromBackingFileCB *copy_cb;
+
+    /* Skip copy entirely if there is no work to do */
+    if (len == 0) {
+        cb(opaque, 0);
+        return;
+    }
+
+    copy_cb = gencb_alloc(sizeof(*copy_cb), cb, opaque);
+    copy_cb->s = s;
+    copy_cb->offset = offset;
+    copy_cb->iov.iov_base = qemu_blockalign(s->bs, len);
+    copy_cb->iov.iov_len = len;
+    qemu_iovec_init_external(&copy_cb->qiov, &copy_cb->iov, 1);
+
+    qed_read_backing_file(s, pos, &copy_cb->qiov,
+                          qed_copy_from_backing_file_write, copy_cb);
+}
+
+/**
+ * Link one or more contiguous clusters into a table
+ *
+ * @s:              QED state
+ * @table:          L2 table
+ * @index:          First cluster index
+ * @n:              Number of contiguous clusters
+ * @cluster:        First cluster byte offset in image file
+ */
+static void qed_update_l2_table(BDRVQEDState *s, QEDTable *table, int index,
+                                unsigned int n, uint64_t cluster)
+{
+    int i;
+    for (i = index; i < index + n; i++) {
+        table->offsets[i] = cluster;
+        cluster += s->header.cluster_size;
+    }
+}
+
+static void qed_aio_complete_bh(void *opaque)
+{
+    QEDAIOCB *acb = opaque;
+    BlockDriverCompletionFunc *cb = acb->common.cb;
+    void *user_opaque = acb->common.opaque;
+    int ret = acb->bh_ret;
+    bool *finished = acb->finished;
+
+    qemu_bh_delete(acb->bh);
+    qemu_aio_release(acb);
+
+    /* Invoke callback */
+    cb(user_opaque, ret);
+
+    /* Signal cancel completion */
+    if (finished) {
+        *finished = true;
+    }
+}
+
+static void qed_aio_complete(QEDAIOCB *acb, int ret)
+{
+    BDRVQEDState *s = acb_to_s(acb);
+
+    trace_qed_aio_complete(s, acb, ret);
+
+    /* Free resources */
+    qemu_iovec_destroy(&acb->cur_qiov);
+    qed_unref_l2_cache_entry(acb->request.l2_table);
+
+    /* Arrange for a bh to invoke the completion function */
+    acb->bh_ret = ret;
+    acb->bh = qemu_bh_new(qed_aio_complete_bh, acb);
+    qemu_bh_schedule(acb->bh);
+
+    /* Start next allocating write request waiting behind this one.  Note that
+     * requests enqueue themselves when they first hit an unallocated cluster
+     * but they wait until the entire request is finished before waking up the
+     * next request in the queue.  This ensures that we don't cycle through
+     * requests multiple times but rather finish one at a time completely.
+     */
+    if (acb == QSIMPLEQ_FIRST(&s->allocating_write_reqs)) {
+        QSIMPLEQ_REMOVE_HEAD(&s->allocating_write_reqs, next);
+        acb = QSIMPLEQ_FIRST(&s->allocating_write_reqs);
+        if (acb) {
+            qed_aio_next_io(acb, 0);
+        }
+    }
+}
+
+/**
+ * Commit the current L2 table to the cache
+ */
+static void qed_commit_l2_update(void *opaque, int ret)
+{
+    QEDAIOCB *acb = opaque;
+    BDRVQEDState *s = acb_to_s(acb);
+    CachedL2Table *l2_table = acb->request.l2_table;
+
+    qed_commit_l2_cache_entry(&s->l2_cache, l2_table);
+
+    /* This is guaranteed to succeed because we just committed the entry to the
+     * cache.
+     */
+    acb->request.l2_table = qed_find_l2_cache_entry(&s->l2_cache,
+                                                    l2_table->offset);
+    assert(acb->request.l2_table != NULL);
+
+    qed_aio_next_io(opaque, ret);
+}
+
+/**
+ * Update L1 table with new L2 table offset and write it out
+ */
+static void qed_aio_write_l1_update(void *opaque, int ret)
+{
+    QEDAIOCB *acb = opaque;
+    BDRVQEDState *s = acb_to_s(acb);
+    int index;
+
+    if (ret) {
+        qed_aio_complete(acb, ret);
+        return;
+    }
+
+    index = qed_l1_index(s, acb->cur_pos);
+    s->l1_table->offsets[index] = acb->request.l2_table->offset;
+
+    qed_write_l1_table(s, index, 1, qed_commit_l2_update, acb);
+}
+
+/**
+ * Update L2 table with new cluster offsets and write them out
+ */
+static void qed_aio_write_l2_update(void *opaque, int ret)
+{
+    QEDAIOCB *acb = opaque;
+    BDRVQEDState *s = acb_to_s(acb);
+    bool need_alloc = acb->find_cluster_ret == QED_CLUSTER_L1;
+    int index;
+
+    if (ret) {
+        goto err;
+    }
+
+    if (need_alloc) {
+        qed_unref_l2_cache_entry(acb->request.l2_table);
+        acb->request.l2_table = qed_new_l2_table(s);
+    }
+
+    index = qed_l2_index(s, acb->cur_pos);
+    qed_update_l2_table(s, acb->request.l2_table->table, index, acb->cur_nclusters,
+                         acb->cur_cluster);
+
+    if (need_alloc) {
+        /* Write out the whole new L2 table */
+        qed_write_l2_table(s, &acb->request, 0, s->table_nelems, true,
+                            qed_aio_write_l1_update, acb);
+    } else {
+        /* Write out only the updated part of the L2 table */
+        qed_write_l2_table(s, &acb->request, index, acb->cur_nclusters, false,
+                            qed_aio_next_io, acb);
+    }
+    return;
+
+err:
+    qed_aio_complete(acb, ret);
+}
+
+/**
+ * Flush new data clusters before updating the L2 table
+ *
+ * This flush is necessary when a backing file is in use.  A crash during an
+ * allocating write could result in empty clusters in the image.  If the write
+ * only touched a subregion of the cluster, then backing image sectors have
+ * been lost in the untouched region.  The solution is to flush after writing a
+ * new data cluster and before updating the L2 table.
+ */
+static void qed_aio_write_flush_before_l2_update(void *opaque, int ret)
+{
+    QEDAIOCB *acb = opaque;
+    BDRVQEDState *s = acb_to_s(acb);
+
+    if (!bdrv_aio_flush(s->bs->file, qed_aio_write_l2_update, opaque)) {
+        qed_aio_complete(acb, -EIO);
+    }
+}
+
+/**
+ * Write data to the image file
+ */
+static void qed_aio_write_main(void *opaque, int ret)
+{
+    QEDAIOCB *acb = opaque;
+    BDRVQEDState *s = acb_to_s(acb);
+    uint64_t offset = acb->cur_cluster +
+                      qed_offset_into_cluster(s, acb->cur_pos);
+    BlockDriverCompletionFunc *next_fn;
+    BlockDriverAIOCB *file_acb;
+
+    trace_qed_aio_write_main(s, acb, ret, offset, acb->cur_qiov.size);
+
+    if (ret) {
+        qed_aio_complete(acb, ret);
+        return;
+    }
+
+    if (acb->find_cluster_ret == QED_CLUSTER_FOUND) {
+        next_fn = qed_aio_next_io;
+    } else {
+        if (s->bs->backing_hd) {
+            next_fn = qed_aio_write_flush_before_l2_update;
+        } else {
+            next_fn = qed_aio_write_l2_update;
+        }
+    }
+
+    BLKDBG_EVENT(s->bs->file, BLKDBG_WRITE_AIO);
+    file_acb = bdrv_aio_writev(s->bs->file, offset / BDRV_SECTOR_SIZE,
+                               &acb->cur_qiov,
+                               acb->cur_qiov.size / BDRV_SECTOR_SIZE,
+                               next_fn, acb);
+    if (!file_acb) {
+        qed_aio_complete(acb, -EIO);
+    }
+}
+
+/**
+ * Populate back untouched region of new data cluster
+ */
+static void qed_aio_write_postfill(void *opaque, int ret)
+{
+    QEDAIOCB *acb = opaque;
+    BDRVQEDState *s = acb_to_s(acb);
+    uint64_t start = acb->cur_pos + acb->cur_qiov.size;
+    uint64_t len =
+        qed_start_of_cluster(s, start + s->header.cluster_size - 1) - start;
+    uint64_t offset = acb->cur_cluster +
+                      qed_offset_into_cluster(s, acb->cur_pos) +
+                      acb->cur_qiov.size;
+
+    if (ret) {
+        qed_aio_complete(acb, ret);
+        return;
+    }
+
+    trace_qed_aio_write_postfill(s, acb, start, len, offset);
+    qed_copy_from_backing_file(s, start, len, offset,
+                                qed_aio_write_main, acb);
+}
+
+/**
+ * Populate front untouched region of new data cluster
+ */
+static void qed_aio_write_prefill(void *opaque, int ret)
+{
+    QEDAIOCB *acb = opaque;
+    BDRVQEDState *s = acb_to_s(acb);
+    uint64_t start = qed_start_of_cluster(s, acb->cur_pos);
+    uint64_t len = qed_offset_into_cluster(s, acb->cur_pos);
+
+    trace_qed_aio_write_prefill(s, acb, start, len, acb->cur_cluster);
+    qed_copy_from_backing_file(s, start, len, acb->cur_cluster,
+                                qed_aio_write_postfill, acb);
+}
+
+/**
+ * Write new data cluster
+ *
+ * @acb:        Write request
+ * @len:        Length in bytes
+ *
+ * This path is taken when writing to previously unallocated clusters.
+ */
+static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
+{
+    BDRVQEDState *s = acb_to_s(acb);
+
+    /* Freeze this request if another allocating write is in progress */
+    if (acb != QSIMPLEQ_FIRST(&s->allocating_write_reqs)) {
+        QSIMPLEQ_INSERT_TAIL(&s->allocating_write_reqs, acb, next);
+    }
+    if (acb != QSIMPLEQ_FIRST(&s->allocating_write_reqs)) {
+        return; /* wait for existing request to finish */
+    }
+
+    acb->cur_nclusters = qed_bytes_to_clusters(s,
+            qed_offset_into_cluster(s, acb->cur_pos) + len);
+    acb->cur_cluster = qed_alloc_clusters(s, acb->cur_nclusters);
+    qemu_iovec_copy(&acb->cur_qiov, acb->qiov, acb->qiov_offset, len);
+
+    /* Write new cluster */
+    qed_aio_write_prefill(acb, 0);
+}
+
+/**
+ * Write data cluster in place
+ *
+ * @acb:        Write request
+ * @offset:     Cluster offset in bytes
+ * @len:        Length in bytes
+ *
+ * This path is taken when writing to already allocated clusters.
+ */
+static void qed_aio_write_inplace(QEDAIOCB *acb, uint64_t offset, size_t len)
+{
+    /* Calculate the I/O vector */
+    acb->cur_cluster = offset;
+    qemu_iovec_copy(&acb->cur_qiov, acb->qiov, acb->qiov_offset, len);
+
+    /* Do the actual write */
+    qed_aio_write_main(acb, 0);
+}
+
+/**
+ * Write data cluster
+ *
+ * @opaque:     Write request
+ * @ret:        QED_CLUSTER_FOUND, QED_CLUSTER_L2, QED_CLUSTER_L1,
+ *              or -errno
+ * @offset:     Cluster offset in bytes
+ * @len:        Length in bytes
+ *
+ * Callback from qed_find_cluster().
+ */
+static void qed_aio_write_data(void *opaque, int ret,
+                               uint64_t offset, size_t len)
+{
+    QEDAIOCB *acb = opaque;
+
+    trace_qed_aio_write_data(acb_to_s(acb), acb, ret, offset, len);
+
+    acb->find_cluster_ret = ret;
+
+    switch (ret) {
+    case QED_CLUSTER_FOUND:
+        qed_aio_write_inplace(acb, offset, len);
+        break;
+
+    case QED_CLUSTER_L2:
+    case QED_CLUSTER_L1:
+        qed_aio_write_alloc(acb, len);
+        break;
+
+    default:
+        qed_aio_complete(acb, ret);
+        break;
+    }
+}
+
+/**
+ * Read data cluster
+ *
+ * @opaque:     Read request
+ * @ret:        QED_CLUSTER_FOUND, QED_CLUSTER_L2, QED_CLUSTER_L1,
+ *              or -errno
+ * @offset:     Cluster offset in bytes
+ * @len:        Length in bytes
+ *
+ * Callback from qed_find_cluster().
+ */
+static void qed_aio_read_data(void *opaque, int ret,
+                              uint64_t offset, size_t len)
+{
+    QEDAIOCB *acb = opaque;
+    BDRVQEDState *s = acb_to_s(acb);
+    BlockDriverState *bs = acb->common.bs;
+    BlockDriverAIOCB *file_acb;
+
+    /* Adjust offset into cluster */
+    offset += qed_offset_into_cluster(s, acb->cur_pos);
+
+    trace_qed_aio_read_data(s, acb, ret, offset, len);
+
+    if (ret < 0) {
+        goto err;
+    }
+
+    qemu_iovec_copy(&acb->cur_qiov, acb->qiov, acb->qiov_offset, len);
+
+    /* Handle backing file and unallocated sparse hole reads */
+    if (ret != QED_CLUSTER_FOUND) {
+        qed_read_backing_file(s, acb->cur_pos, &acb->cur_qiov,
+                              qed_aio_next_io, acb);
+        return;
+    }
+
+    BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
+    file_acb = bdrv_aio_readv(bs->file, offset / BDRV_SECTOR_SIZE,
+                              &acb->cur_qiov,
+                              acb->cur_qiov.size / BDRV_SECTOR_SIZE,
+                              qed_aio_next_io, acb);
+    if (!file_acb) {
+        ret = -EIO;
+        goto err;
+    }
+    return;
+
+err:
+    qed_aio_complete(acb, ret);
+}
+
+/**
+ * Begin next I/O or complete the request
+ */
+static void qed_aio_next_io(void *opaque, int ret)
+{
+    QEDAIOCB *acb = opaque;
+    BDRVQEDState *s = acb_to_s(acb);
+    QEDFindClusterFunc *io_fn =
+        acb->is_write ? qed_aio_write_data : qed_aio_read_data;
+
+    trace_qed_aio_next_io(s, acb, ret, acb->cur_pos + acb->cur_qiov.size);
+
+    /* Handle I/O error */
+    if (ret) {
+        qed_aio_complete(acb, ret);
+        return;
+    }
+
+    acb->qiov_offset += acb->cur_qiov.size;
+    acb->cur_pos += acb->cur_qiov.size;
+    qemu_iovec_reset(&acb->cur_qiov);
+
+    /* Complete request */
+    if (acb->cur_pos >= acb->end_pos) {
+        qed_aio_complete(acb, 0);
+        return;
+    }
+
+    /* Find next cluster and start I/O */
+    qed_find_cluster(s, &acb->request,
+                      acb->cur_pos, acb->end_pos - acb->cur_pos,
+                      io_fn, acb);
+}
+
+static BlockDriverAIOCB *qed_aio_setup(BlockDriverState *bs,
+                                       int64_t sector_num,
+                                       QEMUIOVector *qiov, int nb_sectors,
+                                       BlockDriverCompletionFunc *cb,
+                                       void *opaque, bool is_write)
+{
+    QEDAIOCB *acb = qemu_aio_get(&qed_aio_pool, bs, cb, opaque);
+
+    trace_qed_aio_setup(bs->opaque, acb, sector_num, nb_sectors,
+                         opaque, is_write);
+
+    acb->is_write = is_write;
+    acb->finished = NULL;
+    acb->qiov = qiov;
+    acb->qiov_offset = 0;
+    acb->cur_pos = (uint64_t)sector_num * BDRV_SECTOR_SIZE;
+    acb->end_pos = acb->cur_pos + nb_sectors * BDRV_SECTOR_SIZE;
+    acb->request.l2_table = NULL;
+    qemu_iovec_init(&acb->cur_qiov, qiov->niov);
+
+    /* Start request */
+    qed_aio_next_io(acb, 0);
+    return &acb->common;
+}
+
 static BlockDriverAIOCB *bdrv_qed_aio_readv(BlockDriverState *bs,
                                             int64_t sector_num,
                                             QEMUIOVector *qiov, int nb_sectors,
                                             BlockDriverCompletionFunc *cb,
                                             void *opaque)
 {
-    return NULL;
+    return qed_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, false);
 }
 
 static BlockDriverAIOCB *bdrv_qed_aio_writev(BlockDriverState *bs,
@@ -446,7 +1070,7 @@ static BlockDriverAIOCB *bdrv_qed_aio_writev(BlockDriverState *bs,
                                              BlockDriverCompletionFunc *cb,
                                              void *opaque)
 {
-    return NULL;
+    return qed_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, true);
 }
 
 static BlockDriverAIOCB *bdrv_qed_aio_flush(BlockDriverState *bs,
diff --git a/block/qed.h b/block/qed.h
index 6d49a4d..046a410 100644
--- a/block/qed.h
+++ b/block/qed.h
@@ -116,6 +116,29 @@ typedef struct QEDRequest {
     CachedL2Table *l2_table;
 } QEDRequest;
 
+typedef struct QEDAIOCB {
+    BlockDriverAIOCB common;
+    QEMUBH *bh;
+    int bh_ret;                     /* final return status for completion bh */
+    QSIMPLEQ_ENTRY(QEDAIOCB) next;  /* next request */
+    bool is_write;                  /* false - read, true - write */
+    bool *finished;                 /* signal for cancel completion */
+    uint64_t end_pos;               /* request end on block device, in bytes */
+
+    /* User scatter-gather list */
+    QEMUIOVector *qiov;
+    size_t qiov_offset;             /* byte count already processed */
+
+    /* Current cluster scatter-gather list */
+    QEMUIOVector cur_qiov;
+    uint64_t cur_pos;               /* position on block device, in bytes */
+    uint64_t cur_cluster;           /* cluster offset in image file */
+    unsigned int cur_nclusters;     /* number of clusters being accessed */
+    int find_cluster_ret;           /* used for L1/L2 update */
+
+    QEDRequest request;
+} QEDAIOCB;
+
 typedef struct {
     BlockDriverState *bs;           /* device */
     uint64_t file_size;             /* length of image file, in bytes */
@@ -127,6 +150,9 @@ typedef struct {
     uint32_t l1_shift;
     uint32_t l2_shift;
     uint32_t l2_mask;
+
+    /* Allocating write request queue */
+    QSIMPLEQ_HEAD(, QEDAIOCB) allocating_write_reqs;
 } BDRVQEDState;
 
 enum {
diff --git a/trace-events b/trace-events
index 59f97a2..e8fed0f 100644
--- a/trace-events
+++ b/trace-events
@@ -203,3 +203,13 @@ disable qed_read_table(void *s, uint64_t offset, void *table) "s %p offset %"PRI
 disable qed_read_table_cb(void *s, void *table, int ret) "s %p table %p ret %d"
 disable qed_write_table(void *s, uint64_t offset, void *table, unsigned int index, unsigned int n) "s %p offset %"PRIu64" table %p index %u n %u"
 disable qed_write_table_cb(void *s, void *table, int flush, int ret) "s %p table %p flush %d ret %d"
+
+# block/qed.c
+disable qed_aio_complete(void *s, void *acb, int ret) "s %p acb %p ret %d"
+disable qed_aio_setup(void *s, void *acb, int64_t sector_num, int nb_sectors, void *opaque, int is_write) "s %p acb %p sector_num %"PRId64" nb_sectors %d opaque %p is_write %d"
+disable qed_aio_next_io(void *s, void *acb, int ret, uint64_t cur_pos) "s %p acb %p ret %d cur_pos %"PRIu64""
+disable qed_aio_read_data(void *s, void *acb, int ret, uint64_t offset, size_t len) "s %p acb %p ret %d offset %"PRIu64" len %zu"
+disable qed_aio_write_data(void *s, void *acb, int ret, uint64_t offset, size_t len) "s %p acb %p ret %d offset %"PRIu64" len %zu"
+disable qed_aio_write_prefill(void *s, void *acb, uint64_t start, size_t len, uint64_t offset) "s %p acb %p start %"PRIu64" len %zu offset %"PRIu64""
+disable qed_aio_write_postfill(void *s, void *acb, uint64_t start, size_t len, uint64_t offset) "s %p acb %p start %"PRIu64" len %zu offset %"PRIu64""
+disable qed_aio_write_main(void *s, void *acb, int ret, uint64_t offset, size_t len) "s %p acb %p ret %d offset %"PRIu64" len %zu"
commit 298800cae72eb2a549374189e87615b2b0b79262
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Mon Dec 6 16:08:01 2010 +0000

    qed: Table, L2 cache, and cluster functions
    
    This patch adds code to look up data cluster offsets in the image via
    the L1/L2 tables.  The L2 tables are writethrough cached in memory for
    performance (each read/write requires a lookup so it is essential to
    cache the tables).
    
    With cluster lookup code in place it is possible to implement
    bdrv_is_allocated() to query the number of contiguous
    allocated/unallocated clusters.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/Makefile.objs b/Makefile.objs
index 50b91e8..1860152 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -20,7 +20,7 @@ block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
 
 block-nested-y += raw.o cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o
 block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o
-block-nested-y += qed.o
+block-nested-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
 block-nested-y += parallels.o nbd.o blkdebug.o sheepdog.o blkverify.o
 block-nested-$(CONFIG_WIN32) += raw-win32.o
 block-nested-$(CONFIG_POSIX) += raw-posix.o
diff --git a/block/qed-cluster.c b/block/qed-cluster.c
new file mode 100644
index 0000000..0ec864b
--- /dev/null
+++ b/block/qed-cluster.c
@@ -0,0 +1,154 @@
+/*
+ * QEMU Enhanced Disk Format Cluster functions
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Stefan Hajnoczi   <stefanha at linux.vnet.ibm.com>
+ *  Anthony Liguori   <aliguori at us.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 "qed.h"
+
+/**
+ * Count the number of contiguous data clusters
+ *
+ * @s:              QED state
+ * @table:          L2 table
+ * @index:          First cluster index
+ * @n:              Maximum number of clusters
+ * @offset:         Set to first cluster offset
+ *
+ * This function scans tables for contiguous allocated or free clusters.
+ */
+static unsigned int qed_count_contiguous_clusters(BDRVQEDState *s,
+                                                  QEDTable *table,
+                                                  unsigned int index,
+                                                  unsigned int n,
+                                                  uint64_t *offset)
+{
+    unsigned int end = MIN(index + n, s->table_nelems);
+    uint64_t last = table->offsets[index];
+    unsigned int i;
+
+    *offset = last;
+
+    for (i = index + 1; i < end; i++) {
+        if (last == 0) {
+            /* Counting free clusters */
+            if (table->offsets[i] != 0) {
+                break;
+            }
+        } else {
+            /* Counting allocated clusters */
+            if (table->offsets[i] != last + s->header.cluster_size) {
+                break;
+            }
+            last = table->offsets[i];
+        }
+    }
+    return i - index;
+}
+
+typedef struct {
+    BDRVQEDState *s;
+    uint64_t pos;
+    size_t len;
+
+    QEDRequest *request;
+
+    /* User callback */
+    QEDFindClusterFunc *cb;
+    void *opaque;
+} QEDFindClusterCB;
+
+static void qed_find_cluster_cb(void *opaque, int ret)
+{
+    QEDFindClusterCB *find_cluster_cb = opaque;
+    BDRVQEDState *s = find_cluster_cb->s;
+    QEDRequest *request = find_cluster_cb->request;
+    uint64_t offset = 0;
+    size_t len = 0;
+    unsigned int index;
+    unsigned int n;
+
+    if (ret) {
+        goto out;
+    }
+
+    index = qed_l2_index(s, find_cluster_cb->pos);
+    n = qed_bytes_to_clusters(s,
+                              qed_offset_into_cluster(s, find_cluster_cb->pos) +
+                              find_cluster_cb->len);
+    n = qed_count_contiguous_clusters(s, request->l2_table->table,
+                                      index, n, &offset);
+
+    ret = offset ? QED_CLUSTER_FOUND : QED_CLUSTER_L2;
+    len = MIN(find_cluster_cb->len, n * s->header.cluster_size -
+              qed_offset_into_cluster(s, find_cluster_cb->pos));
+
+    if (offset && !qed_check_cluster_offset(s, offset)) {
+        ret = -EINVAL;
+    }
+
+out:
+    find_cluster_cb->cb(find_cluster_cb->opaque, ret, offset, len);
+    qemu_free(find_cluster_cb);
+}
+
+/**
+ * Find the offset of a data cluster
+ *
+ * @s:          QED state
+ * @request:    L2 cache entry
+ * @pos:        Byte position in device
+ * @len:        Number of bytes
+ * @cb:         Completion function
+ * @opaque:     User data for completion function
+ *
+ * This function translates a position in the block device to an offset in the
+ * image file.  It invokes the cb completion callback to report back the
+ * translated offset or unallocated range in the image file.
+ *
+ * If the L2 table exists, request->l2_table points to the L2 table cache entry
+ * and the caller must free the reference when they are finished.  The cache
+ * entry is exposed in this way to avoid callers having to read the L2 table
+ * again later during request processing.  If request->l2_table is non-NULL it
+ * will be unreferenced before taking on the new cache entry.
+ */
+void qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
+                      size_t len, QEDFindClusterFunc *cb, void *opaque)
+{
+    QEDFindClusterCB *find_cluster_cb;
+    uint64_t l2_offset;
+
+    /* Limit length to L2 boundary.  Requests are broken up at the L2 boundary
+     * so that a request acts on one L2 table at a time.
+     */
+    len = MIN(len, (((pos >> s->l1_shift) + 1) << s->l1_shift) - pos);
+
+    l2_offset = s->l1_table->offsets[qed_l1_index(s, pos)];
+    if (!l2_offset) {
+        cb(opaque, QED_CLUSTER_L1, 0, len);
+        return;
+    }
+    if (!qed_check_table_offset(s, l2_offset)) {
+        cb(opaque, -EINVAL, 0, 0);
+        return;
+    }
+
+    find_cluster_cb = qemu_malloc(sizeof(*find_cluster_cb));
+    find_cluster_cb->s = s;
+    find_cluster_cb->pos = pos;
+    find_cluster_cb->len = len;
+    find_cluster_cb->cb = cb;
+    find_cluster_cb->opaque = opaque;
+    find_cluster_cb->request = request;
+
+    qed_read_l2_table(s, request, l2_offset,
+                      qed_find_cluster_cb, find_cluster_cb);
+}
diff --git a/block/qed-gencb.c b/block/qed-gencb.c
new file mode 100644
index 0000000..1513dc6
--- /dev/null
+++ b/block/qed-gencb.c
@@ -0,0 +1,32 @@
+/*
+ * QEMU Enhanced Disk Format
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * 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 "qed.h"
+
+void *gencb_alloc(size_t len, BlockDriverCompletionFunc *cb, void *opaque)
+{
+    GenericCB *gencb = qemu_malloc(len);
+    gencb->cb = cb;
+    gencb->opaque = opaque;
+    return gencb;
+}
+
+void gencb_complete(void *opaque, int ret)
+{
+    GenericCB *gencb = opaque;
+    BlockDriverCompletionFunc *cb = gencb->cb;
+    void *user_opaque = gencb->opaque;
+
+    qemu_free(gencb);
+    cb(user_opaque, ret);
+}
diff --git a/block/qed-l2-cache.c b/block/qed-l2-cache.c
new file mode 100644
index 0000000..57518a4
--- /dev/null
+++ b/block/qed-l2-cache.c
@@ -0,0 +1,173 @@
+/*
+ * QEMU Enhanced Disk Format L2 Cache
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.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.
+ *
+ */
+
+/*
+ * L2 table cache usage is as follows:
+ *
+ * An open image has one L2 table cache that is used to avoid accessing the
+ * image file for recently referenced L2 tables.
+ *
+ * Cluster offset lookup translates the logical offset within the block device
+ * to a cluster offset within the image file.  This is done by indexing into
+ * the L1 and L2 tables which store cluster offsets.  It is here where the L2
+ * table cache serves up recently referenced L2 tables.
+ *
+ * If there is a cache miss, that L2 table is read from the image file and
+ * committed to the cache.  Subsequent accesses to that L2 table will be served
+ * from the cache until the table is evicted from the cache.
+ *
+ * L2 tables are also committed to the cache when new L2 tables are allocated
+ * in the image file.  Since the L2 table cache is write-through, the new L2
+ * table is first written out to the image file and then committed to the
+ * cache.
+ *
+ * Multiple I/O requests may be using an L2 table cache entry at any given
+ * time.  That means an entry may be in use across several requests and
+ * reference counting is needed to free the entry at the correct time.  In
+ * particular, an entry evicted from the cache will only be freed once all
+ * references are dropped.
+ *
+ * An in-flight I/O request will hold a reference to a L2 table cache entry for
+ * the period during which it needs to access the L2 table.  This includes
+ * cluster offset lookup, L2 table allocation, and L2 table update when a new
+ * data cluster has been allocated.
+ *
+ * An interesting case occurs when two requests need to access an L2 table that
+ * is not in the cache.  Since the operation to read the table from the image
+ * file takes some time to complete, both requests may see a cache miss and
+ * start reading the L2 table from the image file.  The first to finish will
+ * commit its L2 table into the cache.  When the second tries to commit its
+ * table will be deleted in favor of the existing cache entry.
+ */
+
+#include "trace.h"
+#include "qed.h"
+
+/* Each L2 holds 2GB so this let's us fully cache a 100GB disk */
+#define MAX_L2_CACHE_SIZE 50
+
+/**
+ * Initialize the L2 cache
+ */
+void qed_init_l2_cache(L2TableCache *l2_cache)
+{
+    QTAILQ_INIT(&l2_cache->entries);
+    l2_cache->n_entries = 0;
+}
+
+/**
+ * Free the L2 cache
+ */
+void qed_free_l2_cache(L2TableCache *l2_cache)
+{
+    CachedL2Table *entry, *next_entry;
+
+    QTAILQ_FOREACH_SAFE(entry, &l2_cache->entries, node, next_entry) {
+        qemu_vfree(entry->table);
+        qemu_free(entry);
+    }
+}
+
+/**
+ * Allocate an uninitialized entry from the cache
+ *
+ * The returned entry has a reference count of 1 and is owned by the caller.
+ * The caller must allocate the actual table field for this entry and it must
+ * be freeable using qemu_vfree().
+ */
+CachedL2Table *qed_alloc_l2_cache_entry(L2TableCache *l2_cache)
+{
+    CachedL2Table *entry;
+
+    entry = qemu_mallocz(sizeof(*entry));
+    entry->ref++;
+
+    trace_qed_alloc_l2_cache_entry(l2_cache, entry);
+
+    return entry;
+}
+
+/**
+ * Decrease an entry's reference count and free if necessary when the reference
+ * count drops to zero.
+ */
+void qed_unref_l2_cache_entry(CachedL2Table *entry)
+{
+    if (!entry) {
+        return;
+    }
+
+    entry->ref--;
+    trace_qed_unref_l2_cache_entry(entry, entry->ref);
+    if (entry->ref == 0) {
+        qemu_vfree(entry->table);
+        qemu_free(entry);
+    }
+}
+
+/**
+ * Find an entry in the L2 cache.  This may return NULL and it's up to the
+ * caller to satisfy the cache miss.
+ *
+ * For a cached entry, this function increases the reference count and returns
+ * the entry.
+ */
+CachedL2Table *qed_find_l2_cache_entry(L2TableCache *l2_cache, uint64_t offset)
+{
+    CachedL2Table *entry;
+
+    QTAILQ_FOREACH(entry, &l2_cache->entries, node) {
+        if (entry->offset == offset) {
+            trace_qed_find_l2_cache_entry(l2_cache, entry, offset, entry->ref);
+            entry->ref++;
+            return entry;
+        }
+    }
+    return NULL;
+}
+
+/**
+ * Commit an L2 cache entry into the cache.  This is meant to be used as part of
+ * the process to satisfy a cache miss.  A caller would allocate an entry which
+ * is not actually in the L2 cache and then once the entry was valid and
+ * present on disk, the entry can be committed into the cache.
+ *
+ * Since the cache is write-through, it's important that this function is not
+ * called until the entry is present on disk and the L1 has been updated to
+ * point to the entry.
+ *
+ * N.B. This function steals a reference to the l2_table from the caller so the
+ * caller must obtain a new reference by issuing a call to
+ * qed_find_l2_cache_entry().
+ */
+void qed_commit_l2_cache_entry(L2TableCache *l2_cache, CachedL2Table *l2_table)
+{
+    CachedL2Table *entry;
+
+    entry = qed_find_l2_cache_entry(l2_cache, l2_table->offset);
+    if (entry) {
+        qed_unref_l2_cache_entry(entry);
+        qed_unref_l2_cache_entry(l2_table);
+        return;
+    }
+
+    if (l2_cache->n_entries >= MAX_L2_CACHE_SIZE) {
+        entry = QTAILQ_FIRST(&l2_cache->entries);
+        QTAILQ_REMOVE(&l2_cache->entries, entry, node);
+        l2_cache->n_entries--;
+        qed_unref_l2_cache_entry(entry);
+    }
+
+    l2_cache->n_entries++;
+    QTAILQ_INSERT_TAIL(&l2_cache->entries, l2_table, node);
+}
diff --git a/block/qed-table.c b/block/qed-table.c
new file mode 100644
index 0000000..d38c673
--- /dev/null
+++ b/block/qed-table.c
@@ -0,0 +1,319 @@
+/*
+ * QEMU Enhanced Disk Format Table I/O
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Stefan Hajnoczi   <stefanha at linux.vnet.ibm.com>
+ *  Anthony Liguori   <aliguori at us.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 "trace.h"
+#include "qemu_socket.h" /* for EINPROGRESS on Windows */
+#include "qed.h"
+
+typedef struct {
+    GenericCB gencb;
+    BDRVQEDState *s;
+    QEDTable *table;
+
+    struct iovec iov;
+    QEMUIOVector qiov;
+} QEDReadTableCB;
+
+static void qed_read_table_cb(void *opaque, int ret)
+{
+    QEDReadTableCB *read_table_cb = opaque;
+    QEDTable *table = read_table_cb->table;
+    int noffsets = read_table_cb->iov.iov_len / sizeof(uint64_t);
+    int i;
+
+    /* Handle I/O error */
+    if (ret) {
+        goto out;
+    }
+
+    /* Byteswap offsets */
+    for (i = 0; i < noffsets; i++) {
+        table->offsets[i] = le64_to_cpu(table->offsets[i]);
+    }
+
+out:
+    /* Completion */
+    trace_qed_read_table_cb(read_table_cb->s, read_table_cb->table, ret);
+    gencb_complete(&read_table_cb->gencb, ret);
+}
+
+static void qed_read_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
+                           BlockDriverCompletionFunc *cb, void *opaque)
+{
+    QEDReadTableCB *read_table_cb = gencb_alloc(sizeof(*read_table_cb),
+                                                cb, opaque);
+    QEMUIOVector *qiov = &read_table_cb->qiov;
+    BlockDriverAIOCB *aiocb;
+
+    trace_qed_read_table(s, offset, table);
+
+    read_table_cb->s = s;
+    read_table_cb->table = table;
+    read_table_cb->iov.iov_base = table->offsets,
+    read_table_cb->iov.iov_len = s->header.cluster_size * s->header.table_size,
+
+    qemu_iovec_init_external(qiov, &read_table_cb->iov, 1);
+    aiocb = bdrv_aio_readv(s->bs->file, offset / BDRV_SECTOR_SIZE, qiov,
+                           read_table_cb->iov.iov_len / BDRV_SECTOR_SIZE,
+                           qed_read_table_cb, read_table_cb);
+    if (!aiocb) {
+        qed_read_table_cb(read_table_cb, -EIO);
+    }
+}
+
+typedef struct {
+    GenericCB gencb;
+    BDRVQEDState *s;
+    QEDTable *orig_table;
+    QEDTable *table;
+    bool flush;             /* flush after write? */
+
+    struct iovec iov;
+    QEMUIOVector qiov;
+} QEDWriteTableCB;
+
+static void qed_write_table_cb(void *opaque, int ret)
+{
+    QEDWriteTableCB *write_table_cb = opaque;
+
+    trace_qed_write_table_cb(write_table_cb->s,
+                             write_table_cb->orig_table,
+                             write_table_cb->flush,
+                             ret);
+
+    if (ret) {
+        goto out;
+    }
+
+    if (write_table_cb->flush) {
+        /* We still need to flush first */
+        write_table_cb->flush = false;
+        bdrv_aio_flush(write_table_cb->s->bs, qed_write_table_cb,
+                       write_table_cb);
+        return;
+    }
+
+out:
+    qemu_vfree(write_table_cb->table);
+    gencb_complete(&write_table_cb->gencb, ret);
+    return;
+}
+
+/**
+ * Write out an updated part or all of a table
+ *
+ * @s:          QED state
+ * @offset:     Offset of table in image file, in bytes
+ * @table:      Table
+ * @index:      Index of first element
+ * @n:          Number of elements
+ * @flush:      Whether or not to sync to disk
+ * @cb:         Completion function
+ * @opaque:     Argument for completion function
+ */
+static void qed_write_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
+                            unsigned int index, unsigned int n, bool flush,
+                            BlockDriverCompletionFunc *cb, void *opaque)
+{
+    QEDWriteTableCB *write_table_cb;
+    BlockDriverAIOCB *aiocb;
+    unsigned int sector_mask = BDRV_SECTOR_SIZE / sizeof(uint64_t) - 1;
+    unsigned int start, end, i;
+    size_t len_bytes;
+
+    trace_qed_write_table(s, offset, table, index, n);
+
+    /* Calculate indices of the first and one after last elements */
+    start = index & ~sector_mask;
+    end = (index + n + sector_mask) & ~sector_mask;
+
+    len_bytes = (end - start) * sizeof(uint64_t);
+
+    write_table_cb = gencb_alloc(sizeof(*write_table_cb), cb, opaque);
+    write_table_cb->s = s;
+    write_table_cb->orig_table = table;
+    write_table_cb->flush = flush;
+    write_table_cb->table = qemu_blockalign(s->bs, len_bytes);
+    write_table_cb->iov.iov_base = write_table_cb->table->offsets;
+    write_table_cb->iov.iov_len = len_bytes;
+    qemu_iovec_init_external(&write_table_cb->qiov, &write_table_cb->iov, 1);
+
+    /* Byteswap table */
+    for (i = start; i < end; i++) {
+        uint64_t le_offset = cpu_to_le64(table->offsets[i]);
+        write_table_cb->table->offsets[i - start] = le_offset;
+    }
+
+    /* Adjust for offset into table */
+    offset += start * sizeof(uint64_t);
+
+    aiocb = bdrv_aio_writev(s->bs->file, offset / BDRV_SECTOR_SIZE,
+                            &write_table_cb->qiov,
+                            write_table_cb->iov.iov_len / BDRV_SECTOR_SIZE,
+                            qed_write_table_cb, write_table_cb);
+    if (!aiocb) {
+        qed_write_table_cb(write_table_cb, -EIO);
+    }
+}
+
+/**
+ * Propagate return value from async callback
+ */
+static void qed_sync_cb(void *opaque, int ret)
+{
+    *(int *)opaque = ret;
+}
+
+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;
+}
+
+void qed_write_l1_table(BDRVQEDState *s, unsigned int index, unsigned int n,
+                        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BLKDBG_EVENT(s->bs->file, BLKDBG_L1_UPDATE);
+    qed_write_table(s, s->header.l1_table_offset,
+                    s->l1_table, index, n, false, cb, opaque);
+}
+
+int qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index,
+                            unsigned int n)
+{
+    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;
+}
+
+typedef struct {
+    GenericCB gencb;
+    BDRVQEDState *s;
+    uint64_t l2_offset;
+    QEDRequest *request;
+} QEDReadL2TableCB;
+
+static void qed_read_l2_table_cb(void *opaque, int ret)
+{
+    QEDReadL2TableCB *read_l2_table_cb = opaque;
+    QEDRequest *request = read_l2_table_cb->request;
+    BDRVQEDState *s = read_l2_table_cb->s;
+    CachedL2Table *l2_table = request->l2_table;
+
+    if (ret) {
+        /* can't trust loaded L2 table anymore */
+        qed_unref_l2_cache_entry(l2_table);
+        request->l2_table = NULL;
+    } else {
+        l2_table->offset = read_l2_table_cb->l2_offset;
+
+        qed_commit_l2_cache_entry(&s->l2_cache, l2_table);
+
+        /* This is guaranteed to succeed because we just committed the entry
+         * to the cache.
+         */
+        request->l2_table = qed_find_l2_cache_entry(&s->l2_cache,
+                                                    l2_table->offset);
+        assert(request->l2_table != NULL);
+    }
+
+    gencb_complete(&read_l2_table_cb->gencb, ret);
+}
+
+void qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset,
+                       BlockDriverCompletionFunc *cb, void *opaque)
+{
+    QEDReadL2TableCB *read_l2_table_cb;
+
+    qed_unref_l2_cache_entry(request->l2_table);
+
+    /* Check for cached L2 entry */
+    request->l2_table = qed_find_l2_cache_entry(&s->l2_cache, offset);
+    if (request->l2_table) {
+        cb(opaque, 0);
+        return;
+    }
+
+    request->l2_table = qed_alloc_l2_cache_entry(&s->l2_cache);
+    request->l2_table->table = qed_alloc_table(s);
+
+    read_l2_table_cb = gencb_alloc(sizeof(*read_l2_table_cb), cb, opaque);
+    read_l2_table_cb->s = s;
+    read_l2_table_cb->l2_offset = offset;
+    read_l2_table_cb->request = request;
+
+    BLKDBG_EVENT(s->bs->file, BLKDBG_L2_LOAD);
+    qed_read_table(s, offset, request->l2_table->table,
+                   qed_read_l2_table_cb, read_l2_table_cb);
+}
+
+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;
+}
+
+void qed_write_l2_table(BDRVQEDState *s, QEDRequest *request,
+                        unsigned int index, unsigned int n, bool flush,
+                        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BLKDBG_EVENT(s->bs->file, BLKDBG_L2_UPDATE);
+    qed_write_table(s, request->l2_table->offset,
+                    request->l2_table->table, index, n, flush, cb, opaque);
+}
+
+int qed_write_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
+                            unsigned int index, unsigned int n, bool flush)
+{
+    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 1436ac4..cd1bead 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -155,6 +155,13 @@ static int qed_read_string(BlockDriverState *file, uint64_t offset, size_t n,
     return 0;
 }
 
+QEDTable *qed_alloc_table(BDRVQEDState *s)
+{
+    /* Honor O_DIRECT memory alignment requirements */
+    return qemu_blockalign(s->bs,
+                           s->header.cluster_size * s->header.table_size);
+}
+
 static int bdrv_qed_open(BlockDriverState *bs, int flags)
 {
     BDRVQEDState *s = bs->opaque;
@@ -244,11 +251,23 @@ static int bdrv_qed_open(BlockDriverState *bs, int flags)
         bdrv_flush(bs->file);
     }
 
+    s->l1_table = qed_alloc_table(s);
+    qed_init_l2_cache(&s->l2_cache);
+
+    ret = qed_read_l1_table_sync(s);
+    if (ret) {
+        qed_free_l2_cache(&s->l2_cache);
+        qemu_vfree(s->l1_table);
+    }
     return ret;
 }
 
 static void bdrv_qed_close(BlockDriverState *bs)
 {
+    BDRVQEDState *s = bs->opaque;
+
+    qed_free_l2_cache(&s->l2_cache);
+    qemu_vfree(s->l1_table);
 }
 
 static int bdrv_qed_flush(BlockDriverState *bs)
@@ -368,10 +387,43 @@ static int bdrv_qed_create(const char *filename, QEMUOptionParameter *options)
                       backing_file, backing_fmt);
 }
 
+typedef struct {
+    int is_allocated;
+    int *pnum;
+} QEDIsAllocatedCB;
+
+static void qed_is_allocated_cb(void *opaque, int ret, uint64_t offset, size_t len)
+{
+    QEDIsAllocatedCB *cb = opaque;
+    *cb->pnum = len / BDRV_SECTOR_SIZE;
+    cb->is_allocated = ret == QED_CLUSTER_FOUND;
+}
+
 static int bdrv_qed_is_allocated(BlockDriverState *bs, int64_t sector_num,
                                   int nb_sectors, int *pnum)
 {
-    return -ENOTSUP;
+    BDRVQEDState *s = bs->opaque;
+    uint64_t pos = (uint64_t)sector_num * BDRV_SECTOR_SIZE;
+    size_t len = (size_t)nb_sectors * BDRV_SECTOR_SIZE;
+    QEDIsAllocatedCB cb = {
+        .is_allocated = -1,
+        .pnum = pnum,
+    };
+    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;
 }
 
 static int bdrv_qed_make_empty(BlockDriverState *bs)
diff --git a/block/qed.h b/block/qed.h
index 1f8a125..6d49a4d 100644
--- a/block/qed.h
+++ b/block/qed.h
@@ -96,16 +96,118 @@ typedef struct {
 } QEDHeader;
 
 typedef struct {
+    uint64_t offsets[0];            /* in bytes */
+} QEDTable;
+
+/* The L2 cache is a simple write-through cache for L2 structures */
+typedef struct CachedL2Table {
+    QEDTable *table;
+    uint64_t offset;    /* offset=0 indicates an invalidate entry */
+    QTAILQ_ENTRY(CachedL2Table) node;
+    int ref;
+} CachedL2Table;
+
+typedef struct {
+    QTAILQ_HEAD(, CachedL2Table) entries;
+    unsigned int n_entries;
+} L2TableCache;
+
+typedef struct QEDRequest {
+    CachedL2Table *l2_table;
+} QEDRequest;
+
+typedef struct {
     BlockDriverState *bs;           /* device */
     uint64_t file_size;             /* length of image file, in bytes */
 
     QEDHeader header;               /* always cpu-endian */
+    QEDTable *l1_table;
+    L2TableCache l2_cache;          /* l2 table cache */
     uint32_t table_nelems;
     uint32_t l1_shift;
     uint32_t l2_shift;
     uint32_t l2_mask;
 } BDRVQEDState;
 
+enum {
+    QED_CLUSTER_FOUND,         /* cluster found */
+    QED_CLUSTER_L2,            /* cluster missing in L2 */
+    QED_CLUSTER_L1,            /* cluster missing in L1 */
+};
+
+/**
+ * qed_find_cluster() completion callback
+ *
+ * @opaque:     User data for completion callback
+ * @ret:        QED_CLUSTER_FOUND   Success
+ *              QED_CLUSTER_L2      Data cluster unallocated in L2
+ *              QED_CLUSTER_L1      L2 unallocated in L1
+ *              -errno              POSIX error occurred
+ * @offset:     Data cluster offset
+ * @len:        Contiguous bytes starting from cluster offset
+ *
+ * This function is invoked when qed_find_cluster() completes.
+ *
+ * On success ret is QED_CLUSTER_FOUND and offset/len are a contiguous range
+ * in the image file.
+ *
+ * On failure ret is QED_CLUSTER_L2 or QED_CLUSTER_L1 for missing L2 or L1
+ * table offset, respectively.  len is number of contiguous unallocated bytes.
+ */
+typedef void QEDFindClusterFunc(void *opaque, int ret, uint64_t offset, size_t len);
+
+/**
+ * Generic callback for chaining async callbacks
+ */
+typedef struct {
+    BlockDriverCompletionFunc *cb;
+    void *opaque;
+} GenericCB;
+
+void *gencb_alloc(size_t len, BlockDriverCompletionFunc *cb, void *opaque);
+void gencb_complete(void *opaque, int ret);
+
+/**
+ * L2 cache functions
+ */
+void qed_init_l2_cache(L2TableCache *l2_cache);
+void qed_free_l2_cache(L2TableCache *l2_cache);
+CachedL2Table *qed_alloc_l2_cache_entry(L2TableCache *l2_cache);
+void qed_unref_l2_cache_entry(CachedL2Table *entry);
+CachedL2Table *qed_find_l2_cache_entry(L2TableCache *l2_cache, uint64_t offset);
+void qed_commit_l2_cache_entry(L2TableCache *l2_cache, CachedL2Table *l2_table);
+
+/**
+ * Table I/O functions
+ */
+int qed_read_l1_table_sync(BDRVQEDState *s);
+void qed_write_l1_table(BDRVQEDState *s, unsigned int index, unsigned int n,
+                        BlockDriverCompletionFunc *cb, void *opaque);
+int qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index,
+                            unsigned int n);
+int qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
+                           uint64_t offset);
+void qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset,
+                       BlockDriverCompletionFunc *cb, void *opaque);
+void qed_write_l2_table(BDRVQEDState *s, QEDRequest *request,
+                        unsigned int index, unsigned int n, bool flush,
+                        BlockDriverCompletionFunc *cb, void *opaque);
+int qed_write_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
+                            unsigned int index, unsigned int n, bool flush);
+
+/**
+ * Cluster functions
+ */
+void qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
+                      size_t len, QEDFindClusterFunc *cb, void *opaque);
+
+/**
+ * Consistency check
+ */
+int qed_check(BDRVQEDState *s, BdrvCheckResult *result, bool fix);
+
+QEDTable *qed_alloc_table(BDRVQEDState *s);
+
 /**
  * Round down to the start of a cluster
  */
@@ -114,6 +216,27 @@ static inline uint64_t qed_start_of_cluster(BDRVQEDState *s, uint64_t offset)
     return offset & ~(uint64_t)(s->header.cluster_size - 1);
 }
 
+static inline uint64_t qed_offset_into_cluster(BDRVQEDState *s, uint64_t offset)
+{
+    return offset & (s->header.cluster_size - 1);
+}
+
+static inline unsigned int qed_bytes_to_clusters(BDRVQEDState *s, size_t bytes)
+{
+    return qed_start_of_cluster(s, bytes + (s->header.cluster_size - 1)) /
+           (s->header.cluster_size - 1);
+}
+
+static inline unsigned int qed_l1_index(BDRVQEDState *s, uint64_t pos)
+{
+    return pos >> s->l1_shift;
+}
+
+static inline unsigned int qed_l2_index(BDRVQEDState *s, uint64_t pos)
+{
+    return (pos >> s->l2_shift) & s->l2_mask;
+}
+
 /**
  * Test if a cluster offset is valid
  */
diff --git a/trace-events b/trace-events
index da03d4b..59f97a2 100644
--- a/trace-events
+++ b/trace-events
@@ -192,3 +192,14 @@ disable sun4m_iommu_bad_addr(uint64_t addr) "bad addr %"PRIx64""
 
 # vl.c
 disable vm_state_notify(int running, int reason) "running %d reason %d"
+
+# block/qed-l2-cache.c
+disable qed_alloc_l2_cache_entry(void *l2_cache, void *entry) "l2_cache %p entry %p"
+disable qed_unref_l2_cache_entry(void *entry, int ref) "entry %p ref %d"
+disable qed_find_l2_cache_entry(void *l2_cache, void *entry, uint64_t offset, int ref) "l2_cache %p entry %p offset %"PRIu64" ref %d"
+
+# block/qed-table.c
+disable qed_read_table(void *s, uint64_t offset, void *table) "s %p offset %"PRIu64" table %p"
+disable qed_read_table_cb(void *s, void *table, int ret) "s %p table %p ret %d"
+disable qed_write_table(void *s, uint64_t offset, void *table, unsigned int index, unsigned int n) "s %p offset %"PRIu64" table %p index %u n %u"
+disable qed_write_table_cb(void *s, void *table, int flush, int ret) "s %p table %p flush %d ret %d"
commit 75411d236d93d79d8052e0116c3eeebe23e2778b
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Mon Dec 6 16:08:00 2010 +0000

    qed: Add QEMU Enhanced Disk image format
    
    This patch introduces the qed on-disk layout and implements image
    creation.  Later patches add read/write and other functionality.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/Makefile.objs b/Makefile.objs
index 72c07dd..50b91e8 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -20,6 +20,7 @@ block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
 
 block-nested-y += raw.o cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o
 block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o
+block-nested-y += qed.o
 block-nested-y += parallels.o nbd.o blkdebug.o sheepdog.o blkverify.o
 block-nested-$(CONFIG_WIN32) += raw-win32.o
 block-nested-$(CONFIG_POSIX) += raw-posix.o
diff --git a/block/qed.c b/block/qed.c
new file mode 100644
index 0000000..1436ac4
--- /dev/null
+++ b/block/qed.c
@@ -0,0 +1,554 @@
+/*
+ * QEMU Enhanced Disk Format
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Stefan Hajnoczi   <stefanha at linux.vnet.ibm.com>
+ *  Anthony Liguori   <aliguori at us.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 "qed.h"
+
+static int bdrv_qed_probe(const uint8_t *buf, int buf_size,
+                          const char *filename)
+{
+    const QEDHeader *header = (const QEDHeader *)buf;
+
+    if (buf_size < sizeof(*header)) {
+        return 0;
+    }
+    if (le32_to_cpu(header->magic) != QED_MAGIC) {
+        return 0;
+    }
+    return 100;
+}
+
+/**
+ * Check whether an image format is raw
+ *
+ * @fmt:    Backing file format, may be NULL
+ */
+static bool qed_fmt_is_raw(const char *fmt)
+{
+    return fmt && strcmp(fmt, "raw") == 0;
+}
+
+static void qed_header_le_to_cpu(const QEDHeader *le, QEDHeader *cpu)
+{
+    cpu->magic = le32_to_cpu(le->magic);
+    cpu->cluster_size = le32_to_cpu(le->cluster_size);
+    cpu->table_size = le32_to_cpu(le->table_size);
+    cpu->header_size = le32_to_cpu(le->header_size);
+    cpu->features = le64_to_cpu(le->features);
+    cpu->compat_features = le64_to_cpu(le->compat_features);
+    cpu->autoclear_features = le64_to_cpu(le->autoclear_features);
+    cpu->l1_table_offset = le64_to_cpu(le->l1_table_offset);
+    cpu->image_size = le64_to_cpu(le->image_size);
+    cpu->backing_filename_offset = le32_to_cpu(le->backing_filename_offset);
+    cpu->backing_filename_size = le32_to_cpu(le->backing_filename_size);
+}
+
+static void qed_header_cpu_to_le(const QEDHeader *cpu, QEDHeader *le)
+{
+    le->magic = cpu_to_le32(cpu->magic);
+    le->cluster_size = cpu_to_le32(cpu->cluster_size);
+    le->table_size = cpu_to_le32(cpu->table_size);
+    le->header_size = cpu_to_le32(cpu->header_size);
+    le->features = cpu_to_le64(cpu->features);
+    le->compat_features = cpu_to_le64(cpu->compat_features);
+    le->autoclear_features = cpu_to_le64(cpu->autoclear_features);
+    le->l1_table_offset = cpu_to_le64(cpu->l1_table_offset);
+    le->image_size = cpu_to_le64(cpu->image_size);
+    le->backing_filename_offset = cpu_to_le32(cpu->backing_filename_offset);
+    le->backing_filename_size = cpu_to_le32(cpu->backing_filename_size);
+}
+
+static int qed_write_header_sync(BDRVQEDState *s)
+{
+    QEDHeader le;
+    int ret;
+
+    qed_header_cpu_to_le(&s->header, &le);
+    ret = bdrv_pwrite(s->bs->file, 0, &le, sizeof(le));
+    if (ret != sizeof(le)) {
+        return ret;
+    }
+    return 0;
+}
+
+static uint64_t qed_max_image_size(uint32_t cluster_size, uint32_t table_size)
+{
+    uint64_t table_entries;
+    uint64_t l2_size;
+
+    table_entries = (table_size * cluster_size) / sizeof(uint64_t);
+    l2_size = table_entries * cluster_size;
+
+    return l2_size * table_entries;
+}
+
+static bool qed_is_cluster_size_valid(uint32_t cluster_size)
+{
+    if (cluster_size < QED_MIN_CLUSTER_SIZE ||
+        cluster_size > QED_MAX_CLUSTER_SIZE) {
+        return false;
+    }
+    if (cluster_size & (cluster_size - 1)) {
+        return false; /* not power of 2 */
+    }
+    return true;
+}
+
+static bool qed_is_table_size_valid(uint32_t table_size)
+{
+    if (table_size < QED_MIN_TABLE_SIZE ||
+        table_size > QED_MAX_TABLE_SIZE) {
+        return false;
+    }
+    if (table_size & (table_size - 1)) {
+        return false; /* not power of 2 */
+    }
+    return true;
+}
+
+static bool qed_is_image_size_valid(uint64_t image_size, uint32_t cluster_size,
+                                    uint32_t table_size)
+{
+    if (image_size % BDRV_SECTOR_SIZE != 0) {
+        return false; /* not multiple of sector size */
+    }
+    if (image_size > qed_max_image_size(cluster_size, table_size)) {
+        return false; /* image is too large */
+    }
+    return true;
+}
+
+/**
+ * Read a string of known length from the image file
+ *
+ * @file:       Image file
+ * @offset:     File offset to start of string, in bytes
+ * @n:          String length in bytes
+ * @buf:        Destination buffer
+ * @buflen:     Destination buffer length in bytes
+ * @ret:        0 on success, -errno on failure
+ *
+ * The string is NUL-terminated.
+ */
+static int qed_read_string(BlockDriverState *file, uint64_t offset, size_t n,
+                           char *buf, size_t buflen)
+{
+    int ret;
+    if (n >= buflen) {
+        return -EINVAL;
+    }
+    ret = bdrv_pread(file, offset, buf, n);
+    if (ret < 0) {
+        return ret;
+    }
+    buf[n] = '\0';
+    return 0;
+}
+
+static int bdrv_qed_open(BlockDriverState *bs, int flags)
+{
+    BDRVQEDState *s = bs->opaque;
+    QEDHeader le_header;
+    int64_t file_size;
+    int ret;
+
+    s->bs = bs;
+
+    ret = bdrv_pread(bs->file, 0, &le_header, sizeof(le_header));
+    if (ret < 0) {
+        return ret;
+    }
+    ret = 0; /* ret should always be 0 or -errno */
+    qed_header_le_to_cpu(&le_header, &s->header);
+
+    if (s->header.magic != QED_MAGIC) {
+        return -EINVAL;
+    }
+    if (s->header.features & ~QED_FEATURE_MASK) {
+        return -ENOTSUP; /* image uses unsupported feature bits */
+    }
+    if (!qed_is_cluster_size_valid(s->header.cluster_size)) {
+        return -EINVAL;
+    }
+
+    /* Round down file size to the last cluster */
+    file_size = bdrv_getlength(bs->file);
+    if (file_size < 0) {
+        return file_size;
+    }
+    s->file_size = qed_start_of_cluster(s, file_size);
+
+    if (!qed_is_table_size_valid(s->header.table_size)) {
+        return -EINVAL;
+    }
+    if (!qed_is_image_size_valid(s->header.image_size,
+                                 s->header.cluster_size,
+                                 s->header.table_size)) {
+        return -EINVAL;
+    }
+    if (!qed_check_table_offset(s, s->header.l1_table_offset)) {
+        return -EINVAL;
+    }
+
+    s->table_nelems = (s->header.cluster_size * s->header.table_size) /
+                      sizeof(uint64_t);
+    s->l2_shift = ffs(s->header.cluster_size) - 1;
+    s->l2_mask = s->table_nelems - 1;
+    s->l1_shift = s->l2_shift + ffs(s->table_nelems) - 1;
+
+    if ((s->header.features & QED_F_BACKING_FILE)) {
+        if ((uint64_t)s->header.backing_filename_offset +
+            s->header.backing_filename_size >
+            s->header.cluster_size * s->header.header_size) {
+            return -EINVAL;
+        }
+
+        ret = qed_read_string(bs->file, s->header.backing_filename_offset,
+                              s->header.backing_filename_size, bs->backing_file,
+                              sizeof(bs->backing_file));
+        if (ret < 0) {
+            return ret;
+        }
+
+        if (s->header.features & QED_F_BACKING_FORMAT_NO_PROBE) {
+            pstrcpy(bs->backing_format, sizeof(bs->backing_format), "raw");
+        }
+    }
+
+    /* Reset unknown autoclear feature bits.  This is a backwards
+     * compatibility mechanism that allows images to be opened by older
+     * programs, which "knock out" unknown feature bits.  When an image is
+     * opened by a newer program again it can detect that the autoclear
+     * feature is no longer valid.
+     */
+    if ((s->header.autoclear_features & ~QED_AUTOCLEAR_FEATURE_MASK) != 0 &&
+        !bdrv_is_read_only(bs->file)) {
+        s->header.autoclear_features &= QED_AUTOCLEAR_FEATURE_MASK;
+
+        ret = qed_write_header_sync(s);
+        if (ret) {
+            return ret;
+        }
+
+        /* From here on only known autoclear feature bits are valid */
+        bdrv_flush(bs->file);
+    }
+
+    return ret;
+}
+
+static void bdrv_qed_close(BlockDriverState *bs)
+{
+}
+
+static int bdrv_qed_flush(BlockDriverState *bs)
+{
+    return bdrv_flush(bs->file);
+}
+
+static int qed_create(const char *filename, uint32_t cluster_size,
+                      uint64_t image_size, uint32_t table_size,
+                      const char *backing_file, const char *backing_fmt)
+{
+    QEDHeader header = {
+        .magic = QED_MAGIC,
+        .cluster_size = cluster_size,
+        .table_size = table_size,
+        .header_size = 1,
+        .features = 0,
+        .compat_features = 0,
+        .l1_table_offset = cluster_size,
+        .image_size = image_size,
+    };
+    QEDHeader le_header;
+    uint8_t *l1_table = NULL;
+    size_t l1_size = header.cluster_size * header.table_size;
+    int ret = 0;
+    BlockDriverState *bs = NULL;
+
+    ret = bdrv_create_file(filename, NULL);
+    if (ret < 0) {
+        return ret;
+    }
+
+    ret = bdrv_file_open(&bs, filename, BDRV_O_RDWR | BDRV_O_CACHE_WB);
+    if (ret < 0) {
+        return ret;
+    }
+
+    if (backing_file) {
+        header.features |= QED_F_BACKING_FILE;
+        header.backing_filename_offset = sizeof(le_header);
+        header.backing_filename_size = strlen(backing_file);
+
+        if (qed_fmt_is_raw(backing_fmt)) {
+            header.features |= QED_F_BACKING_FORMAT_NO_PROBE;
+        }
+    }
+
+    qed_header_cpu_to_le(&header, &le_header);
+    ret = bdrv_pwrite(bs, 0, &le_header, sizeof(le_header));
+    if (ret < 0) {
+        goto out;
+    }
+    ret = bdrv_pwrite(bs, sizeof(le_header), backing_file,
+                      header.backing_filename_size);
+    if (ret < 0) {
+        goto out;
+    }
+
+    l1_table = qemu_mallocz(l1_size);
+    ret = bdrv_pwrite(bs, header.l1_table_offset, l1_table, l1_size);
+    if (ret < 0) {
+        goto out;
+    }
+
+    ret = 0; /* success */
+out:
+    qemu_free(l1_table);
+    bdrv_delete(bs);
+    return ret;
+}
+
+static int bdrv_qed_create(const char *filename, QEMUOptionParameter *options)
+{
+    uint64_t image_size = 0;
+    uint32_t cluster_size = QED_DEFAULT_CLUSTER_SIZE;
+    uint32_t table_size = QED_DEFAULT_TABLE_SIZE;
+    const char *backing_file = NULL;
+    const char *backing_fmt = NULL;
+
+    while (options && options->name) {
+        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
+            image_size = options->value.n;
+        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
+            backing_file = options->value.s;
+        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FMT)) {
+            backing_fmt = options->value.s;
+        } else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) {
+            if (options->value.n) {
+                cluster_size = options->value.n;
+            }
+        } else if (!strcmp(options->name, BLOCK_OPT_TABLE_SIZE)) {
+            if (options->value.n) {
+                table_size = options->value.n;
+            }
+        }
+        options++;
+    }
+
+    if (!qed_is_cluster_size_valid(cluster_size)) {
+        fprintf(stderr, "QED cluster size must be within range [%u, %u] and power of 2\n",
+                QED_MIN_CLUSTER_SIZE, QED_MAX_CLUSTER_SIZE);
+        return -EINVAL;
+    }
+    if (!qed_is_table_size_valid(table_size)) {
+        fprintf(stderr, "QED table size must be within range [%u, %u] and power of 2\n",
+                QED_MIN_TABLE_SIZE, QED_MAX_TABLE_SIZE);
+        return -EINVAL;
+    }
+    if (!qed_is_image_size_valid(image_size, cluster_size, table_size)) {
+        fprintf(stderr, "QED image size must be a non-zero multiple of "
+                        "cluster size and less than %" PRIu64 " bytes\n",
+                qed_max_image_size(cluster_size, table_size));
+        return -EINVAL;
+    }
+
+    return qed_create(filename, cluster_size, image_size, table_size,
+                      backing_file, backing_fmt);
+}
+
+static int bdrv_qed_is_allocated(BlockDriverState *bs, int64_t sector_num,
+                                  int nb_sectors, int *pnum)
+{
+    return -ENOTSUP;
+}
+
+static int bdrv_qed_make_empty(BlockDriverState *bs)
+{
+    return -ENOTSUP;
+}
+
+static BlockDriverAIOCB *bdrv_qed_aio_readv(BlockDriverState *bs,
+                                            int64_t sector_num,
+                                            QEMUIOVector *qiov, int nb_sectors,
+                                            BlockDriverCompletionFunc *cb,
+                                            void *opaque)
+{
+    return NULL;
+}
+
+static BlockDriverAIOCB *bdrv_qed_aio_writev(BlockDriverState *bs,
+                                             int64_t sector_num,
+                                             QEMUIOVector *qiov, int nb_sectors,
+                                             BlockDriverCompletionFunc *cb,
+                                             void *opaque)
+{
+    return NULL;
+}
+
+static BlockDriverAIOCB *bdrv_qed_aio_flush(BlockDriverState *bs,
+                                            BlockDriverCompletionFunc *cb,
+                                            void *opaque)
+{
+    return bdrv_aio_flush(bs->file, cb, opaque);
+}
+
+static int bdrv_qed_truncate(BlockDriverState *bs, int64_t offset)
+{
+    return -ENOTSUP;
+}
+
+static int64_t bdrv_qed_getlength(BlockDriverState *bs)
+{
+    BDRVQEDState *s = bs->opaque;
+    return s->header.image_size;
+}
+
+static int bdrv_qed_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
+{
+    BDRVQEDState *s = bs->opaque;
+
+    memset(bdi, 0, sizeof(*bdi));
+    bdi->cluster_size = s->header.cluster_size;
+    return 0;
+}
+
+static int bdrv_qed_change_backing_file(BlockDriverState *bs,
+                                        const char *backing_file,
+                                        const char *backing_fmt)
+{
+    BDRVQEDState *s = bs->opaque;
+    QEDHeader new_header, le_header;
+    void *buffer;
+    size_t buffer_len, backing_file_len;
+    int ret;
+
+    /* Refuse to set backing filename if unknown compat feature bits are
+     * active.  If the image uses an unknown compat feature then we may not
+     * know the layout of data following the header structure and cannot safely
+     * add a new string.
+     */
+    if (backing_file && (s->header.compat_features &
+                         ~QED_COMPAT_FEATURE_MASK)) {
+        return -ENOTSUP;
+    }
+
+    memcpy(&new_header, &s->header, sizeof(new_header));
+
+    new_header.features &= ~(QED_F_BACKING_FILE |
+                             QED_F_BACKING_FORMAT_NO_PROBE);
+
+    /* Adjust feature flags */
+    if (backing_file) {
+        new_header.features |= QED_F_BACKING_FILE;
+
+        if (qed_fmt_is_raw(backing_fmt)) {
+            new_header.features |= QED_F_BACKING_FORMAT_NO_PROBE;
+        }
+    }
+
+    /* Calculate new header size */
+    backing_file_len = 0;
+
+    if (backing_file) {
+        backing_file_len = strlen(backing_file);
+    }
+
+    buffer_len = sizeof(new_header);
+    new_header.backing_filename_offset = buffer_len;
+    new_header.backing_filename_size = backing_file_len;
+    buffer_len += backing_file_len;
+
+    /* Make sure we can rewrite header without failing */
+    if (buffer_len > new_header.header_size * new_header.cluster_size) {
+        return -ENOSPC;
+    }
+
+    /* Prepare new header */
+    buffer = qemu_malloc(buffer_len);
+
+    qed_header_cpu_to_le(&new_header, &le_header);
+    memcpy(buffer, &le_header, sizeof(le_header));
+    buffer_len = sizeof(le_header);
+
+    memcpy(buffer + buffer_len, backing_file, backing_file_len);
+    buffer_len += backing_file_len;
+
+    /* Write new header */
+    ret = bdrv_pwrite_sync(bs->file, 0, buffer, buffer_len);
+    qemu_free(buffer);
+    if (ret == 0) {
+        memcpy(&s->header, &new_header, sizeof(new_header));
+    }
+    return ret;
+}
+
+static int bdrv_qed_check(BlockDriverState *bs, BdrvCheckResult *result)
+{
+    return -ENOTSUP;
+}
+
+static QEMUOptionParameter qed_create_options[] = {
+    {
+        .name = BLOCK_OPT_SIZE,
+        .type = OPT_SIZE,
+        .help = "Virtual disk size (in bytes)"
+    }, {
+        .name = BLOCK_OPT_BACKING_FILE,
+        .type = OPT_STRING,
+        .help = "File name of a base image"
+    }, {
+        .name = BLOCK_OPT_BACKING_FMT,
+        .type = OPT_STRING,
+        .help = "Image format of the base image"
+    }, {
+        .name = BLOCK_OPT_CLUSTER_SIZE,
+        .type = OPT_SIZE,
+        .help = "Cluster size (in bytes)"
+    }, {
+        .name = BLOCK_OPT_TABLE_SIZE,
+        .type = OPT_SIZE,
+        .help = "L1/L2 table size (in clusters)"
+    },
+    { /* end of list */ }
+};
+
+static BlockDriver bdrv_qed = {
+    .format_name              = "qed",
+    .instance_size            = sizeof(BDRVQEDState),
+    .create_options           = qed_create_options,
+
+    .bdrv_probe               = bdrv_qed_probe,
+    .bdrv_open                = bdrv_qed_open,
+    .bdrv_close               = bdrv_qed_close,
+    .bdrv_create              = bdrv_qed_create,
+    .bdrv_flush               = bdrv_qed_flush,
+    .bdrv_is_allocated        = bdrv_qed_is_allocated,
+    .bdrv_make_empty          = bdrv_qed_make_empty,
+    .bdrv_aio_readv           = bdrv_qed_aio_readv,
+    .bdrv_aio_writev          = bdrv_qed_aio_writev,
+    .bdrv_aio_flush           = bdrv_qed_aio_flush,
+    .bdrv_truncate            = bdrv_qed_truncate,
+    .bdrv_getlength           = bdrv_qed_getlength,
+    .bdrv_get_info            = bdrv_qed_get_info,
+    .bdrv_change_backing_file = bdrv_qed_change_backing_file,
+    .bdrv_check               = bdrv_qed_check,
+};
+
+static void bdrv_qed_init(void)
+{
+    bdrv_register(&bdrv_qed);
+}
+
+block_init(bdrv_qed_init);
diff --git a/block/qed.h b/block/qed.h
new file mode 100644
index 0000000..1f8a125
--- /dev/null
+++ b/block/qed.h
@@ -0,0 +1,148 @@
+/*
+ * QEMU Enhanced Disk Format
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Stefan Hajnoczi   <stefanha at linux.vnet.ibm.com>
+ *  Anthony Liguori   <aliguori at us.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 BLOCK_QED_H
+#define BLOCK_QED_H
+
+#include "block_int.h"
+
+/* The layout of a QED file is as follows:
+ *
+ * +--------+----------+----------+----------+-----+
+ * | header | L1 table | cluster0 | cluster1 | ... |
+ * +--------+----------+----------+----------+-----+
+ *
+ * There is a 2-level pagetable for cluster allocation:
+ *
+ *                     +----------+
+ *                     | L1 table |
+ *                     +----------+
+ *                ,------'  |  '------.
+ *           +----------+   |    +----------+
+ *           | L2 table |  ...   | L2 table |
+ *           +----------+        +----------+
+ *       ,------'  |  '------.
+ *  +----------+   |    +----------+
+ *  |   Data   |  ...   |   Data   |
+ *  +----------+        +----------+
+ *
+ * The L1 table is fixed size and always present.  L2 tables are allocated on
+ * demand.  The L1 table size determines the maximum possible image size; it
+ * can be influenced using the cluster_size and table_size values.
+ *
+ * All fields are little-endian on disk.
+ */
+
+enum {
+    QED_MAGIC = 'Q' | 'E' << 8 | 'D' << 16 | '\0' << 24,
+
+    /* The image supports a backing file */
+    QED_F_BACKING_FILE = 0x01,
+
+    /* The backing file format must not be probed, treat as raw image */
+    QED_F_BACKING_FORMAT_NO_PROBE = 0x04,
+
+    /* Feature bits must be used when the on-disk format changes */
+    QED_FEATURE_MASK = QED_F_BACKING_FILE | /* supported feature bits */
+                       QED_F_BACKING_FORMAT_NO_PROBE,
+    QED_COMPAT_FEATURE_MASK = 0,            /* supported compat feature bits */
+    QED_AUTOCLEAR_FEATURE_MASK = 0,         /* supported autoclear feature bits */
+
+    /* Data is stored in groups of sectors called clusters.  Cluster size must
+     * be large to avoid keeping too much metadata.  I/O requests that have
+     * sub-cluster size will require read-modify-write.
+     */
+    QED_MIN_CLUSTER_SIZE = 4 * 1024, /* in bytes */
+    QED_MAX_CLUSTER_SIZE = 64 * 1024 * 1024,
+    QED_DEFAULT_CLUSTER_SIZE = 64 * 1024,
+
+    /* Allocated clusters are tracked using a 2-level pagetable.  Table size is
+     * a multiple of clusters so large maximum image sizes can be supported
+     * without jacking up the cluster size too much.
+     */
+    QED_MIN_TABLE_SIZE = 1,        /* in clusters */
+    QED_MAX_TABLE_SIZE = 16,
+    QED_DEFAULT_TABLE_SIZE = 4,
+};
+
+typedef struct {
+    uint32_t magic;                 /* QED\0 */
+
+    uint32_t cluster_size;          /* in bytes */
+    uint32_t table_size;            /* for L1 and L2 tables, in clusters */
+    uint32_t header_size;           /* in clusters */
+
+    uint64_t features;              /* format feature bits */
+    uint64_t compat_features;       /* compatible feature bits */
+    uint64_t autoclear_features;    /* self-resetting feature bits */
+
+    uint64_t l1_table_offset;       /* in bytes */
+    uint64_t image_size;            /* total logical image size, in bytes */
+
+    /* if (features & QED_F_BACKING_FILE) */
+    uint32_t backing_filename_offset; /* in bytes from start of header */
+    uint32_t backing_filename_size;   /* in bytes */
+} QEDHeader;
+
+typedef struct {
+    BlockDriverState *bs;           /* device */
+    uint64_t file_size;             /* length of image file, in bytes */
+
+    QEDHeader header;               /* always cpu-endian */
+    uint32_t table_nelems;
+    uint32_t l1_shift;
+    uint32_t l2_shift;
+    uint32_t l2_mask;
+} BDRVQEDState;
+
+/**
+ * Round down to the start of a cluster
+ */
+static inline uint64_t qed_start_of_cluster(BDRVQEDState *s, uint64_t offset)
+{
+    return offset & ~(uint64_t)(s->header.cluster_size - 1);
+}
+
+/**
+ * Test if a cluster offset is valid
+ */
+static inline bool qed_check_cluster_offset(BDRVQEDState *s, uint64_t offset)
+{
+    uint64_t header_size = (uint64_t)s->header.header_size *
+                           s->header.cluster_size;
+
+    if (offset & (s->header.cluster_size - 1)) {
+        return false;
+    }
+    return offset >= header_size && offset < s->file_size;
+}
+
+/**
+ * Test if a table offset is valid
+ */
+static inline bool qed_check_table_offset(BDRVQEDState *s, uint64_t offset)
+{
+    uint64_t end_offset = offset + (s->header.table_size - 1) *
+                          s->header.cluster_size;
+
+    /* Overflow check */
+    if (end_offset <= offset) {
+        return false;
+    }
+
+    return qed_check_cluster_offset(s, offset) &&
+           qed_check_cluster_offset(s, end_offset);
+}
+
+#endif /* BLOCK_QED_H */
diff --git a/block_int.h b/block_int.h
index eb5cd42..12663e8 100644
--- a/block_int.h
+++ b/block_int.h
@@ -37,6 +37,7 @@
 #define BLOCK_OPT_BACKING_FILE  "backing_file"
 #define BLOCK_OPT_BACKING_FMT   "backing_fmt"
 #define BLOCK_OPT_CLUSTER_SIZE  "cluster_size"
+#define BLOCK_OPT_TABLE_SIZE    "table_size"
 #define BLOCK_OPT_PREALLOC      "preallocation"
 
 typedef struct AIOPool {
commit 71af014f1451bec3244e086298813b5aa7b2a0ee
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Mon Dec 6 16:07:59 2010 +0000

    docs: Add QED image format specification
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/docs/specs/qed_spec.txt b/docs/specs/qed_spec.txt
new file mode 100644
index 0000000..446b5a2
--- /dev/null
+++ b/docs/specs/qed_spec.txt
@@ -0,0 +1,130 @@
+=Specification=
+
+The file format looks like this:
+
+ +----------+----------+----------+-----+
+ | cluster0 | cluster1 | cluster2 | ... |
+ +----------+----------+----------+-----+
+
+The first cluster begins with the '''header'''.  The header contains information about where regular clusters start; this allows the header to be extensible and store extra information about the image file.  A regular cluster may be a '''data cluster''', an '''L2''', or an '''L1 table'''.  L1 and L2 tables are composed of one or more contiguous clusters.
+
+Normally the file size will be a multiple of the cluster size.  If the file size is not a multiple, extra information after the last cluster may not be preserved if data is written.  Legitimate extra information should use space between the header and the first regular cluster.
+
+All fields are little-endian.
+
+==Header==
+ Header {
+     uint32_t magic;               /* QED\0 */
+ 
+     uint32_t cluster_size;        /* in bytes */
+     uint32_t table_size;          /* for L1 and L2 tables, in clusters */
+     uint32_t header_size;         /* in clusters */
+ 
+     uint64_t features;            /* format feature bits */
+     uint64_t compat_features;     /* compat feature bits */
+     uint64_t autoclear_features;  /* self-resetting feature bits */
+
+     uint64_t l1_table_offset;     /* in bytes */
+     uint64_t image_size;          /* total logical image size, in bytes */
+ 
+     /* if (features & QED_F_BACKING_FILE) */
+     uint32_t backing_filename_offset; /* in bytes from start of header */
+     uint32_t backing_filename_size;   /* in bytes */
+ }
+
+Field descriptions:
+* ''cluster_size'' must be a power of 2 in range [212, 226].
+* ''table_size'' must be a power of 2 in range [1, 16].
+* ''header_size'' is the number of clusters used by the header and any additional information stored before regular clusters.
+* ''features'', ''compat_features'', and ''autoclear_features'' are file format extension bitmaps.  They work as follows:
+** An image with unknown ''features'' bits enabled must not be opened.  File format changes that are not backwards-compatible must use ''features'' bits.
+** An image with unknown ''compat_features'' bits enabled can be opened safely.  The unknown features are simply ignored and represent backwards-compatible changes to the file format.
+** An image with unknown ''autoclear_features'' bits enable can be opened safely after clearing the unknown bits.  This allows for backwards-compatible changes to the file format which degrade gracefully and can be re-enabled again by a new program later.
+* ''l1_table_offset'' is the offset of the first byte of the L1 table in the image file and must be a multiple of ''cluster_size''.
+* ''image_size'' is the block device size seen by the guest and must be a multiple of 512 bytes.
+* ''backing_filename_offset'' and ''backing_filename_size'' describe a string in (byte offset, byte size) form.  It is not NUL-terminated and has no alignment constraints.  The string must be stored within the first ''header_size'' clusters.  The backing filename may be an absolute path or relative to the image file.
+
+Feature bits:
+* QED_F_BACKING_FILE = 0x01.  The image uses a backing file.
+* QED_F_NEED_CHECK = 0x02.  The image needs a consistency check before use.
+* QED_F_BACKING_FORMAT_NO_PROBE = 0x04.  The backing file is a raw disk image and no file format autodetection should be attempted.  This should be used to ensure that raw backing files are never detected as an image format if they happen to contain magic constants.
+
+There are currently no defined ''compat_features'' or ''autoclear_features'' bits.
+
+Fields predicated on a feature bit are only used when that feature is set.  The fields always take up header space, regardless of whether or not the feature bit is set.
+
+==Tables==
+
+Tables provide the translation from logical offsets in the block device to cluster offsets in the file.
+
+ #define TABLE_NOFFSETS (table_size * cluster_size / sizeof(uint64_t))
+  
+ Table {
+     uint64_t offsets[TABLE_NOFFSETS];
+ }
+
+The tables are organized as follows:
+
+                    +----------+
+                    | L1 table |
+                    +----------+
+               ,------'  |  '------.
+          +----------+   |    +----------+
+          | L2 table |  ...   | L2 table |
+          +----------+        +----------+
+      ,------'  |  '------.
+ +----------+   |    +----------+
+ |   Data   |  ...   |   Data   |
+ +----------+        +----------+
+
+A table is made up of one or more contiguous clusters.  The table_size header field determines table size for an image file.  For example, cluster_size=64 KB and table_size=4 results in 256 KB tables.
+
+The logical image size must be less than or equal to the maximum possible size of clusters rooted by the L1 table:
+ header.image_size <= TABLE_NOFFSETS * TABLE_NOFFSETS * header.cluster_size
+
+L1, L2, and data cluster offsets must be aligned to header.cluster_size.  The following offsets have special meanings:
+
+===L2 table offsets===
+* 0 - unallocated.  The L2 table is not yet allocated.
+
+===Data cluster offsets===
+* 0 - unallocated.  The data cluster is not yet allocated.
+
+Future format extensions may wish to store per-offset information.  The least significant 12 bits of an offset are reserved for this purpose and must be set to zero.  Image files with cluster_size > 212 will have more unused bits which should also be zeroed.
+
+===Unallocated L2 tables and data clusters===
+Reads to an unallocated area of the image file access the backing file.  If there is no backing file, then zeroes are produced.  The backing file may be smaller than the image file and reads of unallocated areas beyond the end of the backing file produce zeroes.
+
+Writes to an unallocated area cause a new data clusters to be allocated, and a new L2 table if that is also unallocated.  The new data cluster is populated with data from the backing file (or zeroes if no backing file) and the data being written.
+
+===Logical offset translation===
+Logical offsets are translated into cluster offsets as follows:
+
+  table_bits table_bits    cluster_bits
+  <--------> <--------> <--------------->
+ +----------+----------+-----------------+
+ | L1 index | L2 index |     byte offset |
+ +----------+----------+-----------------+
+ 
+       Structure of a logical offset
+
+ offset_mask = ~(cluster_size - 1) # mask for the image file byte offset
+ 
+ def logical_to_cluster_offset(l1_index, l2_index, byte_offset):
+   l2_offset = l1_table[l1_index]
+   l2_table = load_table(l2_offset)
+   cluster_offset = l2_table[l2_index] & offset_mask
+   return cluster_offset + byte_offset
+
+==Consistency checking==
+
+This section is informational and included to provide background on the use of the QED_F_NEED_CHECK ''features'' bit.
+
+The QED_F_NEED_CHECK bit is used to mark an image as dirty before starting an operation that could leave the image in an inconsistent state if interrupted by a crash or power failure.  A dirty image must be checked on open because its metadata may not be consistent.
+
+Consistency check includes the following invariants:
+# Each cluster is referenced once and only once.  It is an inconsistency to have a cluster referenced more than once by L1 or L2 tables.  A cluster has been leaked if it has no references.
+# Offsets must be within the image file size and must be ''cluster_size'' aligned.
+# Table offsets must at least ''table_size'' * ''cluster_size'' bytes from the end of the image file so that there is space for the entire table.
+
+The consistency check process starts by from ''l1_table_offset'' and scans all L2 tables.  After the check completes with no other errors besides leaks, the QED_F_NEED_CHECK bit can be cleared and the image can be accessed.
commit 095343adf97212396c1c2d7021d5fb338a4286c8
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Fri Dec 17 11:55:37 2010 +0100

    qemu-io: Fix typo in help texts
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/qemu-io.c b/qemu-io.c
index 2318a28..65dee13 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -326,7 +326,7 @@ read_help(void)
 " -l, -- length for pattern verification (only with -P)\n"
 " -p, -- use bdrv_pread to read the file\n"
 " -P, -- use a pattern to verify read data\n"
-" -q, -- quite mode, do not show I/O statistics\n"
+" -q, -- quiet mode, do not show I/O statistics\n"
 " -s, -- start offset for pattern verification (only with -P)\n"
 " -v, -- dump buffer to standard output\n"
 "\n");
@@ -509,7 +509,7 @@ readv_help(void)
 " -C, -- report statistics in a machine parsable format\n"
 " -P, -- use a pattern to verify read data\n"
 " -v, -- dump buffer to standard output\n"
-" -q, -- quite mode, do not show I/O statistics\n"
+" -q, -- quiet mode, do not show I/O statistics\n"
 "\n");
 }
 
@@ -633,7 +633,7 @@ write_help(void)
 " -p, -- use bdrv_pwrite to write the file\n"
 " -P, -- use different pattern to fill file\n"
 " -C, -- report statistics in a machine parsable format\n"
-" -q, -- quite mode, do not show I/O statistics\n"
+" -q, -- quiet mode, do not show I/O statistics\n"
 "\n");
 }
 
@@ -765,7 +765,7 @@ writev_help(void)
 " filled with a set pattern (0xcdcdcdcd).\n"
 " -P, -- use different pattern to fill file\n"
 " -C, -- report statistics in a machine parsable format\n"
-" -q, -- quite mode, do not show I/O statistics\n"
+" -q, -- quiet mode, do not show I/O statistics\n"
 "\n");
 }
 
@@ -1100,7 +1100,7 @@ aio_read_help(void)
 " -C, -- report statistics in a machine parsable format\n"
 " -P, -- use a pattern to verify read data\n"
 " -v, -- dump buffer to standard output\n"
-" -q, -- quite mode, do not show I/O statistics\n"
+" -q, -- quiet mode, do not show I/O statistics\n"
 "\n");
 }
 
@@ -1198,7 +1198,7 @@ aio_write_help(void)
 " used to ensure all outstanding aio requests have been completed\n"
 " -P, -- use different pattern to fill file\n"
 " -C, -- report statistics in a machine parsable format\n"
-" -q, -- quite mode, do not show I/O statistics\n"
+" -q, -- quiet mode, do not show I/O statistics\n"
 "\n");
 }
 
@@ -1406,7 +1406,7 @@ discard_help(void)
 "\n"
 " Discards a segment of the currently open file.\n"
 " -C, -- report statistics in a machine parsable format\n"
-" -q, -- quite mode, do not show I/O statistics\n"
+" -q, -- quiet mode, do not show I/O statistics\n"
 "\n");
 }
 
commit dce512dedf2b842f453f8b20d6ca37ce283103da
Author: Christoph Hellwig <hch at lst.de>
Date:   Fri Dec 17 11:41:15 2010 +0100

    raw-posix: add discard support
    
    Add support to discard blocks in a raw image residing on an XFS filesystem
    by calling the XFS_IOC_UNRESVSP64 ioctl to punch holes.  Support for other
    hole punching mechanisms can be added when they become available.
    
    Signed-off-by: Christoph Hellwig <hch at lst.de>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/raw-posix.c b/block/raw-posix.c
index 9286fb8..6b72470 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -69,6 +69,10 @@
 #include <sys/diskslice.h>
 #endif
 
+#ifdef CONFIG_XFS
+#include <xfs/xfs.h>
+#endif
+
 //#define DEBUG_FLOPPY
 
 //#define DEBUG_BLOCK
@@ -120,6 +124,9 @@ typedef struct BDRVRawState {
 #endif
     uint8_t *aligned_buf;
     unsigned aligned_buf_size;
+#ifdef CONFIG_XFS
+    bool is_xfs : 1;
+#endif
 } BDRVRawState;
 
 static int fd_open(BlockDriverState *bs);
@@ -196,6 +203,12 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
 #endif
     }
 
+#ifdef CONFIG_XFS
+    if (platform_test_xfs_fd(s->fd)) {
+        s->is_xfs = 1;
+    }
+#endif
+
     return 0;
 
 out_free_buf:
@@ -740,6 +753,37 @@ static int raw_flush(BlockDriverState *bs)
     return qemu_fdatasync(s->fd);
 }
 
+#ifdef CONFIG_XFS
+static int xfs_discard(BDRVRawState *s, int64_t sector_num, int nb_sectors)
+{
+    struct xfs_flock64 fl;
+
+    memset(&fl, 0, sizeof(fl));
+    fl.l_whence = SEEK_SET;
+    fl.l_start = sector_num << 9;
+    fl.l_len = (int64_t)nb_sectors << 9;
+
+    if (xfsctl(NULL, s->fd, XFS_IOC_UNRESVSP64, &fl) < 0) {
+        DEBUG_BLOCK_PRINT("cannot punch hole (%s)\n", strerror(errno));
+        return -errno;
+    }
+
+    return 0;
+}
+#endif
+
+static int raw_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors)
+{
+#ifdef CONFIG_XFS
+    BDRVRawState *s = bs->opaque;
+
+    if (s->is_xfs) {
+        return xfs_discard(s, sector_num, nb_sectors);
+    }
+#endif
+
+    return 0;
+}
 
 static QEMUOptionParameter raw_create_options[] = {
     {
@@ -761,6 +805,7 @@ static BlockDriver bdrv_file = {
     .bdrv_close = raw_close,
     .bdrv_create = raw_create,
     .bdrv_flush = raw_flush,
+    .bdrv_discard = raw_discard,
 
     .bdrv_aio_readv = raw_aio_readv,
     .bdrv_aio_writev = raw_aio_writev,
diff --git a/configure b/configure
index 62defc4..47e4cf0 100755
--- a/configure
+++ b/configure
@@ -288,6 +288,7 @@ xen=""
 linux_aio=""
 attr=""
 vhost_net=""
+xfs=""
 
 gprof="no"
 debug_tcg="no"
@@ -1399,6 +1400,27 @@ EOF
 fi
 
 ##########################################
+# xfsctl() probe, used for raw-posix
+if test "$xfs" != "no" ; then
+  cat > $TMPC << EOF
+#include <xfs/xfs.h>
+int main(void)
+{
+    xfsctl(NULL, 0, 0, NULL);
+    return 0;
+}
+EOF
+  if compile_prog "" "" ; then
+    xfs="yes"
+  else
+    if test "$xfs" = "yes" ; then
+      feature_not_found "xfs"
+    fi
+    xfs=no
+  fi
+fi
+
+##########################################
 # vde libraries probe
 if test "$vde" != "no" ; then
   vde_libs="-lvdeplug"
@@ -2403,6 +2425,7 @@ echo "Trace backend     $trace_backend"
 echo "Trace output file $trace_file-<pid>"
 echo "spice support     $spice"
 echo "rbd support       $rbd"
+echo "xfsctl support    $xfs"
 
 if test $sdl_too_old = "yes"; then
 echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -2548,6 +2571,9 @@ fi
 if test "$uuid" = "yes" ; then
   echo "CONFIG_UUID=y" >> $config_host_mak
 fi
+if test "$xfs" = "yes" ; then
+  echo "CONFIG_XFS=y" >> $config_host_mak
+fi
 qemu_version=`head $source_path/VERSION`
 echo "VERSION=$qemu_version" >>$config_host_mak
 echo "PKGVERSION=$pkgversion" >>$config_host_mak
commit edff5db1f50fd89e807f3fb518c77af7531e8117
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Mon Dec 13 09:36:26 2010 +0000

    qemu-io: Add discard command
    
    discard [-Cq] off len -- discards a number of bytes at a specified
    offset
    
     discards a range of bytes from the given offset
    
     Example:
     'discard 512 1k' - discards 1 kilobyte from 512 bytes into the file
    
     Discards a segment of the currently open file.
     -C, -- report statistics in a machine parsable format
     -q, -- quite mode, do not show I/O statistics
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/qemu-io.c b/qemu-io.c
index 0f6d1b6..2318a28 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -1394,6 +1394,93 @@ static const cmdinfo_t info_cmd = {
 	.oneline	= "prints information about the current file",
 };
 
+static void
+discard_help(void)
+{
+	printf(
+"\n"
+" discards a range of bytes from the given offset\n"
+"\n"
+" Example:\n"
+" 'discard 512 1k' - discards 1 kilobyte from 512 bytes into the file\n"
+"\n"
+" Discards a segment of the currently open file.\n"
+" -C, -- report statistics in a machine parsable format\n"
+" -q, -- quite mode, do not show I/O statistics\n"
+"\n");
+}
+
+static int discard_f(int argc, char **argv);
+
+static const cmdinfo_t discard_cmd = {
+	.name		= "discard",
+	.altname	= "d",
+	.cfunc		= discard_f,
+	.argmin		= 2,
+	.argmax		= -1,
+	.args		= "[-Cq] off len",
+	.oneline	= "discards a number of bytes at a specified offset",
+	.help		= discard_help,
+};
+
+static int
+discard_f(int argc, char **argv)
+{
+	struct timeval t1, t2;
+	int Cflag = 0, qflag = 0;
+	int c, ret;
+	int64_t offset;
+	int count;
+
+	while ((c = getopt(argc, argv, "Cq")) != EOF) {
+		switch (c) {
+		case 'C':
+			Cflag = 1;
+			break;
+		case 'q':
+			qflag = 1;
+			break;
+		default:
+			return command_usage(&discard_cmd);
+		}
+	}
+
+	if (optind != argc - 2) {
+		return command_usage(&discard_cmd);
+	}
+
+	offset = cvtnum(argv[optind]);
+	if (offset < 0) {
+		printf("non-numeric length argument -- %s\n", argv[optind]);
+		return 0;
+	}
+
+	optind++;
+	count = cvtnum(argv[optind]);
+	if (count < 0) {
+		printf("non-numeric length argument -- %s\n", argv[optind]);
+		return 0;
+	}
+
+	gettimeofday(&t1, NULL);
+	ret = bdrv_discard(bs, offset, count);
+	gettimeofday(&t2, NULL);
+
+	if (ret < 0) {
+		printf("discard failed: %s\n", strerror(-ret));
+		goto out;
+	}
+
+	/* Finally, report back -- -C gives a parsable format */
+	if (!qflag) {
+		t2 = tsub(t2, t1);
+		print_report("discard", &t2, offset, count, count, 1, Cflag);
+	}
+
+out:
+	return 0;
+}
+
 static int
 alloc_f(int argc, char **argv)
 {
@@ -1715,6 +1802,7 @@ int main(int argc, char **argv)
 	add_command(&truncate_cmd);
 	add_command(&length_cmd);
 	add_command(&info_cmd);
+	add_command(&discard_cmd);
 	add_command(&alloc_cmd);
 	add_command(&map_cmd);
 
commit ea3bd56f56822350bbb91518b3d786948f573359
Author: Christoph Hellwig <hch at lst.de>
Date:   Thu Dec 16 19:36:43 2010 +0100

    scsi-disk: support WRITE SAME (16) with unmap bit
    
    Support discards via the WRITE SAME command with the unmap bit set, and
    tell the initiator about the support for it via the block limit and the
    new thin provisioning EVPD pages.  Also fix the comment which incorrectly
    describedthe block limits EVPD page.
    
    Signed-off-by: Christoph Hellwig <hch at lst.de>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-defs.h b/hw/scsi-defs.h
index 1473ecb..413cce0 100644
--- a/hw/scsi-defs.h
+++ b/hw/scsi-defs.h
@@ -84,6 +84,7 @@
 #define MODE_SENSE_10         0x5a
 #define PERSISTENT_RESERVE_IN 0x5e
 #define PERSISTENT_RESERVE_OUT 0x5f
+#define WRITE_SAME_16         0x93
 #define MAINTENANCE_IN        0xa3
 #define MAINTENANCE_OUT       0xa4
 #define MOVE_MEDIUM           0xa5
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 87f9e86..6cb317c 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -424,7 +424,8 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
             outbuf[buflen++] = 0x80; // unit serial number
             outbuf[buflen++] = 0x83; // device identification
             if (bdrv_get_type_hint(s->bs) != BDRV_TYPE_CDROM) {
-                outbuf[buflen++] = 0xb0; // block device characteristics
+                outbuf[buflen++] = 0xb0; // block limits
+                outbuf[buflen++] = 0xb2; // thin provisioning
             }
             outbuf[pages] = buflen - pages - 1; // number of pages
             break;
@@ -466,8 +467,10 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
             buflen += id_len;
             break;
         }
-        case 0xb0: /* block device characteristics */
+        case 0xb0: /* block limits */
         {
+            unsigned int unmap_sectors =
+                    s->qdev.conf.discard_granularity / s->qdev.blocksize;
             unsigned int min_io_size =
                     s->qdev.conf.min_io_size / s->qdev.blocksize;
             unsigned int opt_io_size =
@@ -492,6 +495,21 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
             outbuf[13] = (opt_io_size >> 16) & 0xff;
             outbuf[14] = (opt_io_size >> 8) & 0xff;
             outbuf[15] = opt_io_size & 0xff;
+
+            /* optimal unmap granularity */
+            outbuf[28] = (unmap_sectors >> 24) & 0xff;
+            outbuf[29] = (unmap_sectors >> 16) & 0xff;
+            outbuf[30] = (unmap_sectors >> 8) & 0xff;
+            outbuf[31] = unmap_sectors & 0xff;
+            break;
+        }
+        case 0xb2: /* thin provisioning */
+        {
+            outbuf[3] = buflen = 8;
+            outbuf[4] = 0;
+            outbuf[5] = 0x40; /* write same with unmap supported */
+            outbuf[6] = 0;
+            outbuf[7] = 0;
             break;
         }
         default:
@@ -959,6 +977,12 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
             outbuf[11] = 0;
             outbuf[12] = 0;
             outbuf[13] = get_physical_block_exp(&s->qdev.conf);
+
+            /* set TPE bit if the format supports discard */
+            if (s->qdev.conf.discard_granularity) {
+                outbuf[14] = 0x80;
+            }
+
             /* Protection, exponent and lowest lba field left blank. */
             buflen = req->cmd.xfer;
             break;
@@ -1123,6 +1147,31 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
             goto illegal_lba;
         }
         break;
+    case WRITE_SAME_16:
+        len = r->req.cmd.xfer / d->blocksize;
+
+        DPRINTF("WRITE SAME(16) (sector %" PRId64 ", count %d)\n",
+                r->req.cmd.lba, len);
+
+        if (r->req.cmd.lba > s->max_lba) {
+            goto illegal_lba;
+        }
+
+        /*
+         * We only support WRITE SAME with the unmap bit set for now.
+         */
+        if (!(buf[1] & 0x8)) {
+            goto fail;
+        }
+
+        rc = bdrv_discard(s->bs, r->req.cmd.lba * s->cluster_size,
+                          len * s->cluster_size);
+        if (rc < 0) {
+            /* XXX: better error code ?*/
+            goto fail;
+        }
+
+        break;
     default:
         DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
     fail:
commit bb8bf76fb1c4afa116a7f11fee559b3cca671a4a
Author: Christoph Hellwig <hch at lst.de>
Date:   Thu Dec 16 19:36:31 2010 +0100

    block: add discard support
    
    Add a new bdrv_discard method to free blocks in a mapping image, and a new
    drive property to set the granularity for these discard.  If no discard
    granularity support is set discard support is disabled.
    
    Signed-off-by: Christoph Hellwig <hch at lst.de>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index fe07d0b..9b5e9e1 100644
--- a/block.c
+++ b/block.c
@@ -1515,6 +1515,17 @@ int bdrv_has_zero_init(BlockDriverState *bs)
     return 1;
 }
 
+int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors)
+{
+    if (!bs->drv) {
+        return -ENOMEDIUM;
+    }
+    if (!bs->drv->bdrv_discard) {
+        return 0;
+    }
+    return bs->drv->bdrv_discard(bs, sector_num, nb_sectors);
+}
+
 /*
  * Returns true iff the specified sector is present in the disk image. Drivers
  * not implementing the functionality are assumed to not support backing files,
diff --git a/block.h b/block.h
index b812172..f923add 100644
--- a/block.h
+++ b/block.h
@@ -146,6 +146,7 @@ int bdrv_flush(BlockDriverState *bs);
 void bdrv_flush_all(void);
 void bdrv_close_all(void);
 
+int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors);
 int bdrv_has_zero_init(BlockDriverState *bs);
 int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
 	int *pnum);
diff --git a/block/raw.c b/block/raw.c
index 1980deb..b0f72d6 100644
--- a/block/raw.c
+++ b/block/raw.c
@@ -65,6 +65,11 @@ static int raw_probe(const uint8_t *buf, int buf_size, const char *filename)
    return 1; /* everything can be opened as raw image */
 }
 
+static int raw_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors)
+{
+    return bdrv_discard(bs->file, sector_num, nb_sectors);
+}
+
 static int raw_is_inserted(BlockDriverState *bs)
 {
     return bdrv_is_inserted(bs->file);
@@ -130,6 +135,7 @@ static BlockDriver bdrv_raw = {
     .bdrv_aio_readv     = raw_aio_readv,
     .bdrv_aio_writev    = raw_aio_writev,
     .bdrv_aio_flush     = raw_aio_flush,
+    .bdrv_discard       = raw_discard,
 
     .bdrv_is_inserted   = raw_is_inserted,
     .bdrv_eject         = raw_eject,
diff --git a/block_int.h b/block_int.h
index 6b3b098..eb5cd42 100644
--- a/block_int.h
+++ b/block_int.h
@@ -72,6 +72,8 @@ struct BlockDriver {
         BlockDriverCompletionFunc *cb, void *opaque);
     BlockDriverAIOCB *(*bdrv_aio_flush)(BlockDriverState *bs,
         BlockDriverCompletionFunc *cb, void *opaque);
+    int (*bdrv_discard)(BlockDriverState *bs, int64_t sector_num,
+                        int nb_sectors);
 
     int (*bdrv_aio_multiwrite)(BlockDriverState *bs, BlockRequest *reqs,
         int num_reqs);
@@ -227,6 +229,7 @@ typedef struct BlockConf {
     uint16_t min_io_size;
     uint32_t opt_io_size;
     int32_t bootindex;
+    uint32_t discard_granularity;
 } BlockConf;
 
 static inline unsigned int get_physical_block_exp(BlockConf *conf)
@@ -250,6 +253,8 @@ static inline unsigned int get_physical_block_exp(BlockConf *conf)
                        _conf.physical_block_size, 512),                 \
     DEFINE_PROP_UINT16("min_io_size", _state, _conf.min_io_size, 0),  \
     DEFINE_PROP_UINT32("opt_io_size", _state, _conf.opt_io_size, 0),    \
-    DEFINE_PROP_INT32("bootindex", _state, _conf.bootindex, -1)         \
+    DEFINE_PROP_INT32("bootindex", _state, _conf.bootindex, -1),        \
+    DEFINE_PROP_UINT32("discard_granularity", _state, \
+                       _conf.discard_granularity, 0)
 
 #endif /* BLOCK_INT_H */
commit 61d9d6b091aa04e5e5bd20951aa689a5bbe65aed
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Thu Dec 16 15:54:06 2010 +0000

    ide: Register vm change state handler once only
    
    We register the vm change state handler in a PCI BAR map() function.
    This function can be called multiple times throughout the lifetime of a
    PCI IDE device.  This results in duplicate vm change state handlers
    being register, none of which are ever unregistered.
    
    Instead, register the vm change state handler in the device's init
    function once and for all.
    
    piix tested, cmd646 and via not tested.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c
index e191ee6..89ba836 100644
--- a/hw/ide/cmd646.c
+++ b/hw/ide/cmd646.c
@@ -167,10 +167,6 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num,
 
     for(i = 0;i < 2; i++) {
         BMDMAState *bm = &d->bmdma[i];
-        bmdma_init(&d->bus[i], bm);
-        bm->bus = d->bus+i;
-        qemu_add_vm_change_state_handler(d->bus[i].dma->ops->restart_cb,
-                                         &bm->dma);
 
         if (i == 0) {
             register_ioport_write(addr, 4, 1, bmdma_writeb_0, d);
@@ -228,6 +224,7 @@ static int pci_cmd646_ide_initfn(PCIDevice *dev)
     PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);
     uint8_t *pci_conf = d->dev.config;
     qemu_irq *irq;
+    int i;
 
     pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_CMD);
     pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_CMD_646);
@@ -253,10 +250,15 @@ static int pci_cmd646_ide_initfn(PCIDevice *dev)
     pci_conf[PCI_INTERRUPT_PIN] = 0x01; // interrupt on pin 1
 
     irq = qemu_allocate_irqs(cmd646_set_irq, d, 2);
-    ide_bus_new(&d->bus[0], &d->dev.qdev, 0);
-    ide_bus_new(&d->bus[1], &d->dev.qdev, 1);
-    ide_init2(&d->bus[0], irq[0]);
-    ide_init2(&d->bus[1], irq[1]);
+    for (i = 0; i < 2; i++) {
+        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]);
+        bm->bus = &d->bus[i];
+        qemu_add_vm_change_state_handler(d->bus[i].dma->ops->restart_cb,
+                                         &d->bmdma[i]->dma);
+    }
 
     vmstate_register(&dev->qdev, 0, &vmstate_ide_pci, d);
     qemu_register_reset(cmd646_reset, d);
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index a6b5d92..1cad906 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -76,10 +76,6 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num,
 
     for(i = 0;i < 2; i++) {
         BMDMAState *bm = &d->bmdma[i];
-        bmdma_init(&d->bus[i], bm);
-        bm->bus = d->bus+i;
-        qemu_add_vm_change_state_handler(d->bus[i].dma->ops->restart_cb,
-                                         &bm->dma);
 
         register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm);
 
@@ -112,6 +108,29 @@ static void piix3_reset(void *opaque)
     pci_conf[0x20] = 0x01; /* BMIBA: 20-23h */
 }
 
+static void pci_piix_init_ports(PCIIDEState *d) {
+    int i;
+    struct {
+        int iobase;
+        int iobase2;
+        int isairq;
+    } port_info[] = {
+        {0x1f0, 0x3f6, 14},
+        {0x170, 0x376, 15},
+    };
+
+    for (i = 0; i < 2; i++) {
+        ide_bus_new(&d->bus[i], &d->dev.qdev, i);
+        ide_init_ioport(&d->bus[i], port_info[i].iobase, port_info[i].iobase2);
+        ide_init2(&d->bus[i], isa_reserve_irq(port_info[i].isairq));
+
+        bmdma_init(&d->bus[i], &d->bmdma[i]);
+        d->bmdma[i].bus = &d->bus[i];
+        qemu_add_vm_change_state_handler(d->bus[i].dma->ops->restart_cb,
+                                         &d->bmdma[i].dma);
+    }
+}
+
 static int pci_piix_ide_initfn(PCIIDEState *d)
 {
     uint8_t *pci_conf = d->dev.config;
@@ -125,13 +144,8 @@ static int pci_piix_ide_initfn(PCIIDEState *d)
 
     vmstate_register(&d->dev.qdev, 0, &vmstate_ide_pci, d);
 
-    ide_bus_new(&d->bus[0], &d->dev.qdev, 0);
-    ide_bus_new(&d->bus[1], &d->dev.qdev, 1);
-    ide_init_ioport(&d->bus[0], 0x1f0, 0x3f6);
-    ide_init_ioport(&d->bus[1], 0x170, 0x376);
+    pci_piix_init_ports(d);
 
-    ide_init2(&d->bus[0], isa_reserve_irq(14));
-    ide_init2(&d->bus[1], isa_reserve_irq(15));
     return 0;
 }
 
diff --git a/hw/ide/via.c b/hw/ide/via.c
index 2603110..5b70bd2 100644
--- a/hw/ide/via.c
+++ b/hw/ide/via.c
@@ -78,10 +78,6 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num,
 
     for(i = 0;i < 2; i++) {
         BMDMAState *bm = &d->bmdma[i];
-        bmdma_init(&d->bus[i], bm);
-        bm->bus = d->bus+i;
-        qemu_add_vm_change_state_handler(d->bus[i].dma->ops->restart_cb,
-                                         &bm->dma);
 
         register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm);
 
@@ -135,6 +131,29 @@ static void via_reset(void *opaque)
     pci_set_long(pci_conf + 0xc0, 0x00020001);
 }
 
+static void vt82c686b_init_ports(PCIIDEState *d) {
+    int i;
+    struct {
+        int iobase;
+        int iobase2;
+        int isairq;
+    } port_info[] = {
+        {0x1f0, 0x3f6, 14},
+        {0x170, 0x376, 15},
+    };
+
+    for (i = 0; i < 2; i++) {
+        ide_bus_new(&d->bus[i], &d->dev.qdev, i);
+        ide_init_ioport(&d->bus[i], port_info[i].iobase, port_info[i].iobase2);
+        ide_init2(&d->bus[i], isa_reserve_irq(port_info[i].isairq));
+
+        bmdma_init(&d->bus[i], &d->bmdma[i]);
+        d->bmdma[i].bus = &d->bus[i];
+        qemu_add_vm_change_state_handler(d->bus[i].dma->ops->restart_cb,
+                                         &d->bmdma[i]->dma);
+    }
+}
+
 /* via ide func */
 static int vt82c686b_ide_initfn(PCIDevice *dev)
 {
@@ -154,12 +173,7 @@ static int vt82c686b_ide_initfn(PCIDevice *dev)
 
     vmstate_register(&dev->qdev, 0, &vmstate_ide_pci, d);
 
-    ide_bus_new(&d->bus[0], &d->dev.qdev, 0);
-    ide_bus_new(&d->bus[1], &d->dev.qdev, 1);
-    ide_init2(&d->bus[0], isa_reserve_irq(14));
-    ide_init2(&d->bus[1], isa_reserve_irq(15));
-    ide_init_ioport(&d->bus[0], 0x1f0, 0x3f6);
-    ide_init_ioport(&d->bus[1], 0x170, 0x376);
+    vt82c686b_init_ports(d);
 
     return 0;
 }
commit ad7171394f2fe3f9b5fe02f0c62496291a859a92
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Thu Dec 16 15:37:41 2010 +0100

    Remove NULL checks for bdrv_new return value
    
    It's an indirect call to qemu_malloc, which never returns an error.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/xen_disk.c b/hw/xen_disk.c
index 85a1c85..ed9e5eb 100644
--- a/hw/xen_disk.c
+++ b/hw/xen_disk.c
@@ -634,17 +634,12 @@ static int blk_init(struct XenDevice *xendev)
     if (!blkdev->dinfo) {
         /* setup via xenbus -> create new block driver instance */
         xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n");
-	blkdev->bs = bdrv_new(blkdev->dev);
-	if (blkdev->bs) {
-	    if (bdrv_open(blkdev->bs, blkdev->filename, qflags,
-                           bdrv_find_whitelisted_format(blkdev->fileproto))
-                != 0) {
-		bdrv_delete(blkdev->bs);
-		blkdev->bs = NULL;
-	    }
-	}
-	if (!blkdev->bs)
-	    return -1;
+        blkdev->bs = bdrv_new(blkdev->dev);
+        if (bdrv_open(blkdev->bs, blkdev->filename, qflags,
+                      bdrv_find_whitelisted_format(blkdev->fileproto)) != 0) {
+            bdrv_delete(blkdev->bs);
+            return -1;
+        }
     } else {
         /* setup via qemu cmdline -> already setup for us */
         xen_be_printf(&blkdev->xendev, 2, "get configured bdrv (cmdline setup)\n");
diff --git a/qemu-img.c b/qemu-img.c
index 0b871d8..afd9ed2 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -215,10 +215,7 @@ static BlockDriverState *bdrv_new_open(const char *filename,
     char password[256];
 
     bs = bdrv_new("");
-    if (!bs) {
-        error_report("Not enough memory");
-        goto fail;
-    }
+
     if (fmt) {
         drv = bdrv_find_format(fmt);
         if (!drv) {
diff --git a/qemu-io.c b/qemu-io.c
index ff353eb..0f6d1b6 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -1509,8 +1509,6 @@ static int openfile(char *name, int flags, int growable)
 		}
 	} else {
 		bs = bdrv_new("hda");
-		if (!bs)
-			return 1;
 
 		if (bdrv_open(bs, name, flags, NULL) < 0) {
 			fprintf(stderr, "%s: can't open device %s\n", progname, name);
diff --git a/qemu-nbd.c b/qemu-nbd.c
index 99f1d22..e858033 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -336,8 +336,6 @@ int main(int argc, char **argv)
     bdrv_init();
 
     bs = bdrv_new("hda");
-    if (bs == NULL)
-        return 1;
 
     if ((ret = bdrv_open(bs, argv[optind], flags, NULL)) < 0) {
         errno = -ret;
commit 15654a6d7c3269e922b92f9596e48078c9bfcbfa
Author: Jes Sorensen <Jes.Sorensen at redhat.com>
Date:   Thu Dec 16 14:31:53 2010 +0100

    qemu.img.c: Use error_report() instead of own error() implementation
    
    Signed-off-by: Jes Sorensen <Jes.Sorensen at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/qemu-img.c b/qemu-img.c
index 0ff179f..0b871d8 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -41,16 +41,6 @@ typedef struct img_cmd_t {
 /* Default to cache=writeback as data integrity is not important for qemu-tcg. */
 #define BDRV_O_FLAGS BDRV_O_CACHE_WB
 
-static void GCC_FMT_ATTR(1, 2) error(const char *fmt, ...)
-{
-    va_list ap;
-    va_start(ap, fmt);
-    fprintf(stderr, "qemu-img: ");
-    vfprintf(stderr, fmt, ap);
-    fprintf(stderr, "\n");
-    va_end(ap);
-}
-
 static void format_print(void *opaque, const char *name)
 {
     printf(" %s", name);
@@ -197,13 +187,13 @@ static int print_block_option_help(const char *filename, const char *fmt)
     /* Find driver and parse its options */
     drv = bdrv_find_format(fmt);
     if (!drv) {
-        error("Unknown file format '%s'", fmt);
+        error_report("Unknown file format '%s'", fmt);
         return 1;
     }
 
     proto_drv = bdrv_find_protocol(filename);
     if (!proto_drv) {
-        error("Unknown protocol '%s'", filename);
+        error_report("Unknown protocol '%s'", filename);
         return 1;
     }
 
@@ -226,30 +216,30 @@ static BlockDriverState *bdrv_new_open(const char *filename,
 
     bs = bdrv_new("");
     if (!bs) {
-        error("Not enough memory");
+        error_report("Not enough memory");
         goto fail;
     }
     if (fmt) {
         drv = bdrv_find_format(fmt);
         if (!drv) {
-            error("Unknown file format '%s'", fmt);
+            error_report("Unknown file format '%s'", fmt);
             goto fail;
         }
     } else {
         drv = NULL;
     }
     if (bdrv_open(bs, filename, flags, drv) < 0) {
-        error("Could not open '%s'", filename);
+        error_report("Could not open '%s'", filename);
         goto fail;
     }
     if (bdrv_is_encrypted(bs)) {
         printf("Disk image '%s' is encrypted.\n", filename);
         if (read_password(password, sizeof(password)) < 0) {
-            error("No password given");
+            error_report("No password given");
             goto fail;
         }
         if (bdrv_set_key(bs, password) < 0) {
-            error("invalid password");
+            error_report("invalid password");
             goto fail;
         }
     }
@@ -267,13 +257,15 @@ static int add_old_style_options(const char *fmt, QEMUOptionParameter *list,
 {
     if (base_filename) {
         if (set_option_parameter(list, BLOCK_OPT_BACKING_FILE, base_filename)) {
-            error("Backing file not supported for file format '%s'", fmt);
+            error_report("Backing file not supported for file format '%s'",
+                         fmt);
             return -1;
         }
     }
     if (base_fmt) {
         if (set_option_parameter(list, BLOCK_OPT_BACKING_FMT, base_fmt)) {
-            error("Backing file format not supported for file format '%s'", fmt);
+            error_report("Backing file format not supported for file "
+                         "format '%s'", fmt);
             return -1;
         }
     }
@@ -310,11 +302,11 @@ static int img_create(int argc, char **argv)
             fmt = optarg;
             break;
         case 'e':
-            error("qemu-img: option -e is deprecated, please use \'-o "
+            error_report("qemu-img: option -e is deprecated, please use \'-o "
                   "encryption\' instead!");
             return 1;
         case '6':
-            error("qemu-img: option -6 is deprecated, please use \'-o "
+            error_report("qemu-img: option -6 is deprecated, please use \'-o "
                   "compat6\' instead!");
             return 1;
         case 'o':
@@ -334,9 +326,9 @@ static int img_create(int argc, char **argv)
         ssize_t sval;
         sval = strtosz_suffix(argv[optind++], NULL, STRTOSZ_DEFSUFFIX_B);
         if (sval < 0) {
-            error("Invalid image size specified! You may use k, M, G or "
+            error_report("Invalid image size specified! You may use k, M, G or "
                   "T suffixes for ");
-            error("kilobytes, megabytes, gigabytes and terabytes.");
+            error_report("kilobytes, megabytes, gigabytes and terabytes.");
             ret = -1;
             goto out;
         }
@@ -400,7 +392,7 @@ static int img_check(int argc, char **argv)
     ret = bdrv_check(bs, &result);
 
     if (ret == -ENOTSUP) {
-        error("This image format does not support checks");
+        error_report("This image format does not support checks");
         bdrv_delete(bs);
         return 1;
     }
@@ -482,16 +474,16 @@ static int img_commit(int argc, char **argv)
         printf("Image committed.\n");
         break;
     case -ENOENT:
-        error("No disk inserted");
+        error_report("No disk inserted");
         break;
     case -EACCES:
-        error("Image is read-only");
+        error_report("Image is read-only");
         break;
     case -ENOTSUP:
-        error("Image is already committed");
+        error_report("Image is already committed");
         break;
     default:
-        error("Error while committing image");
+        error_report("Error while committing image");
         break;
     }
 
@@ -614,11 +606,11 @@ static int img_convert(int argc, char **argv)
             compress = 1;
             break;
         case 'e':
-            error("qemu-img: option -e is deprecated, please use \'-o "
+            error_report("qemu-img: option -e is deprecated, please use \'-o "
                   "encryption\' instead!");
             return 1;
         case '6':
-            error("qemu-img: option -6 is deprecated, please use \'-o "
+            error_report("qemu-img: option -6 is deprecated, please use \'-o "
                   "compat6\' instead!");
             return 1;
         case 'o':
@@ -643,7 +635,8 @@ static int img_convert(int argc, char **argv)
     }
 
     if (bs_n > 1 && out_baseimg) {
-        error("-B makes no sense when concatenating multiple input images");
+        error_report("-B makes no sense when concatenating multiple input "
+                     "images");
         ret = -1;
         goto out;
     }
@@ -654,7 +647,7 @@ static int img_convert(int argc, char **argv)
     for (bs_i = 0; bs_i < bs_n; bs_i++) {
         bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt, BDRV_O_FLAGS);
         if (!bs[bs_i]) {
-            error("Could not open '%s'", argv[optind + bs_i]);
+            error_report("Could not open '%s'", argv[optind + bs_i]);
             ret = -1;
             goto out;
         }
@@ -664,12 +657,12 @@ static int img_convert(int argc, char **argv)
 
     if (snapshot_name != NULL) {
         if (bs_n > 1) {
-            error("No support for concatenating multiple snapshot\n");
+            error_report("No support for concatenating multiple snapshot\n");
             ret = -1;
             goto out;
         }
         if (bdrv_snapshot_load_tmp(bs[0], snapshot_name) < 0) {
-            error("Failed to load snapshot\n");
+            error_report("Failed to load snapshot\n");
             ret = -1;
             goto out;
         }
@@ -678,14 +671,14 @@ static int img_convert(int argc, char **argv)
     /* Find driver and parse its options */
     drv = bdrv_find_format(out_fmt);
     if (!drv) {
-        error("Unknown file format '%s'", out_fmt);
+        error_report("Unknown file format '%s'", out_fmt);
         ret = -1;
         goto out;
     }
 
     proto_drv = bdrv_find_protocol(out_filename);
     if (!proto_drv) {
-        error("Unknown protocol '%s'", out_filename);
+        error_report("Unknown protocol '%s'", out_filename);
         ret = -1;
         goto out;
     }
@@ -698,7 +691,7 @@ static int img_convert(int argc, char **argv)
     if (options) {
         param = parse_option_parameters(options, create_options, param);
         if (param == NULL) {
-            error("Invalid options for file format '%s'.", out_fmt);
+            error_report("Invalid options for file format '%s'.", out_fmt);
             ret = -1;
             goto out;
         }
@@ -724,13 +717,14 @@ static int img_convert(int argc, char **argv)
             get_option_parameter(param, BLOCK_OPT_ENCRYPT);
 
         if (!drv->bdrv_write_compressed) {
-            error("Compression not supported for this file format");
+            error_report("Compression not supported for this file format");
             ret = -1;
             goto out;
         }
 
         if (encryption && encryption->value.n) {
-            error("Compression and encryption not supported at the same time");
+            error_report("Compression and encryption not supported at "
+                         "the same time");
             ret = -1;
             goto out;
         }
@@ -740,11 +734,14 @@ static int img_convert(int argc, char **argv)
     ret = bdrv_create(drv, out_filename, param);
     if (ret < 0) {
         if (ret == -ENOTSUP) {
-            error("Formatting not supported for file format '%s'", out_fmt);
+            error_report("Formatting not supported for file format '%s'",
+                         out_fmt);
         } else if (ret == -EFBIG) {
-            error("The image size is too large for file format '%s'", out_fmt);
+            error_report("The image size is too large for file format '%s'",
+                         out_fmt);
         } else {
-            error("%s: error while converting %s: %s", out_filename, out_fmt, strerror(-ret));
+            error_report("%s: error while converting %s: %s",
+                         out_filename, out_fmt, strerror(-ret));
         }
         goto out;
     }
@@ -764,12 +761,12 @@ static int img_convert(int argc, char **argv)
     if (compress) {
         ret = bdrv_get_info(out_bs, &bdi);
         if (ret < 0) {
-            error("could not get block driver info");
+            error_report("could not get block driver info");
             goto out;
         }
         cluster_size = bdi.cluster_size;
         if (cluster_size <= 0 || cluster_size > IO_BUF_SIZE) {
-            error("invalid cluster size");
+            error_report("invalid cluster size");
             ret = -1;
             goto out;
         }
@@ -810,7 +807,7 @@ static int img_convert(int argc, char **argv)
 
                 ret = bdrv_read(bs[bs_i], bs_num, buf2, nlow);
                 if (ret < 0) {
-                    error("error while reading");
+                    error_report("error while reading");
                     goto out;
                 }
 
@@ -828,7 +825,7 @@ static int img_convert(int argc, char **argv)
                 ret = bdrv_write_compressed(out_bs, sector_num, buf,
                                             cluster_sectors);
                 if (ret != 0) {
-                    error("error while compressing sector %" PRId64,
+                    error_report("error while compressing sector %" PRId64,
                           sector_num);
                     goto out;
                 }
@@ -887,7 +884,7 @@ static int img_convert(int argc, char **argv)
 
             ret = bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n);
             if (ret < 0) {
-                error("error while reading");
+                error_report("error while reading");
                 goto out;
             }
             /* NOTE: at the same time we convert, we do not write zero
@@ -906,7 +903,7 @@ static int img_convert(int argc, char **argv)
                     is_allocated_sectors(buf1, n, &n1)) {
                     ret = bdrv_write(out_bs, sector_num, buf1, n1);
                     if (ret < 0) {
-                        error("error while writing");
+                        error_report("error while writing");
                         goto out;
                     }
                 }
@@ -1148,7 +1145,7 @@ static int img_snapshot(int argc, char **argv)
 
         ret = bdrv_snapshot_create(bs, &sn);
         if (ret) {
-            error("Could not create snapshot '%s': %d (%s)",
+            error_report("Could not create snapshot '%s': %d (%s)",
                 snapshot_name, ret, strerror(-ret));
         }
         break;
@@ -1156,7 +1153,7 @@ static int img_snapshot(int argc, char **argv)
     case SNAPSHOT_APPLY:
         ret = bdrv_snapshot_goto(bs, snapshot_name);
         if (ret) {
-            error("Could not apply snapshot '%s': %d (%s)",
+            error_report("Could not apply snapshot '%s': %d (%s)",
                 snapshot_name, ret, strerror(-ret));
         }
         break;
@@ -1164,7 +1161,7 @@ static int img_snapshot(int argc, char **argv)
     case SNAPSHOT_DELETE:
         ret = bdrv_snapshot_delete(bs, snapshot_name);
         if (ret) {
-            error("Could not delete snapshot '%s': %d (%s)",
+            error_report("Could not delete snapshot '%s': %d (%s)",
                 snapshot_name, ret, strerror(-ret));
         }
         break;
@@ -1241,7 +1238,7 @@ static int img_rebase(int argc, char **argv)
     if (!unsafe && bs->backing_format[0] != '\0') {
         old_backing_drv = bdrv_find_format(bs->backing_format);
         if (old_backing_drv == NULL) {
-            error("Invalid format name: '%s'", bs->backing_format);
+            error_report("Invalid format name: '%s'", bs->backing_format);
             ret = -1;
             goto out;
         }
@@ -1250,7 +1247,7 @@ static int img_rebase(int argc, char **argv)
     if (out_basefmt != NULL) {
         new_backing_drv = bdrv_find_format(out_basefmt);
         if (new_backing_drv == NULL) {
-            error("Invalid format name: '%s'", out_basefmt);
+            error_report("Invalid format name: '%s'", out_basefmt);
             ret = -1;
             goto out;
         }
@@ -1269,7 +1266,7 @@ static int img_rebase(int argc, char **argv)
         ret = bdrv_open(bs_old_backing, backing_name, BDRV_O_FLAGS,
                         old_backing_drv);
         if (ret) {
-            error("Could not open old backing file '%s'", backing_name);
+            error_report("Could not open old backing file '%s'", backing_name);
             goto out;
         }
 
@@ -1277,7 +1274,7 @@ static int img_rebase(int argc, char **argv)
         ret = bdrv_open(bs_new_backing, out_baseimg, BDRV_O_FLAGS,
                         new_backing_drv);
         if (ret) {
-            error("Could not open new backing file '%s'", out_baseimg);
+            error_report("Could not open new backing file '%s'", out_baseimg);
             goto out;
         }
     }
@@ -1321,12 +1318,12 @@ static int img_rebase(int argc, char **argv)
             /* Read old and new backing file */
             ret = bdrv_read(bs_old_backing, sector, buf_old, n);
             if (ret < 0) {
-                error("error while reading from old backing file");
+                error_report("error while reading from old backing file");
                 goto out;
             }
             ret = bdrv_read(bs_new_backing, sector, buf_new, n);
             if (ret < 0) {
-                error("error while reading from new backing file");
+                error_report("error while reading from new backing file");
                 goto out;
             }
 
@@ -1342,7 +1339,7 @@ static int img_rebase(int argc, char **argv)
                     ret = bdrv_write(bs, sector + written,
                         buf_old + written * 512, pnum);
                     if (ret < 0) {
-                        error("Error while writing to COW image: %s",
+                        error_report("Error while writing to COW image: %s",
                             strerror(-ret));
                         goto out;
                     }
@@ -1363,10 +1360,10 @@ static int img_rebase(int argc, char **argv)
      */
     ret = bdrv_change_backing_file(bs, out_baseimg, out_basefmt);
     if (ret == -ENOSPC) {
-        error("Could not change the backing file to '%s': No space left in "
-            "the file header", out_baseimg);
+        error_report("Could not change the backing file to '%s': No "
+                     "space left in the file header", out_baseimg);
     } else if (ret < 0) {
-        error("Could not change the backing file to '%s': %s",
+        error_report("Could not change the backing file to '%s': %s",
             out_baseimg, strerror(-ret));
     }
 
@@ -1465,7 +1462,7 @@ static int img_resize(int argc, char **argv)
         total_size = n;
     }
     if (total_size <= 0) {
-        error("New image size must be positive");
+        error_report("New image size must be positive");
         ret = -1;
         goto out;
     }
@@ -1476,13 +1473,13 @@ static int img_resize(int argc, char **argv)
         printf("Image resized.\n");
         break;
     case -ENOTSUP:
-        error("This image format does not support resize");
+        error_report("This image format does not support resize");
         break;
     case -EACCES:
-        error("Image is read-only");
+        error_report("Image is read-only");
         break;
     default:
-        error("Error resizing image (%d)", -ret);
+        error_report("Error resizing image (%d)", -ret);
         break;
     }
 out:
commit 4f70f249ca26e11895b64199f9bcc7a1f894d978
Author: Jes Sorensen <Jes.Sorensen at redhat.com>
Date:   Thu Dec 16 13:52:18 2010 +0100

    bdrv_img_create() use proper errno return values
    
    Kevin suggested to have bdrv_img_create() return proper -errno values
    on error.
    
    Signed-off-by: Jes Sorensen <Jes.Sorensen at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index 0c14eee..fe07d0b 100644
--- a/block.c
+++ b/block.c
@@ -2773,14 +2773,14 @@ int bdrv_img_create(const char *filename, const char *fmt,
     drv = bdrv_find_format(fmt);
     if (!drv) {
         error_report("Unknown file format '%s'", fmt);
-        ret = -1;
+        ret = -EINVAL;
         goto out;
     }
 
     proto_drv = bdrv_find_protocol(filename);
     if (!proto_drv) {
         error_report("Unknown protocol '%s'", filename);
-        ret = -1;
+        ret = -EINVAL;
         goto out;
     }
 
@@ -2799,7 +2799,7 @@ int bdrv_img_create(const char *filename, const char *fmt,
         param = parse_option_parameters(options, create_options, param);
         if (param == NULL) {
             error_report("Invalid options for file format '%s'.", fmt);
-            ret = -1;
+            ret = -EINVAL;
             goto out;
         }
     }
@@ -2809,7 +2809,7 @@ int bdrv_img_create(const char *filename, const char *fmt,
                                  base_filename)) {
             error_report("Backing file not supported for file format '%s'",
                          fmt);
-            ret = -1;
+            ret = -EINVAL;
             goto out;
         }
     }
@@ -2818,7 +2818,7 @@ int bdrv_img_create(const char *filename, const char *fmt,
         if (set_option_parameter(param, BLOCK_OPT_BACKING_FMT, base_fmt)) {
             error_report("Backing file format not supported for file "
                          "format '%s'", fmt);
-            ret = -1;
+            ret = -EINVAL;
             goto out;
         }
     }
@@ -2828,7 +2828,7 @@ int bdrv_img_create(const char *filename, const char *fmt,
         if (!strcmp(filename, backing_file->value.s)) {
             error_report("Error: Trying to create an image with the "
                          "same filename as the backing file");
-            ret = -1;
+            ret = -EINVAL;
             goto out;
         }
     }
@@ -2838,7 +2838,7 @@ int bdrv_img_create(const char *filename, const char *fmt,
         if (!bdrv_find_format(backing_fmt->value.s)) {
             error_report("Unknown backing file format '%s'",
                          backing_fmt->value.s);
-            ret = -1;
+            ret = -EINVAL;
             goto out;
         }
     }
@@ -2860,7 +2860,6 @@ int bdrv_img_create(const char *filename, const char *fmt,
             ret = bdrv_open(bs, backing_file->value.s, flags, drv);
             if (ret < 0) {
                 error_report("Could not open '%s'", filename);
-                ret = -1;
                 goto out;
             }
             bdrv_get_geometry(bs, &size);
@@ -2870,7 +2869,7 @@ int bdrv_img_create(const char *filename, const char *fmt,
             set_option_parameter(param, BLOCK_OPT_SIZE, buf);
         } else {
             error_report("Image creation needs a size parameter");
-            ret = -1;
+            ret = -EINVAL;
             goto out;
         }
     }
@@ -2901,8 +2900,6 @@ out:
     if (bs) {
         bdrv_delete(bs);
     }
-    if (ret) {
-        return 1;
-    }
-    return 0;
+
+    return ret;
 }
commit 792da93a635bce0181c8a46a26941560bf2f7412
Author: Jes Sorensen <Jes.Sorensen at redhat.com>
Date:   Thu Dec 16 13:52:17 2010 +0100

    Prevent creating an image with the same filename as backing file
    
    Signed-off-by: Jes Sorensen <Jes.Sorensen at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index a48b30c..0c14eee 100644
--- a/block.c
+++ b/block.c
@@ -2764,7 +2764,7 @@ int bdrv_img_create(const char *filename, const char *fmt,
                     char *options, uint64_t img_size, int flags)
 {
     QEMUOptionParameter *param = NULL, *create_options = NULL;
-    QEMUOptionParameter *backing_fmt;
+    QEMUOptionParameter *backing_fmt, *backing_file;
     BlockDriverState *bs = NULL;
     BlockDriver *drv, *proto_drv;
     int ret = 0;
@@ -2823,6 +2823,16 @@ int bdrv_img_create(const char *filename, const char *fmt,
         }
     }
 
+    backing_file = get_option_parameter(param, BLOCK_OPT_BACKING_FILE);
+    if (backing_file && backing_file->value.s) {
+        if (!strcmp(filename, backing_file->value.s)) {
+            error_report("Error: Trying to create an image with the "
+                         "same filename as the backing file");
+            ret = -1;
+            goto out;
+        }
+    }
+
     backing_fmt = get_option_parameter(param, BLOCK_OPT_BACKING_FMT);
     if (backing_fmt && backing_fmt->value.s) {
         if (!bdrv_find_format(backing_fmt->value.s)) {
@@ -2836,9 +2846,6 @@ int bdrv_img_create(const char *filename, const char *fmt,
     // The size for the image must always be specified, with one exception:
     // If we are using a backing file, we can obtain the size from there
     if (get_option_parameter(param, BLOCK_OPT_SIZE)->value.n == -1) {
-        QEMUOptionParameter *backing_file =
-            get_option_parameter(param, BLOCK_OPT_BACKING_FILE);
-
         if (backing_file && backing_file->value.s) {
             uint64_t size;
             const char *fmt = NULL;
commit f88825680aa71eb4069cdaee9d65f2269f5c7cf3
Author: Jes Sorensen <Jes.Sorensen at redhat.com>
Date:   Thu Dec 16 13:52:16 2010 +0100

    Introduce do_snapshot_blkdev() and monitor command to handle it.
    
    The monitor command is:
    snapshot_blkdev <device> [snapshot-file] [format]
    
    Default format is qcow2. For now snapshots without a snapshot-file, eg
    internal snapshots, are not supported.
    
    Signed-off-by: Jes Sorensen <Jes.Sorensen at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/blockdev.c b/blockdev.c
index 3b3b82d..d7add36 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -516,6 +516,68 @@ void do_commit(Monitor *mon, const QDict *qdict)
     }
 }
 
+int do_snapshot_blkdev(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    const char *device = qdict_get_str(qdict, "device");
+    const char *filename = qdict_get_try_str(qdict, "snapshot_file");
+    const char *format = qdict_get_try_str(qdict, "format");
+    BlockDriverState *bs;
+    BlockDriver *drv, *proto_drv;
+    int ret = 0;
+    int flags;
+
+    bs = bdrv_find(device);
+    if (!bs) {
+        qerror_report(QERR_DEVICE_NOT_FOUND, device);
+        ret = -1;
+        goto out;
+    }
+
+    if (!format) {
+        format = "qcow2";
+    }
+
+    drv = bdrv_find_format(format);
+    if (!drv) {
+        qerror_report(QERR_INVALID_BLOCK_FORMAT, format);
+        ret = -1;
+        goto out;
+    }
+
+    proto_drv = bdrv_find_protocol(filename);
+    if (!proto_drv) {
+        qerror_report(QERR_INVALID_BLOCK_FORMAT, format);
+        ret = -1;
+        goto out;
+    }
+
+    ret = bdrv_img_create(filename, format, bs->filename,
+                          bs->drv->format_name, NULL, -1, bs->open_flags);
+    if (ret) {
+        goto out;
+    }
+
+    qemu_aio_flush();
+    bdrv_flush(bs);
+
+    flags = bs->open_flags;
+    bdrv_close(bs);
+    ret = bdrv_open(bs, filename, flags, drv);
+    /*
+     * If reopening the image file we just created fails, we really
+     * are in trouble :(
+     */
+    if (ret != 0) {
+        abort();
+    }
+out:
+    if (ret) {
+        ret = -1;
+    }
+
+    return ret;
+}
+
 static int eject_device(Monitor *mon, BlockDriverState *bs, int force)
 {
     if (!force) {
diff --git a/blockdev.h b/blockdev.h
index 4cb8ca9..4536b5c 100644
--- a/blockdev.h
+++ b/blockdev.h
@@ -52,5 +52,6 @@ int do_block_set_passwd(Monitor *mon, const QDict *qdict, QObject **ret_data);
 int do_change_block(Monitor *mon, const char *device,
                     const char *filename, const char *fmt);
 int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
+int do_snapshot_blkdev(Monitor *mon, const QDict *qdict, QObject **ret_data);
 
 #endif
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 23024ba..dd3db36 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -801,6 +801,25 @@ STEXI
 Set maximum tolerated downtime (in seconds) for migration.
 ETEXI
 
+    {
+        .name       = "snapshot_blkdev",
+        .args_type  = "device:s,snapshot_file:s?,format:s?",
+        .params     = "device [new-image-file] [format]",
+        .help       = "initiates a live snapshot\n\t\t\t"
+                      "of device. If a new image file is specified, the\n\t\t\t"
+                      "new image file will become the new root image.\n\t\t\t"
+                      "If format is specified, the snapshot file will\n\t\t\t"
+                      "be created in that format. Otherwise the\n\t\t\t"
+                      "snapshot will be internal! (currently unsupported)",
+        .mhandler.cmd_new = do_snapshot_blkdev,
+    },
+
+STEXI
+ at item snapshot_blkdev
+ at findex snapshot_blkdev
+Snapshot device, using snapshot file as target if provided
+ETEXI
+
 #if defined(TARGET_I386)
     {
         .name       = "drive_add",
commit f88e1a4201e31cac0438df395dfcdd45ac35c17d
Author: Jes Sorensen <Jes.Sorensen at redhat.com>
Date:   Thu Dec 16 13:52:15 2010 +0100

    qemu-img.c: Re-factor img_create()
    
    This patch re-factors img_create() moving the code doing the actual
    work into block.c where it can be shared with QEMU. This is needed to
    be able to create images from QEMU to be used for live snapshots.
    
    Signed-off-by: Jes Sorensen <Jes.Sorensen at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index b4aaf41..a48b30c 100644
--- a/block.c
+++ b/block.c
@@ -2758,3 +2758,144 @@ int64_t bdrv_get_dirty_count(BlockDriverState *bs)
 {
     return bs->dirty_count;
 }
+
+int bdrv_img_create(const char *filename, const char *fmt,
+                    const char *base_filename, const char *base_fmt,
+                    char *options, uint64_t img_size, int flags)
+{
+    QEMUOptionParameter *param = NULL, *create_options = NULL;
+    QEMUOptionParameter *backing_fmt;
+    BlockDriverState *bs = NULL;
+    BlockDriver *drv, *proto_drv;
+    int ret = 0;
+
+    /* Find driver and parse its options */
+    drv = bdrv_find_format(fmt);
+    if (!drv) {
+        error_report("Unknown file format '%s'", fmt);
+        ret = -1;
+        goto out;
+    }
+
+    proto_drv = bdrv_find_protocol(filename);
+    if (!proto_drv) {
+        error_report("Unknown protocol '%s'", filename);
+        ret = -1;
+        goto out;
+    }
+
+    create_options = append_option_parameters(create_options,
+                                              drv->create_options);
+    create_options = append_option_parameters(create_options,
+                                              proto_drv->create_options);
+
+    /* Create parameter list with default values */
+    param = parse_option_parameters("", create_options, param);
+
+    set_option_parameter_int(param, BLOCK_OPT_SIZE, img_size);
+
+    /* Parse -o options */
+    if (options) {
+        param = parse_option_parameters(options, create_options, param);
+        if (param == NULL) {
+            error_report("Invalid options for file format '%s'.", fmt);
+            ret = -1;
+            goto out;
+        }
+    }
+
+    if (base_filename) {
+        if (set_option_parameter(param, BLOCK_OPT_BACKING_FILE,
+                                 base_filename)) {
+            error_report("Backing file not supported for file format '%s'",
+                         fmt);
+            ret = -1;
+            goto out;
+        }
+    }
+
+    if (base_fmt) {
+        if (set_option_parameter(param, BLOCK_OPT_BACKING_FMT, base_fmt)) {
+            error_report("Backing file format not supported for file "
+                         "format '%s'", fmt);
+            ret = -1;
+            goto out;
+        }
+    }
+
+    backing_fmt = get_option_parameter(param, BLOCK_OPT_BACKING_FMT);
+    if (backing_fmt && backing_fmt->value.s) {
+        if (!bdrv_find_format(backing_fmt->value.s)) {
+            error_report("Unknown backing file format '%s'",
+                         backing_fmt->value.s);
+            ret = -1;
+            goto out;
+        }
+    }
+
+    // The size for the image must always be specified, with one exception:
+    // If we are using a backing file, we can obtain the size from there
+    if (get_option_parameter(param, BLOCK_OPT_SIZE)->value.n == -1) {
+        QEMUOptionParameter *backing_file =
+            get_option_parameter(param, BLOCK_OPT_BACKING_FILE);
+
+        if (backing_file && backing_file->value.s) {
+            uint64_t size;
+            const char *fmt = NULL;
+            char buf[32];
+
+            if (backing_fmt && backing_fmt->value.s) {
+                fmt = backing_fmt->value.s;
+            }
+
+            bs = bdrv_new("");
+
+            ret = bdrv_open(bs, backing_file->value.s, flags, drv);
+            if (ret < 0) {
+                error_report("Could not open '%s'", filename);
+                ret = -1;
+                goto out;
+            }
+            bdrv_get_geometry(bs, &size);
+            size *= 512;
+
+            snprintf(buf, sizeof(buf), "%" PRId64, size);
+            set_option_parameter(param, BLOCK_OPT_SIZE, buf);
+        } else {
+            error_report("Image creation needs a size parameter");
+            ret = -1;
+            goto out;
+        }
+    }
+
+    printf("Formatting '%s', fmt=%s ", filename, fmt);
+    print_option_parameters(param);
+    puts("");
+
+    ret = bdrv_create(drv, filename, param);
+
+    if (ret < 0) {
+        if (ret == -ENOTSUP) {
+            error_report("Formatting or formatting option not supported for "
+                         "file format '%s'", fmt);
+        } else if (ret == -EFBIG) {
+            error_report("The image size is too large for file format '%s'",
+                         fmt);
+        } else {
+            error_report("%s: error while creating %s: %s", filename, fmt,
+                         strerror(-ret));
+        }
+    }
+
+out:
+    free_option_parameters(create_options);
+    free_option_parameters(param);
+
+    if (bs) {
+        bdrv_delete(bs);
+    }
+    if (ret) {
+        return 1;
+    }
+    return 0;
+}
diff --git a/block.h b/block.h
index 78ecfac..b812172 100644
--- a/block.h
+++ b/block.h
@@ -227,6 +227,10 @@ int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
 int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf,
                       int64_t pos, int size);
 
+int bdrv_img_create(const char *filename, const char *fmt,
+                    const char *base_filename, const char *base_fmt,
+                    char *options, uint64_t img_size, int flags);
+
 #define BDRV_SECTORS_PER_DIRTY_CHUNK 2048
 
 void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable);
diff --git a/qemu-img.c b/qemu-img.c
index f576cfb..0ff179f 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -288,9 +288,6 @@ static int img_create(int argc, char **argv)
     const char *base_fmt = NULL;
     const char *filename;
     const char *base_filename = NULL;
-    BlockDriver *drv, *proto_drv;
-    QEMUOptionParameter *param = NULL, *create_options = NULL;
-    QEMUOptionParameter *backing_fmt = NULL;
     char *options = NULL;
 
     for(;;) {
@@ -351,110 +348,9 @@ static int img_create(int argc, char **argv)
         goto out;
     }
 
-    /* Find driver and parse its options */
-    drv = bdrv_find_format(fmt);
-    if (!drv) {
-        error("Unknown file format '%s'", fmt);
-        ret = -1;
-        goto out;
-    }
-
-    proto_drv = bdrv_find_protocol(filename);
-    if (!proto_drv) {
-        error("Unknown protocol '%s'", filename);
-        ret = -1;
-        goto out;
-    }
-
-    create_options = append_option_parameters(create_options,
-                                              drv->create_options);
-    create_options = append_option_parameters(create_options,
-                                              proto_drv->create_options);
-
-    /* Create parameter list with default values */
-    param = parse_option_parameters("", create_options, param);
-
-    set_option_parameter_int(param, BLOCK_OPT_SIZE, img_size);
-
-    /* Parse -o options */
-    if (options) {
-        param = parse_option_parameters(options, create_options, param);
-        if (param == NULL) {
-            error("Invalid options for file format '%s'.", fmt);
-            ret = -1;
-            goto out;
-        }
-    }
-
-    /* Add old-style options to parameters */
-    ret = add_old_style_options(fmt, param, base_filename, base_fmt);
-    if (ret < 0) {
-        goto out;
-    }
-
-    backing_fmt = get_option_parameter(param, BLOCK_OPT_BACKING_FMT);
-    if (backing_fmt && backing_fmt->value.s) {
-        if (!bdrv_find_format(backing_fmt->value.s)) {
-            error("Unknown backing file format '%s'",
-                  backing_fmt->value.s);
-            ret = -1;
-            goto out;
-        }
-    }
-
-    // The size for the image must always be specified, with one exception:
-    // If we are using a backing file, we can obtain the size from there
-    if (get_option_parameter(param, BLOCK_OPT_SIZE)->value.n == -1) {
-
-        QEMUOptionParameter *backing_file =
-            get_option_parameter(param, BLOCK_OPT_BACKING_FILE);
-
-        if (backing_file && backing_file->value.s) {
-            BlockDriverState *bs;
-            uint64_t size;
-            const char *fmt = NULL;
-            char buf[32];
-
-            if (backing_fmt && backing_fmt->value.s) {
-                fmt = backing_fmt->value.s;
-            }
-
-            bs = bdrv_new_open(backing_file->value.s, fmt, BDRV_O_FLAGS);
-            if (!bs) {
-                ret = -1;
-                goto out;
-            }
-            bdrv_get_geometry(bs, &size);
-            size *= 512;
-            bdrv_delete(bs);
-
-            snprintf(buf, sizeof(buf), "%" PRId64, size);
-            set_option_parameter(param, BLOCK_OPT_SIZE, buf);
-        } else {
-            error("Image creation needs a size parameter");
-            ret = -1;
-            goto out;
-        }
-    }
-
-    printf("Formatting '%s', fmt=%s ", filename, fmt);
-    print_option_parameters(param);
-    puts("");
-
-    ret = bdrv_create(drv, filename, param);
-
-    if (ret < 0) {
-        if (ret == -ENOTSUP) {
-            error("Formatting or formatting option not supported for file format '%s'", fmt);
-        } else if (ret == -EFBIG) {
-            error("The image size is too large for file format '%s'", fmt);
-        } else {
-            error("%s: error while creating %s: %s", filename, fmt, strerror(-ret));
-        }
-    }
+    ret = bdrv_img_create(filename, fmt, base_filename, base_fmt,
+                          options, img_size, BDRV_O_FLAGS);
 out:
-    free_option_parameters(create_options);
-    free_option_parameters(param);
     if (ret) {
         return 1;
     }
commit 53f76e5857b66dd7fa90efa9ea8326eff5aa693f
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Thu Dec 16 15:10:32 2010 +0100

    qemu-img: Call error_set_progname
    
    Call error_set_progname during the qemu-img initialization, so that error
    messages printed with error_report() use the right prefix.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/qemu-img.c b/qemu-img.c
index 1d936ed..f576cfb 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -23,6 +23,7 @@
  */
 #include "qemu-common.h"
 #include "qemu-option.h"
+#include "qemu-error.h"
 #include "osdep.h"
 #include "sysemu.h"
 #include "block_int.h"
@@ -1612,6 +1613,8 @@ int main(int argc, char **argv)
     const img_cmd_t *cmd;
     const char *cmdname;
 
+    error_set_progname(argv[0]);
+
     bdrv_init();
     if (argc < 2)
         help();
commit 1bdaa28d7a521628345a46626c2fd6c279562776
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Dec 14 16:23:38 2010 +0100

    ide: honor ncq for atapi
    
    ATAPI also can do ncq, so let's expose the capability.
    
    This patch makes CD-ROM support work on Windows 7 for me.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/ide/core.c b/hw/ide/core.c
index 9e1d4e6..9496e99 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -217,6 +217,12 @@ static void ide_atapi_identify(IDEState *s)
     put_le16(p + 71, 30); /* in ns */
     put_le16(p + 72, 30); /* in ns */
 
+    if (s->ncq_queues) {
+        put_le16(p + 75, s->ncq_queues - 1);
+        /* NCQ supported */
+        put_le16(p + 76, (1 << 8));
+    }
+
     put_le16(p + 80, 0x1e); /* support up to ATA/ATAPI-4 */
 #ifdef USE_DMA_CDROM
     put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */
commit 38a08f0557418d14ad49616b31f336b30c2c684d
Author: Sebastian Herbszt <herbszt at gmx.de>
Date:   Tue Dec 14 01:34:43 2010 +0100

    ahci: set SATA Mode Select
    
    Set SATA Mode Select to AHCI in the Address Map Register.
    
    Signed-off-by: Sebastian Herbszt <herbszt at gmx.de>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index f937a92..8ae236a 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -1473,6 +1473,9 @@ static int pci_ahci_init(PCIDevice *dev)
     d->card.config[PCI_LATENCY_TIMER]   = 0x00;  /* Latency timer */
     pci_config_set_interrupt_pin(d->card.config, 1);
 
+    /* XXX Software should program this register */
+    d->card.config[0x90]   = 1 << 6; /* Address Map Register - AHCI mode */
+
     qemu_register_reset(ahci_reset, d);
 
     /* XXX BAR size should be 1k, but that breaks, so bump it to 4k for now */
commit f675d5c889363436822e5c10f3da1c843109d1e3
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Dec 14 01:34:42 2010 +0100

    config: add ahci for pci capable machines
    
    This patch enables AHCI for all machines supporting PCI.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/default-configs/pci.mak b/default-configs/pci.mak
index d700b3c..0471efb 100644
--- a/default-configs/pci.mak
+++ b/default-configs/pci.mak
@@ -13,3 +13,4 @@ CONFIG_E1000_PCI=y
 CONFIG_IDE_CORE=y
 CONFIG_IDE_QDEV=y
 CONFIG_IDE_PCI=y
+CONFIG_AHCI=y
commit 461d13d31ca58e9940bc4b935f3e4ab34294ab8f
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Dec 14 01:34:41 2010 +0100

    config: move ide core and pci to pci.mak
    
    Every device that can do PCI should also be able to do IDE. So let's move
    the IDE definitions over to pci.mak.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index ac48dc1..8d1174f 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -8,7 +8,6 @@ CONFIG_ECC=y
 CONFIG_SERIAL=y
 CONFIG_PTIMER=y
 CONFIG_SD=y
-CONFIG_IDE_CORE=y
 CONFIG_MAX7310=y
 CONFIG_WM8750=y
 CONFIG_TWL92230=y
diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
index ce905d2..323fafb 100644
--- a/default-configs/i386-softmmu.mak
+++ b/default-configs/i386-softmmu.mak
@@ -13,9 +13,6 @@ CONFIG_FDC=y
 CONFIG_ACPI=y
 CONFIG_APM=y
 CONFIG_DMA=y
-CONFIG_IDE_CORE=y
-CONFIG_IDE_QDEV=y
-CONFIG_IDE_PCI=y
 CONFIG_IDE_ISA=y
 CONFIG_IDE_PIIX=y
 CONFIG_NE2000_ISA=y
diff --git a/default-configs/mips-softmmu.mak b/default-configs/mips-softmmu.mak
index 565e611..f524971 100644
--- a/default-configs/mips-softmmu.mak
+++ b/default-configs/mips-softmmu.mak
@@ -17,9 +17,6 @@ CONFIG_ACPI=y
 CONFIG_APM=y
 CONFIG_DMA=y
 CONFIG_PIIX4=y
-CONFIG_IDE_CORE=y
-CONFIG_IDE_QDEV=y
-CONFIG_IDE_PCI=y
 CONFIG_IDE_ISA=y
 CONFIG_IDE_PIIX=y
 CONFIG_NE2000_ISA=y
diff --git a/default-configs/mips64-softmmu.mak b/default-configs/mips64-softmmu.mak
index 03bd8eb..aeab6b2 100644
--- a/default-configs/mips64-softmmu.mak
+++ b/default-configs/mips64-softmmu.mak
@@ -17,9 +17,6 @@ CONFIG_ACPI=y
 CONFIG_APM=y
 CONFIG_DMA=y
 CONFIG_PIIX4=y
-CONFIG_IDE_CORE=y
-CONFIG_IDE_QDEV=y
-CONFIG_IDE_PCI=y
 CONFIG_IDE_ISA=y
 CONFIG_IDE_PIIX=y
 CONFIG_NE2000_ISA=y
diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
index 4661617..8e6511c 100644
--- a/default-configs/mips64el-softmmu.mak
+++ b/default-configs/mips64el-softmmu.mak
@@ -17,9 +17,6 @@ CONFIG_ACPI=y
 CONFIG_APM=y
 CONFIG_DMA=y
 CONFIG_PIIX4=y
-CONFIG_IDE_CORE=y
-CONFIG_IDE_QDEV=y
-CONFIG_IDE_PCI=y
 CONFIG_IDE_ISA=y
 CONFIG_IDE_PIIX=y
 CONFIG_IDE_VIA=y
diff --git a/default-configs/mipsel-softmmu.mak b/default-configs/mipsel-softmmu.mak
index 92fc473..a05ac25 100644
--- a/default-configs/mipsel-softmmu.mak
+++ b/default-configs/mipsel-softmmu.mak
@@ -17,9 +17,6 @@ CONFIG_ACPI=y
 CONFIG_APM=y
 CONFIG_DMA=y
 CONFIG_PIIX4=y
-CONFIG_IDE_CORE=y
-CONFIG_IDE_QDEV=y
-CONFIG_IDE_PCI=y
 CONFIG_IDE_ISA=y
 CONFIG_IDE_PIIX=y
 CONFIG_NE2000_ISA=y
diff --git a/default-configs/pci.mak b/default-configs/pci.mak
index c74a99f..d700b3c 100644
--- a/default-configs/pci.mak
+++ b/default-configs/pci.mak
@@ -10,3 +10,6 @@ CONFIG_PCNET_COMMON=y
 CONFIG_LSI_SCSI_PCI=y
 CONFIG_RTL8139_PCI=y
 CONFIG_E1000_PCI=y
+CONFIG_IDE_CORE=y
+CONFIG_IDE_QDEV=y
+CONFIG_IDE_PCI=y
diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index f1cb99e..4563742 100644
--- a/default-configs/ppc-softmmu.mak
+++ b/default-configs/ppc-softmmu.mak
@@ -23,9 +23,6 @@ CONFIG_GRACKLE_PCI=y
 CONFIG_UNIN_PCI=y
 CONFIG_DEC_PCI=y
 CONFIG_PPCE500_PCI=y
-CONFIG_IDE_CORE=y
-CONFIG_IDE_QDEV=y
-CONFIG_IDE_PCI=y
 CONFIG_IDE_ISA=y
 CONFIG_IDE_CMD646=y
 CONFIG_IDE_MACIO=y
diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak
index 83cbe97..d5073b3 100644
--- a/default-configs/ppc64-softmmu.mak
+++ b/default-configs/ppc64-softmmu.mak
@@ -23,9 +23,6 @@ CONFIG_GRACKLE_PCI=y
 CONFIG_UNIN_PCI=y
 CONFIG_DEC_PCI=y
 CONFIG_PPCE500_PCI=y
-CONFIG_IDE_CORE=y
-CONFIG_IDE_QDEV=y
-CONFIG_IDE_PCI=y
 CONFIG_IDE_ISA=y
 CONFIG_IDE_CMD646=y
 CONFIG_IDE_MACIO=y
diff --git a/default-configs/ppcemb-softmmu.mak b/default-configs/ppcemb-softmmu.mak
index 2b52d4a..9f0730c 100644
--- a/default-configs/ppcemb-softmmu.mak
+++ b/default-configs/ppcemb-softmmu.mak
@@ -23,9 +23,6 @@ CONFIG_GRACKLE_PCI=y
 CONFIG_UNIN_PCI=y
 CONFIG_DEC_PCI=y
 CONFIG_PPCE500_PCI=y
-CONFIG_IDE_CORE=y
-CONFIG_IDE_QDEV=y
-CONFIG_IDE_PCI=y
 CONFIG_IDE_ISA=y
 CONFIG_IDE_CMD646=y
 CONFIG_IDE_MACIO=y
diff --git a/default-configs/sh4-softmmu.mak b/default-configs/sh4-softmmu.mak
index 87247a4..5c69acc 100644
--- a/default-configs/sh4-softmmu.mak
+++ b/default-configs/sh4-softmmu.mak
@@ -3,6 +3,5 @@
 include pci.mak
 CONFIG_SERIAL=y
 CONFIG_PTIMER=y
-CONFIG_IDE_CORE=y
 CONFIG_PFLASH_CFI02=y
 CONFIG_ISA_MMIO=y
diff --git a/default-configs/sh4eb-softmmu.mak b/default-configs/sh4eb-softmmu.mak
index 5b8a16e..7cdc122 100644
--- a/default-configs/sh4eb-softmmu.mak
+++ b/default-configs/sh4eb-softmmu.mak
@@ -3,6 +3,5 @@
 include pci.mak
 CONFIG_SERIAL=y
 CONFIG_PTIMER=y
-CONFIG_IDE_CORE=y
 CONFIG_PFLASH_CFI02=y
 CONFIG_ISA_MMIO=y
diff --git a/default-configs/sparc64-softmmu.mak b/default-configs/sparc64-softmmu.mak
index ecc3122..d8f17e7 100644
--- a/default-configs/sparc64-softmmu.mak
+++ b/default-configs/sparc64-softmmu.mak
@@ -9,8 +9,5 @@ CONFIG_SERIAL=y
 CONFIG_PARALLEL=y
 CONFIG_PCKBD=y
 CONFIG_FDC=y
-CONFIG_IDE_CORE=y
-CONFIG_IDE_QDEV=y
-CONFIG_IDE_PCI=y
 CONFIG_IDE_ISA=y
 CONFIG_IDE_CMD646=y
diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak
index 7f22599..eff26d2 100644
--- a/default-configs/x86_64-softmmu.mak
+++ b/default-configs/x86_64-softmmu.mak
@@ -13,9 +13,6 @@ CONFIG_FDC=y
 CONFIG_ACPI=y
 CONFIG_APM=y
 CONFIG_DMA=y
-CONFIG_IDE_CORE=y
-CONFIG_IDE_QDEV=y
-CONFIG_IDE_PCI=y
 CONFIG_IDE_ISA=y
 CONFIG_IDE_PIIX=y
 CONFIG_NE2000_ISA=y
commit f6ad2e32f8d833c7f1c75dc084a84a8f02704d64
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Dec 14 01:34:40 2010 +0100

    ahci: add ahci emulation
    
    This patch adds an emulation layer for an ICH-9 AHCI controller. For now
    this controller does not do IDE legacy emulation. It is a pure AHCI controller.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/Makefile.objs b/Makefile.objs
index 24b2f99..72c07dd 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -243,6 +243,7 @@ hw-obj-$(CONFIG_IDE_PIIX) += ide/piix.o
 hw-obj-$(CONFIG_IDE_CMD646) += ide/cmd646.o
 hw-obj-$(CONFIG_IDE_MACIO) += ide/macio.o
 hw-obj-$(CONFIG_IDE_VIA) += ide/via.o
+hw-obj-$(CONFIG_AHCI) += ide/ahci.o
 
 # SCSI layer
 hw-obj-$(CONFIG_LSI_SCSI_PCI) += lsi53c895a.o
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
new file mode 100644
index 0000000..f937a92
--- /dev/null
+++ b/hw/ide/ahci.c
@@ -0,0 +1,1524 @@
+/*
+ * QEMU AHCI Emulation
+ *
+ * Copyright (c) 2010 qiaochong at loongson.cn
+ * Copyright (c) 2010 Roland Elek <elek.roland at gmail.com>
+ * Copyright (c) 2010 Sebastian Herbszt <herbszt at gmx.de>
+ * Copyright (c) 2010 Alexander Graf <agraf at suse.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * lspci dump of a ICH-9 real device in IDE mode (hopefully close enough):
+ *
+ * 00:1f.2 SATA controller [0106]: Intel Corporation 82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA AHCI Controller [8086:2922] (rev 02) (prog-if 01 [AHCI 1.0])
+ *         Subsystem: Intel Corporation 82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA AHCI Controller [8086:2922]
+ *         Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+
+ *         Status: Cap+ 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
+ *         Latency: 0
+ *         Interrupt: pin B routed to IRQ 222
+ *         Region 0: I/O ports at d000 [size=8]
+ *         Region 1: I/O ports at cc00 [size=4]
+ *         Region 2: I/O ports at c880 [size=8]
+ *         Region 3: I/O ports at c800 [size=4]
+ *         Region 4: I/O ports at c480 [size=32]
+ *         Region 5: Memory at febf9000 (32-bit, non-prefetchable) [size=2K]
+ *         Capabilities: [80] Message Signalled Interrupts: Mask- 64bit- Count=1/16 Enable+
+ *                 Address: fee0f00c  Data: 41d9
+ *         Capabilities: [70] Power Management version 3
+ *                 Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot+,D3cold-)
+ *                 Status: D0 PME-Enable- DSel=0 DScale=0 PME-
+ *         Capabilities: [a8] SATA HBA <?>
+ *         Capabilities: [b0] Vendor Specific Information <?>
+ *         Kernel driver in use: ahci
+ *         Kernel modules: ahci
+ * 00: 86 80 22 29 07 04 b0 02 02 01 06 01 00 00 00 00
+ * 10: 01 d0 00 00 01 cc 00 00 81 c8 00 00 01 c8 00 00
+ * 20: 81 c4 00 00 00 90 bf fe 00 00 00 00 86 80 22 29
+ * 30: 00 00 00 00 80 00 00 00 00 00 00 00 0f 02 00 00
+ * 40: 00 80 00 80 00 00 00 00 00 00 00 00 00 00 00 00
+ * 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 70: 01 a8 03 40 08 00 00 00 00 00 00 00 00 00 00 00
+ * 80: 05 70 09 00 0c f0 e0 fe d9 41 00 00 00 00 00 00
+ * 90: 40 00 0f 82 93 01 00 00 00 00 00 00 00 00 00 00
+ * a0: ac 00 00 00 0a 00 12 00 12 b0 10 00 48 00 00 00
+ * b0: 09 00 06 20 00 00 00 00 00 00 00 00 00 00 00 00
+ * c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * f0: 00 00 00 00 00 00 00 00 86 0f 02 00 00 00 00 00
+ *
+ */
+
+#include <hw/hw.h>
+#include <hw/msi.h>
+#include <hw/pc.h>
+#include <hw/pci.h>
+
+#include "monitor.h"
+#include "dma.h"
+#include "cpu-common.h"
+#include "blockdev.h"
+#include "internal.h"
+#include <hw/ide/pci.h>
+
+/* #define DEBUG_AHCI */
+
+#ifdef DEBUG_AHCI
+#define DPRINTF(port, fmt, ...) \
+do { fprintf(stderr, "ahci: %s: [%d] ", __FUNCTION__, port); \
+     fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(port, fmt, ...) do {} while(0)
+#endif
+
+#define AHCI_PCI_BAR              5
+#define AHCI_MAX_PORTS            32
+#define AHCI_MAX_SG               168 /* hardware max is 64K */
+#define AHCI_DMA_BOUNDARY         0xffffffff
+#define AHCI_USE_CLUSTERING       0
+#define AHCI_MAX_CMDS             32
+#define AHCI_CMD_SZ               32
+#define AHCI_CMD_SLOT_SZ          (AHCI_MAX_CMDS * AHCI_CMD_SZ)
+#define AHCI_RX_FIS_SZ            256
+#define AHCI_CMD_TBL_CDB          0x40
+#define AHCI_CMD_TBL_HDR_SZ       0x80
+#define AHCI_CMD_TBL_SZ           (AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16))
+#define AHCI_CMD_TBL_AR_SZ        (AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS)
+#define AHCI_PORT_PRIV_DMA_SZ     (AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ + \
+                                   AHCI_RX_FIS_SZ)
+
+#define AHCI_IRQ_ON_SG            (1 << 31)
+#define AHCI_CMD_ATAPI            (1 << 5)
+#define AHCI_CMD_WRITE            (1 << 6)
+#define AHCI_CMD_PREFETCH         (1 << 7)
+#define AHCI_CMD_RESET            (1 << 8)
+#define AHCI_CMD_CLR_BUSY         (1 << 10)
+
+#define RX_FIS_D2H_REG            0x40 /* offset of D2H Register FIS data */
+#define RX_FIS_SDB                0x58 /* offset of SDB FIS data */
+#define RX_FIS_UNK                0x60 /* offset of Unknown FIS data */
+
+/* global controller registers */
+#define HOST_CAP                  0x00 /* host capabilities */
+#define HOST_CTL                  0x04 /* global host control */
+#define HOST_IRQ_STAT             0x08 /* interrupt status */
+#define HOST_PORTS_IMPL           0x0c /* bitmap of implemented ports */
+#define HOST_VERSION              0x10 /* AHCI spec. version compliancy */
+
+/* HOST_CTL bits */
+#define HOST_CTL_RESET            (1 << 0)  /* reset controller; self-clear */
+#define HOST_CTL_IRQ_EN           (1 << 1)  /* global IRQ enable */
+#define HOST_CTL_AHCI_EN          (1 << 31) /* AHCI enabled */
+
+/* HOST_CAP bits */
+#define HOST_CAP_SSC              (1 << 14) /* Slumber capable */
+#define HOST_CAP_AHCI             (1 << 18) /* AHCI only */
+#define HOST_CAP_CLO              (1 << 24) /* Command List Override support */
+#define HOST_CAP_SSS              (1 << 27) /* Staggered Spin-up */
+#define HOST_CAP_NCQ              (1 << 30) /* Native Command Queueing */
+#define HOST_CAP_64               (1 << 31) /* PCI DAC (64-bit DMA) support */
+
+/* registers for each SATA port */
+#define PORT_LST_ADDR             0x00 /* command list DMA addr */
+#define PORT_LST_ADDR_HI          0x04 /* command list DMA addr hi */
+#define PORT_FIS_ADDR             0x08 /* FIS rx buf addr */
+#define PORT_FIS_ADDR_HI          0x0c /* FIS rx buf addr hi */
+#define PORT_IRQ_STAT             0x10 /* interrupt status */
+#define PORT_IRQ_MASK             0x14 /* interrupt enable/disable mask */
+#define PORT_CMD                  0x18 /* port command */
+#define PORT_TFDATA               0x20 /* taskfile data */
+#define PORT_SIG                  0x24 /* device TF signature */
+#define PORT_SCR_STAT             0x28 /* SATA phy register: SStatus */
+#define PORT_SCR_CTL              0x2c /* SATA phy register: SControl */
+#define PORT_SCR_ERR              0x30 /* SATA phy register: SError */
+#define PORT_SCR_ACT              0x34 /* SATA phy register: SActive */
+#define PORT_CMD_ISSUE            0x38 /* command issue */
+#define PORT_RESERVED             0x3c /* reserved */
+
+/* PORT_IRQ_{STAT,MASK} bits */
+#define PORT_IRQ_COLD_PRES        (1 << 31) /* cold presence detect */
+#define PORT_IRQ_TF_ERR           (1 << 30) /* task file error */
+#define PORT_IRQ_HBUS_ERR         (1 << 29) /* host bus fatal error */
+#define PORT_IRQ_HBUS_DATA_ERR    (1 << 28) /* host bus data error */
+#define PORT_IRQ_IF_ERR           (1 << 27) /* interface fatal error */
+#define PORT_IRQ_IF_NONFATAL      (1 << 26) /* interface non-fatal error */
+#define PORT_IRQ_OVERFLOW         (1 << 24) /* xfer exhausted available S/G */
+#define PORT_IRQ_BAD_PMP          (1 << 23) /* incorrect port multiplier */
+
+#define PORT_IRQ_PHYRDY           (1 << 22) /* PhyRdy changed */
+#define PORT_IRQ_DEV_ILCK         (1 << 7) /* device interlock */
+#define PORT_IRQ_CONNECT          (1 << 6) /* port connect change status */
+#define PORT_IRQ_SG_DONE          (1 << 5) /* descriptor processed */
+#define PORT_IRQ_UNK_FIS          (1 << 4) /* unknown FIS rx'd */
+#define PORT_IRQ_SDB_FIS          (1 << 3) /* Set Device Bits FIS rx'd */
+#define PORT_IRQ_DMAS_FIS         (1 << 2) /* DMA Setup FIS rx'd */
+#define PORT_IRQ_PIOS_FIS         (1 << 1) /* PIO Setup FIS rx'd */
+#define PORT_IRQ_D2H_REG_FIS      (1 << 0) /* D2H Register FIS rx'd */
+
+#define PORT_IRQ_FREEZE           (PORT_IRQ_HBUS_ERR | PORT_IRQ_IF_ERR |   \
+                                   PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY |    \
+                                   PORT_IRQ_UNK_FIS)
+#define PORT_IRQ_ERROR            (PORT_IRQ_FREEZE | PORT_IRQ_TF_ERR |     \
+                                   PORT_IRQ_HBUS_DATA_ERR)
+#define DEF_PORT_IRQ              (PORT_IRQ_ERROR | PORT_IRQ_SG_DONE |     \
+                                   PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS |  \
+                                   PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS)
+
+/* PORT_CMD bits */
+#define PORT_CMD_ATAPI            (1 << 24) /* Device is ATAPI */
+#define PORT_CMD_LIST_ON          (1 << 15) /* cmd list DMA engine running */
+#define PORT_CMD_FIS_ON           (1 << 14) /* FIS DMA engine running */
+#define PORT_CMD_FIS_RX           (1 << 4) /* Enable FIS receive DMA engine */
+#define PORT_CMD_CLO              (1 << 3) /* Command list override */
+#define PORT_CMD_POWER_ON         (1 << 2) /* Power up device */
+#define PORT_CMD_SPIN_UP          (1 << 1) /* Spin up device */
+#define PORT_CMD_START            (1 << 0) /* Enable port DMA engine */
+
+#define PORT_CMD_ICC_MASK         (0xf << 28) /* i/f ICC state mask */
+#define PORT_CMD_ICC_ACTIVE       (0x1 << 28) /* Put i/f in active state */
+#define PORT_CMD_ICC_PARTIAL      (0x2 << 28) /* Put i/f in partial state */
+#define PORT_CMD_ICC_SLUMBER      (0x6 << 28) /* Put i/f in slumber state */
+
+#define PORT_IRQ_STAT_DHRS        (1 << 0) /* Device to Host Register FIS */
+#define PORT_IRQ_STAT_PSS         (1 << 1) /* PIO Setup FIS */
+#define PORT_IRQ_STAT_DSS         (1 << 2) /* DMA Setup FIS */
+#define PORT_IRQ_STAT_SDBS        (1 << 3) /* Set Device Bits */
+#define PORT_IRQ_STAT_UFS         (1 << 4) /* Unknown FIS */
+#define PORT_IRQ_STAT_DPS         (1 << 5) /* Descriptor Processed */
+#define PORT_IRQ_STAT_PCS         (1 << 6) /* Port Connect Change Status */
+#define PORT_IRQ_STAT_DMPS        (1 << 7) /* Device Mechanical Presence
+                                              Status */
+#define PORT_IRQ_STAT_PRCS        (1 << 22) /* File Ready Status */
+#define PORT_IRQ_STAT_IPMS        (1 << 23) /* Incorrect Port Multiplier
+                                               Status */
+#define PORT_IRQ_STAT_OFS         (1 << 24) /* Overflow Status */
+#define PORT_IRQ_STAT_INFS        (1 << 26) /* Interface Non-Fatal Error
+                                               Status */
+#define PORT_IRQ_STAT_IFS         (1 << 27) /* Interface Fatal Error */
+#define PORT_IRQ_STAT_HBDS        (1 << 28) /* Host Bus Data Error Status */
+#define PORT_IRQ_STAT_HBFS        (1 << 29) /* Host Bus Fatal Error Status */
+#define PORT_IRQ_STAT_TFES        (1 << 30) /* Task File Error Status */
+#define PORT_IRQ_STAT_CPDS        (1 << 31) /* Code Port Detect Status */
+
+/* ap->flags bits */
+#define AHCI_FLAG_NO_NCQ                  (1 << 24)
+#define AHCI_FLAG_IGN_IRQ_IF_ERR          (1 << 25) /* ignore IRQ_IF_ERR */
+#define AHCI_FLAG_HONOR_PI                (1 << 26) /* honor PORTS_IMPL */
+#define AHCI_FLAG_IGN_SERR_INTERNAL       (1 << 27) /* ignore SERR_INTERNAL */
+#define AHCI_FLAG_32BIT_ONLY              (1 << 28) /* force 32bit */
+
+#define ATA_SRST                          (1 << 2)  /* software reset */
+
+#define STATE_RUN                         0
+#define STATE_RESET                       1
+
+#define SATA_SCR_SSTATUS_DET_NODEV        0x0
+#define SATA_SCR_SSTATUS_DET_DEV_PRESENT_PHY_UP 0x3
+
+#define SATA_SCR_SSTATUS_SPD_NODEV        0x00
+#define SATA_SCR_SSTATUS_SPD_GEN1         0x10
+
+#define SATA_SCR_SSTATUS_IPM_NODEV        0x000
+#define SATA_SCR_SSTATUS_IPM_ACTIVE       0X100
+
+#define AHCI_SCR_SCTL_DET                 0xf
+
+#define SATA_FIS_TYPE_REGISTER_H2D        0x27
+#define SATA_FIS_REG_H2D_UPDATE_COMMAND_REGISTER 0x80
+
+#define AHCI_CMD_HDR_CMD_FIS_LEN           0x1f
+#define AHCI_CMD_HDR_PRDT_LEN              16
+
+#define SATA_SIGNATURE_CDROM               0xeb140000
+#define SATA_SIGNATURE_DISK                0x00000101
+
+#define AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR 0x20
+                                            /* Shouldn't this be 0x2c? */
+
+#define SATA_PORTS                         4
+
+#define AHCI_PORT_REGS_START_ADDR          0x100
+#define AHCI_PORT_REGS_END_ADDR (AHCI_PORT_REGS_START_ADDR + SATA_PORTS * 0x80)
+#define AHCI_PORT_ADDR_OFFSET_MASK         0x7f
+
+#define AHCI_NUM_COMMAND_SLOTS             31
+#define AHCI_SUPPORTED_SPEED               20
+#define AHCI_SUPPORTED_SPEED_GEN1          1
+#define AHCI_VERSION_1_0                   0x10000
+
+#define AHCI_PROGMODE_MAJOR_REV_1          1
+
+#define AHCI_COMMAND_TABLE_ACMD            0x40
+
+#define IDE_FEATURE_DMA                    1
+
+#define READ_FPDMA_QUEUED                  0x60
+#define WRITE_FPDMA_QUEUED                 0x61
+
+#define RES_FIS_DSFIS                      0x00
+#define RES_FIS_PSFIS                      0x20
+#define RES_FIS_RFIS                       0x40
+#define RES_FIS_SDBFIS                     0x58
+#define RES_FIS_UFIS                       0x60
+
+typedef struct AHCIControlRegs {
+    uint32_t    cap;
+    uint32_t    ghc;
+    uint32_t    irqstatus;
+    uint32_t    impl;
+    uint32_t    version;
+} AHCIControlRegs;
+
+typedef struct AHCIPortRegs {
+    uint32_t    lst_addr;
+    uint32_t    lst_addr_hi;
+    uint32_t    fis_addr;
+    uint32_t    fis_addr_hi;
+    uint32_t    irq_stat;
+    uint32_t    irq_mask;
+    uint32_t    cmd;
+    uint32_t    unused0;
+    uint32_t    tfdata;
+    uint32_t    sig;
+    uint32_t    scr_stat;
+    uint32_t    scr_ctl;
+    uint32_t    scr_err;
+    uint32_t    scr_act;
+    uint32_t    cmd_issue;
+    uint32_t    reserved;
+} AHCIPortRegs;
+
+typedef struct AHCICmdHdr {
+    uint32_t    opts;
+    uint32_t    status;
+    uint64_t    tbl_addr;
+    uint32_t    reserved[4];
+} __attribute__ ((packed)) AHCICmdHdr;
+
+typedef struct AHCI_SG {
+    uint64_t    addr;
+    uint32_t    reserved;
+    uint32_t    flags_size;
+} __attribute__ ((packed)) AHCI_SG;
+
+typedef struct AHCIDevice AHCIDevice;
+
+typedef struct NCQTransferState {
+    AHCIDevice *drive;
+    BlockDriverAIOCB *aiocb;
+    QEMUSGList sglist;
+    int is_read;
+    uint16_t sector_count;
+    uint64_t lba;
+    uint8_t tag;
+    int slot;
+    int used;
+} NCQTransferState;
+
+struct AHCIDevice {
+    IDEDMA dma;
+    IDEBus port;
+    int port_no;
+    uint32_t port_state;
+    uint32_t finished;
+    AHCIPortRegs port_regs;
+    struct AHCIState *hba;
+    QEMUBH *check_bh;
+    uint8_t *lst;
+    uint8_t *res_fis;
+    int dma_status;
+    int done_atapi_packet;
+    int busy_slot;
+    BlockDriverCompletionFunc *dma_cb;
+    AHCICmdHdr *cur_cmd;
+    NCQTransferState ncq_tfs[AHCI_MAX_CMDS];
+};
+
+typedef struct AHCIState {
+    AHCIDevice dev[SATA_PORTS];
+    AHCIControlRegs control_regs;
+    int mem;
+    qemu_irq irq;
+} AHCIState;
+
+typedef struct AHCIPCIState {
+    PCIDevice card;
+    AHCIState ahci;
+} AHCIPCIState;
+
+typedef struct NCQFrame {
+    uint8_t fis_type;
+    uint8_t c;
+    uint8_t command;
+    uint8_t sector_count_low;
+    uint8_t lba0;
+    uint8_t lba1;
+    uint8_t lba2;
+    uint8_t fua;
+    uint8_t lba3;
+    uint8_t lba4;
+    uint8_t lba5;
+    uint8_t sector_count_high;
+    uint8_t tag;
+    uint8_t reserved5;
+    uint8_t reserved6;
+    uint8_t control;
+    uint8_t reserved7;
+    uint8_t reserved8;
+    uint8_t reserved9;
+    uint8_t reserved10;
+} __attribute__ ((packed)) NCQFrame;
+
+static void check_cmd(AHCIState *s, int port);
+static int handle_cmd(AHCIState *s,int port,int slot);
+static void ahci_reset_port(AHCIState *s, int port);
+static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis);
+
+static uint32_t  ahci_port_read(AHCIState *s, int port, int offset)
+{
+    uint32_t val;
+    AHCIPortRegs *pr;
+    pr = &s->dev[port].port_regs;
+
+    switch (offset) {
+    case PORT_LST_ADDR:
+        val = pr->lst_addr;
+        break;
+    case PORT_LST_ADDR_HI:
+        val = pr->lst_addr_hi;
+        break;
+    case PORT_FIS_ADDR:
+        val = pr->fis_addr;
+        break;
+    case PORT_FIS_ADDR_HI:
+        val = pr->fis_addr_hi;
+        break;
+    case PORT_IRQ_STAT:
+        val = pr->irq_stat;
+        break;
+    case PORT_IRQ_MASK:
+        val = pr->irq_mask;
+        break;
+    case PORT_CMD:
+        val = pr->cmd;
+        break;
+    case PORT_TFDATA:
+        val = ((uint16_t)s->dev[port].port.ifs[0].error << 8) |
+              s->dev[port].port.ifs[0].status;
+        break;
+    case PORT_SIG:
+        val = pr->sig;
+        break;
+    case PORT_SCR_STAT:
+        if (s->dev[port].port.ifs[0].bs) {
+            val = SATA_SCR_SSTATUS_DET_DEV_PRESENT_PHY_UP |
+                  SATA_SCR_SSTATUS_SPD_GEN1 | SATA_SCR_SSTATUS_IPM_ACTIVE;
+        } else {
+            val = SATA_SCR_SSTATUS_DET_NODEV;
+        }
+        break;
+    case PORT_SCR_CTL:
+        val = pr->scr_ctl;
+        break;
+    case PORT_SCR_ERR:
+        val = pr->scr_err;
+        break;
+    case PORT_SCR_ACT:
+        pr->scr_act &= ~s->dev[port].finished;
+        s->dev[port].finished = 0;
+        val = pr->scr_act;
+        break;
+    case PORT_CMD_ISSUE:
+        val = pr->cmd_issue;
+        break;
+    case PORT_RESERVED:
+    default:
+        val = 0;
+    }
+    DPRINTF(port, "offset: 0x%x val: 0x%x\n", offset, val);
+    return val;
+
+}
+
+static void ahci_irq_raise(AHCIState *s, AHCIDevice *dev)
+{
+    struct AHCIPCIState *d = container_of(s, AHCIPCIState, ahci);
+
+    DPRINTF(0, "raise irq\n");
+
+    if (msi_enabled(&d->card)) {
+        msi_notify(&d->card, 0);
+    } else {
+        qemu_irq_raise(s->irq);
+    }
+}
+
+static void ahci_irq_lower(AHCIState *s, AHCIDevice *dev)
+{
+    struct AHCIPCIState *d = container_of(s, AHCIPCIState, ahci);
+
+    DPRINTF(0, "lower irq\n");
+
+    if (!msi_enabled(&d->card)) {
+        qemu_irq_lower(s->irq);
+    }
+}
+
+static void ahci_check_irq(AHCIState *s)
+{
+    int i;
+
+    DPRINTF(-1, "check irq %#x\n", s->control_regs.irqstatus);
+
+    for (i = 0; i < SATA_PORTS; i++) {
+        AHCIPortRegs *pr = &s->dev[i].port_regs;
+        if (pr->irq_stat & pr->irq_mask) {
+            s->control_regs.irqstatus |= (1 << i);
+        }
+    }
+
+    if (s->control_regs.irqstatus &&
+        (s->control_regs.ghc & HOST_CTL_IRQ_EN)) {
+            ahci_irq_raise(s, NULL);
+    } else {
+        ahci_irq_lower(s, NULL);
+    }
+}
+
+static void ahci_trigger_irq(AHCIState *s, AHCIDevice *d,
+                             int irq_type)
+{
+    DPRINTF(d->port_no, "trigger irq %#x -> %x\n",
+            irq_type, d->port_regs.irq_mask & irq_type);
+
+    d->port_regs.irq_stat |= irq_type;
+    ahci_check_irq(s);
+}
+
+static void map_page(uint8_t **ptr, uint64_t addr, uint32_t wanted)
+{
+    target_phys_addr_t len = wanted;
+
+    if (*ptr) {
+        cpu_physical_memory_unmap(*ptr, 1, len, len);
+    }
+
+    *ptr = cpu_physical_memory_map(addr, &len, 1);
+    if (len < wanted) {
+        cpu_physical_memory_unmap(*ptr, 1, len, len);
+        *ptr = NULL;
+    }
+}
+
+static void  ahci_port_write(AHCIState *s, int port, int offset, uint32_t val)
+{
+    AHCIPortRegs *pr = &s->dev[port].port_regs;
+
+    DPRINTF(port, "offset: 0x%x val: 0x%x\n", offset, val);
+    switch (offset) {
+        case PORT_LST_ADDR:
+            pr->lst_addr = val;
+            map_page(&s->dev[port].lst,
+                     ((uint64_t)pr->lst_addr_hi << 32) | pr->lst_addr, 1024);
+            s->dev[port].cur_cmd = NULL;
+            break;
+        case PORT_LST_ADDR_HI:
+            pr->lst_addr_hi = val;
+            map_page(&s->dev[port].lst,
+                     ((uint64_t)pr->lst_addr_hi << 32) | pr->lst_addr, 1024);
+            s->dev[port].cur_cmd = NULL;
+            break;
+        case PORT_FIS_ADDR:
+            pr->fis_addr = val;
+            map_page(&s->dev[port].res_fis,
+                     ((uint64_t)pr->fis_addr_hi << 32) | pr->fis_addr, 256);
+            break;
+        case PORT_FIS_ADDR_HI:
+            pr->fis_addr_hi = val;
+            map_page(&s->dev[port].res_fis,
+                     ((uint64_t)pr->fis_addr_hi << 32) | pr->fis_addr, 256);
+            break;
+        case PORT_IRQ_STAT:
+            pr->irq_stat &= ~val;
+            break;
+        case PORT_IRQ_MASK:
+            pr->irq_mask = val & 0xfdc000ff;
+            ahci_check_irq(s);
+            break;
+        case PORT_CMD:
+            pr->cmd = val & ~(PORT_CMD_LIST_ON | PORT_CMD_FIS_ON);
+
+            if (pr->cmd & PORT_CMD_START) {
+                pr->cmd |= PORT_CMD_LIST_ON;
+            }
+
+            if (pr->cmd & PORT_CMD_FIS_RX) {
+                pr->cmd |= PORT_CMD_FIS_ON;
+            }
+
+            check_cmd(s, port);
+            break;
+        case PORT_TFDATA:
+            s->dev[port].port.ifs[0].error = (val >> 8) & 0xff;
+            s->dev[port].port.ifs[0].status = val & 0xff;
+            break;
+        case PORT_SIG:
+            pr->sig = val;
+            break;
+        case PORT_SCR_STAT:
+            pr->scr_stat = val;
+            break;
+        case PORT_SCR_CTL:
+            if (((pr->scr_ctl & AHCI_SCR_SCTL_DET) == 1) &&
+                ((val & AHCI_SCR_SCTL_DET) == 0)) {
+                ahci_reset_port(s, port);
+            }
+            pr->scr_ctl = val;
+            break;
+        case PORT_SCR_ERR:
+            pr->scr_err &= ~val;
+            break;
+        case PORT_SCR_ACT:
+            /* RW1 */
+            pr->scr_act |= val;
+            break;
+        case PORT_CMD_ISSUE:
+            pr->cmd_issue |= val;
+            check_cmd(s, port);
+            break;
+        default:
+            break;
+    }
+}
+
+static uint32_t ahci_mem_readl(void *ptr, target_phys_addr_t addr)
+{
+    AHCIState *s = ptr;
+    uint32_t val = 0;
+
+    addr = addr & 0xfff;
+    if (addr < AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR) {
+        switch (addr) {
+        case HOST_CAP:
+            val = s->control_regs.cap;
+            break;
+        case HOST_CTL:
+            val = s->control_regs.ghc;
+            break;
+        case HOST_IRQ_STAT:
+            val = s->control_regs.irqstatus;
+            break;
+        case HOST_PORTS_IMPL:
+            val = s->control_regs.impl;
+            break;
+        case HOST_VERSION:
+            val = s->control_regs.version;
+            break;
+        }
+
+        DPRINTF(-1, "(addr 0x%08X), val 0x%08X\n", (unsigned) addr, val);
+    } else if ((addr >= AHCI_PORT_REGS_START_ADDR) &&
+               (addr < AHCI_PORT_REGS_END_ADDR)) {
+        val = ahci_port_read(s, (addr - AHCI_PORT_REGS_START_ADDR) >> 7,
+                             addr & AHCI_PORT_ADDR_OFFSET_MASK);
+    }
+
+    return val;
+}
+
+
+
+static void ahci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
+{
+    AHCIState *s = ptr;
+    addr = addr & 0xfff;
+
+    /* Only aligned reads are allowed on AHCI */
+    if (addr & 3) {
+        fprintf(stderr, "ahci: Mis-aligned write to addr 0x"
+                TARGET_FMT_plx "\n", addr);
+        return;
+    }
+
+    if (addr < AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR) {
+        DPRINTF(-1, "(addr 0x%08X), val 0x%08X\n", (unsigned) addr, val);
+
+        switch (addr) {
+            case HOST_CAP: /* R/WO, RO */
+                /* FIXME handle R/WO */
+                break;
+            case HOST_CTL: /* R/W */
+                if (val & HOST_CTL_RESET) {
+                    DPRINTF(-1, "HBA Reset\n");
+                    /* FIXME reset? */
+                } else {
+                    s->control_regs.ghc = (val & 0x3) | HOST_CTL_AHCI_EN;
+                    ahci_check_irq(s);
+                }
+                break;
+            case HOST_IRQ_STAT: /* R/WC, RO */
+                s->control_regs.irqstatus &= ~val;
+                ahci_check_irq(s);
+                break;
+            case HOST_PORTS_IMPL: /* R/WO, RO */
+                /* FIXME handle R/WO */
+                break;
+            case HOST_VERSION: /* RO */
+                /* FIXME report write? */
+                break;
+            default:
+                DPRINTF(-1, "write to unknown register 0x%x\n", (unsigned)addr);
+        }
+    } else if ((addr >= AHCI_PORT_REGS_START_ADDR) &&
+               (addr < AHCI_PORT_REGS_END_ADDR)) {
+        ahci_port_write(s, (addr - AHCI_PORT_REGS_START_ADDR) >> 7,
+                        addr & AHCI_PORT_ADDR_OFFSET_MASK, 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 void ahci_reg_init(AHCIState *s)
+{
+    int i;
+
+    s->control_regs.cap = (SATA_PORTS - 1) |
+                          (AHCI_NUM_COMMAND_SLOTS << 8) |
+                          (AHCI_SUPPORTED_SPEED_GEN1 << AHCI_SUPPORTED_SPEED) |
+                          HOST_CAP_NCQ | HOST_CAP_AHCI;
+
+    s->control_regs.impl = (1 << SATA_PORTS) - 1;
+
+    s->control_regs.version = AHCI_VERSION_1_0;
+
+    for (i = 0; i < SATA_PORTS; i++) {
+        s->dev[i].port_state = STATE_RUN;
+    }
+}
+
+static uint32_t read_from_sglist(uint8_t *buffer, uint32_t len,
+                                 QEMUSGList *sglist)
+{
+    uint32_t i = 0;
+    uint32_t total = 0, once;
+    ScatterGatherEntry *cur_prd;
+    uint32_t sgcount;
+
+    cur_prd = sglist->sg;
+    sgcount = sglist->nsg;
+    for (i = 0; len && sgcount; i++) {
+        once = MIN(cur_prd->len, len);
+        cpu_physical_memory_read(cur_prd->base, buffer, once);
+        cur_prd++;
+        sgcount--;
+        len -= once;
+        buffer += once;
+        total += once;
+    }
+
+    return total;
+}
+
+static uint32_t write_to_sglist(uint8_t *buffer, uint32_t len,
+                                QEMUSGList *sglist)
+{
+    uint32_t i = 0;
+    uint32_t total = 0, once;
+    ScatterGatherEntry *cur_prd;
+    uint32_t sgcount;
+
+    DPRINTF(-1, "total: 0x%x bytes\n", len);
+
+    cur_prd = sglist->sg;
+    sgcount = sglist->nsg;
+    for (i = 0; len && sgcount; i++) {
+        once = MIN(cur_prd->len, len);
+        DPRINTF(-1, "write 0x%x bytes to 0x%lx\n", once, (long)cur_prd->base);
+        cpu_physical_memory_write(cur_prd->base, buffer, once);
+        cur_prd++;
+        sgcount--;
+        len -= once;
+        buffer += once;
+        total += once;
+    }
+
+    return total;
+}
+
+static void check_cmd(AHCIState *s, int port)
+{
+    AHCIPortRegs *pr = &s->dev[port].port_regs;
+    int slot;
+
+    if ((pr->cmd & PORT_CMD_START) && pr->cmd_issue) {
+        for (slot = 0; (slot < 32) && pr->cmd_issue; slot++) {
+            if ((pr->cmd_issue & (1 << slot)) &&
+                !handle_cmd(s, port, slot)) {
+                pr->cmd_issue &= ~(1 << slot);
+            }
+        }
+    }
+}
+
+static void ahci_check_cmd_bh(void *opaque)
+{
+    AHCIDevice *ad = opaque;
+
+    qemu_bh_delete(ad->check_bh);
+    ad->check_bh = NULL;
+
+    if ((ad->busy_slot != -1) &&
+        !(ad->port.ifs[0].status & (BUSY_STAT|DRQ_STAT))) {
+        /* no longer busy */
+        ad->port_regs.cmd_issue &= ~(1 << ad->busy_slot);
+        ad->busy_slot = -1;
+    }
+
+    check_cmd(ad->hba, ad->port_no);
+}
+
+static void ahci_reset_port(AHCIState *s, int port)
+{
+    AHCIDevice *d = &s->dev[port];
+    AHCIPortRegs *pr = &d->port_regs;
+    IDEState *ide_state = &d->port.ifs[0];
+    uint8_t init_fis[0x20];
+    uint32_t tfd;
+    int i;
+
+    DPRINTF(port, "reset port\n");
+
+    ide_bus_reset(&d->port);
+    ide_state->ncq_queues = AHCI_MAX_CMDS;
+
+    pr->irq_stat = 0;
+    pr->irq_mask = 0;
+    pr->scr_stat = 0;
+    pr->scr_ctl = 0;
+    pr->scr_err = 0;
+    pr->scr_act = 0;
+    d->busy_slot = -1;
+
+    ide_state = &s->dev[port].port.ifs[0];
+    if (!ide_state->bs) {
+        return;
+    }
+
+    /* reset ncq queue */
+    for (i = 0; i < AHCI_MAX_CMDS; i++) {
+        NCQTransferState *ncq_tfs = &s->dev[port].ncq_tfs[i];
+        if (!ncq_tfs->used) {
+            continue;
+        }
+
+        if (ncq_tfs->aiocb) {
+            bdrv_aio_cancel(ncq_tfs->aiocb);
+            ncq_tfs->aiocb = NULL;
+        }
+
+        qemu_sglist_destroy(&ncq_tfs->sglist);
+        ncq_tfs->used = 0;
+    }
+
+    memset(init_fis, 0, sizeof(init_fis));
+    s->dev[port].port_state = STATE_RUN;
+    if (!ide_state->bs) {
+        s->dev[port].port_regs.sig = 0;
+        tfd = (1 << 8) | SEEK_STAT | WRERR_STAT;
+    } else if (ide_state->drive_kind == IDE_CD) {
+        s->dev[port].port_regs.sig = SATA_SIGNATURE_CDROM;
+        ide_state->lcyl = 0x14;
+        ide_state->hcyl = 0xeb;
+        DPRINTF(port, "set lcyl = %d\n", ide_state->lcyl);
+        init_fis[5] = ide_state->lcyl;
+        init_fis[6] = ide_state->hcyl;
+        ide_state->status = SEEK_STAT | WRERR_STAT | READY_STAT;
+    } else {
+        s->dev[port].port_regs.sig = SATA_SIGNATURE_DISK;
+        ide_state->status = SEEK_STAT | WRERR_STAT;
+    }
+
+    ide_state->error = 1;
+    init_fis[4] = 1;
+    init_fis[12] = 1;
+    ahci_write_fis_d2h(d, init_fis);
+}
+
+static void debug_print_fis(uint8_t *fis, int cmd_len)
+{
+#ifdef DEBUG_AHCI
+    int i;
+
+    fprintf(stderr, "fis:");
+    for (i = 0; i < cmd_len; i++) {
+        if ((i & 0xf) == 0) {
+            fprintf(stderr, "\n%02x:",i);
+        }
+        fprintf(stderr, "%02x ",fis[i]);
+    }
+    fprintf(stderr, "\n");
+#endif
+}
+
+static void ahci_write_fis_sdb(AHCIState *s, int port, uint32_t finished)
+{
+    AHCIPortRegs *pr = &s->dev[port].port_regs;
+    IDEState *ide_state;
+    uint8_t *sdb_fis;
+
+    if (!s->dev[port].res_fis ||
+        !(pr->cmd & PORT_CMD_FIS_RX)) {
+        return;
+    }
+
+    sdb_fis = &s->dev[port].res_fis[RES_FIS_SDBFIS];
+    ide_state = &s->dev[port].port.ifs[0];
+
+    /* clear memory */
+    *(uint32_t*)sdb_fis = 0;
+
+    /* write values */
+    sdb_fis[0] = ide_state->error;
+    sdb_fis[2] = ide_state->status & 0x77;
+    s->dev[port].finished |= finished;
+    *(uint32_t*)(sdb_fis + 4) = cpu_to_le32(s->dev[port].finished);
+
+    ahci_trigger_irq(s, &s->dev[port], PORT_IRQ_STAT_SDBS);
+}
+
+static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis)
+{
+    AHCIPortRegs *pr = &ad->port_regs;
+    uint8_t *d2h_fis;
+    int i;
+    target_phys_addr_t cmd_len = 0x80;
+    int cmd_mapped = 0;
+
+    if (!ad->res_fis || !(pr->cmd & PORT_CMD_FIS_RX)) {
+        return;
+    }
+
+    if (!cmd_fis) {
+        /* map cmd_fis */
+        uint64_t tbl_addr = le64_to_cpu(ad->cur_cmd->tbl_addr);
+        cmd_fis = cpu_physical_memory_map(tbl_addr, &cmd_len, 0);
+        cmd_mapped = 1;
+    }
+
+    d2h_fis = &ad->res_fis[RES_FIS_RFIS];
+
+    d2h_fis[0] = 0x34;
+    d2h_fis[1] = (ad->hba->control_regs.irqstatus ? (1 << 6) : 0);
+    d2h_fis[2] = ad->port.ifs[0].status;
+    d2h_fis[3] = ad->port.ifs[0].error;
+
+    d2h_fis[4] = cmd_fis[4];
+    d2h_fis[5] = cmd_fis[5];
+    d2h_fis[6] = cmd_fis[6];
+    d2h_fis[7] = cmd_fis[7];
+    d2h_fis[8] = cmd_fis[8];
+    d2h_fis[9] = cmd_fis[9];
+    d2h_fis[10] = cmd_fis[10];
+    d2h_fis[11] = cmd_fis[11];
+    d2h_fis[12] = cmd_fis[12];
+    d2h_fis[13] = cmd_fis[13];
+    for (i = 14; i < 0x20; i++) {
+        d2h_fis[i] = 0;
+    }
+
+    if (d2h_fis[2] & ERR_STAT) {
+        ahci_trigger_irq(ad->hba, ad, PORT_IRQ_STAT_TFES);
+    }
+
+    ahci_trigger_irq(ad->hba, ad, PORT_IRQ_D2H_REG_FIS);
+
+    if (cmd_mapped) {
+        cpu_physical_memory_unmap(cmd_fis, 0, cmd_len, cmd_len);
+    }
+}
+
+static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist)
+{
+    AHCICmdHdr *cmd = ad->cur_cmd;
+    uint32_t opts = le32_to_cpu(cmd->opts);
+    uint64_t prdt_addr = le64_to_cpu(cmd->tbl_addr) + 0x80;
+    int sglist_alloc_hint = opts >> AHCI_CMD_HDR_PRDT_LEN;
+    target_phys_addr_t prdt_len = (sglist_alloc_hint * sizeof(AHCI_SG));
+    target_phys_addr_t real_prdt_len = prdt_len;
+    uint8_t *prdt;
+    int i;
+    int r = 0;
+
+    if (!sglist_alloc_hint) {
+        DPRINTF(ad->port_no, "no sg list given by guest: 0x%08x\n", opts);
+        return -1;
+    }
+
+    /* map PRDT */
+    if (!(prdt = cpu_physical_memory_map(prdt_addr, &prdt_len, 0))){
+        DPRINTF(ad->port_no, "map failed\n");
+        return -1;
+    }
+
+    if (prdt_len < real_prdt_len) {
+        DPRINTF(ad->port_no, "mapped less than expected\n");
+        r = -1;
+        goto out;
+    }
+
+    /* Get entries in the PRDT, init a qemu sglist accordingly */
+    if (sglist_alloc_hint > 0) {
+        AHCI_SG *tbl = (AHCI_SG *)prdt;
+
+        qemu_sglist_init(sglist, sglist_alloc_hint);
+        for (i = 0; i < sglist_alloc_hint; i++) {
+            /* flags_size is zero-based */
+            qemu_sglist_add(sglist, le64_to_cpu(tbl[i].addr),
+                            le32_to_cpu(tbl[i].flags_size) + 1);
+        }
+    }
+
+out:
+    cpu_physical_memory_unmap(prdt, 0, prdt_len, prdt_len);
+    return r;
+}
+
+static void ncq_cb(void *opaque, int ret)
+{
+    NCQTransferState *ncq_tfs = (NCQTransferState *)opaque;
+    IDEState *ide_state = &ncq_tfs->drive->port.ifs[0];
+
+    /* Clear bit for this tag in SActive */
+    ncq_tfs->drive->port_regs.scr_act &= ~(1 << ncq_tfs->tag);
+
+    if (ret < 0) {
+        /* error */
+        ide_state->error = ABRT_ERR;
+        ide_state->status = READY_STAT | ERR_STAT;
+        ncq_tfs->drive->port_regs.scr_err |= (1 << ncq_tfs->tag);
+    } else {
+        ide_state->status = READY_STAT | SEEK_STAT;
+    }
+
+    ahci_write_fis_sdb(ncq_tfs->drive->hba, ncq_tfs->drive->port_no,
+                       (1 << ncq_tfs->tag));
+
+    DPRINTF(ncq_tfs->drive->port_no, "NCQ transfer tag %d finished\n",
+            ncq_tfs->tag);
+
+    qemu_sglist_destroy(&ncq_tfs->sglist);
+    ncq_tfs->used = 0;
+}
+
+static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis,
+                                int slot)
+{
+    NCQFrame *ncq_fis = (NCQFrame*)cmd_fis;
+    uint8_t tag = ncq_fis->tag >> 3;
+    NCQTransferState *ncq_tfs = &s->dev[port].ncq_tfs[tag];
+
+    if (ncq_tfs->used) {
+        /* error - already in use */
+        fprintf(stderr, "%s: tag %d already used\n", __FUNCTION__, tag);
+        return;
+    }
+
+    ncq_tfs->used = 1;
+    ncq_tfs->drive = &s->dev[port];
+    ncq_tfs->slot = slot;
+    ncq_tfs->lba = ((uint64_t)ncq_fis->lba5 << 40) |
+                   ((uint64_t)ncq_fis->lba4 << 32) |
+                   ((uint64_t)ncq_fis->lba3 << 24) |
+                   ((uint64_t)ncq_fis->lba2 << 16) |
+                   ((uint64_t)ncq_fis->lba1 << 8) |
+                   (uint64_t)ncq_fis->lba0;
+
+    /* Note: We calculate the sector count, but don't currently rely on it.
+     * The total size of the DMA buffer tells us the transfer size instead. */
+    ncq_tfs->sector_count = ((uint16_t)ncq_fis->sector_count_high << 8) |
+                                ncq_fis->sector_count_low;
+
+    DPRINTF(port, "NCQ transfer LBA from %ld to %ld, drive max %ld\n",
+            ncq_tfs->lba, ncq_tfs->lba + ncq_tfs->sector_count - 2,
+            s->dev[port].port.ifs[0].nb_sectors - 1);
+
+    ahci_populate_sglist(&s->dev[port], &ncq_tfs->sglist);
+    ncq_tfs->tag = tag;
+
+    switch(ncq_fis->command) {
+        case READ_FPDMA_QUEUED:
+            DPRINTF(port, "NCQ reading %d sectors from LBA %ld, tag %d\n",
+                    ncq_tfs->sector_count-1, ncq_tfs->lba, ncq_tfs->tag);
+            ncq_tfs->is_read = 1;
+
+            DPRINTF(port, "tag %d aio read %ld\n", ncq_tfs->tag, ncq_tfs->lba);
+            ncq_tfs->aiocb = dma_bdrv_read(ncq_tfs->drive->port.ifs[0].bs,
+                                           &ncq_tfs->sglist, ncq_tfs->lba,
+                                           ncq_cb, ncq_tfs);
+            break;
+        case WRITE_FPDMA_QUEUED:
+            DPRINTF(port, "NCQ writing %d sectors to LBA %ld, tag %d\n",
+                    ncq_tfs->sector_count-1, ncq_tfs->lba, ncq_tfs->tag);
+            ncq_tfs->is_read = 0;
+
+            DPRINTF(port, "tag %d aio write %ld\n", ncq_tfs->tag, ncq_tfs->lba);
+            ncq_tfs->aiocb = dma_bdrv_write(ncq_tfs->drive->port.ifs[0].bs,
+                                            &ncq_tfs->sglist, ncq_tfs->lba,
+                                            ncq_cb, ncq_tfs);
+            break;
+        default:
+            DPRINTF(port, "error: tried to process non-NCQ command as NCQ\n");
+            qemu_sglist_destroy(&ncq_tfs->sglist);
+            break;
+    }
+}
+
+static int handle_cmd(AHCIState *s, int port, int slot)
+{
+    IDEState *ide_state;
+    AHCIPortRegs *pr;
+    uint32_t opts;
+    uint64_t tbl_addr;
+    AHCICmdHdr *cmd;
+    uint8_t *cmd_fis;
+    target_phys_addr_t cmd_len;
+
+    if (s->dev[port].port.ifs[0].status & (BUSY_STAT|DRQ_STAT)) {
+        /* Engine currently busy, try again later */
+        DPRINTF(port, "engine busy\n");
+        return -1;
+    }
+
+    pr = &s->dev[port].port_regs;
+    cmd = &((AHCICmdHdr *)s->dev[port].lst)[slot];
+
+    if (!s->dev[port].lst) {
+        DPRINTF(port, "error: lst not given but cmd handled");
+        return -1;
+    }
+
+    /* remember current slot handle for later */
+    s->dev[port].cur_cmd = cmd;
+
+    opts = le32_to_cpu(cmd->opts);
+    tbl_addr = le64_to_cpu(cmd->tbl_addr);
+
+    cmd_len = 0x80;
+    cmd_fis = cpu_physical_memory_map(tbl_addr, &cmd_len, 1);
+
+    if (!cmd_fis) {
+        DPRINTF(port, "error: guest passed us an invalid cmd fis\n");
+        return -1;
+    }
+
+    /* The device we are working for */
+    ide_state = &s->dev[port].port.ifs[0];
+
+    if (!ide_state->bs) {
+        DPRINTF(port, "error: guest accessed unused port");
+        goto out;
+    }
+
+    debug_print_fis(cmd_fis, 0x90);
+    //debug_print_fis(cmd_fis, (opts & AHCI_CMD_HDR_CMD_FIS_LEN) * 4);
+
+    switch (cmd_fis[0]) {
+        case SATA_FIS_TYPE_REGISTER_H2D:
+            break;
+        default:
+            DPRINTF(port, "unknown command cmd_fis[0]=%02x cmd_fis[1]=%02x "
+                          "cmd_fis[2]=%02x\n", cmd_fis[0], cmd_fis[1],
+                          cmd_fis[2]);
+            goto out;
+            break;
+    }
+
+    switch (cmd_fis[1]) {
+        case SATA_FIS_REG_H2D_UPDATE_COMMAND_REGISTER:
+            break;
+        case 0:
+            break;
+        default:
+            DPRINTF(port, "unknown command cmd_fis[0]=%02x cmd_fis[1]=%02x "
+                          "cmd_fis[2]=%02x\n", cmd_fis[0], cmd_fis[1],
+                          cmd_fis[2]);
+            goto out;
+            break;
+    }
+
+    switch (s->dev[port].port_state) {
+        case STATE_RUN:
+            if (cmd_fis[15] & ATA_SRST) {
+                s->dev[port].port_state = STATE_RESET;
+            }
+            break;
+        case STATE_RESET:
+            if (!(cmd_fis[15] & ATA_SRST)) {
+                ahci_reset_port(s, port);
+            }
+            break;
+    }
+
+    if (cmd_fis[1] == SATA_FIS_REG_H2D_UPDATE_COMMAND_REGISTER) {
+
+        /* Check for NCQ command */
+        if ((cmd_fis[2] == READ_FPDMA_QUEUED) ||
+            (cmd_fis[2] == WRITE_FPDMA_QUEUED)) {
+            process_ncq_command(s, port, cmd_fis, slot);
+            goto out;
+        }
+
+        /* Decompose the FIS  */
+        ide_state->nsector = (int64_t)((cmd_fis[13] << 8) | cmd_fis[12]);
+        ide_state->feature = cmd_fis[3];
+        if (!ide_state->nsector) {
+            ide_state->nsector = 256;
+        }
+
+        if (ide_state->drive_kind != IDE_CD) {
+            ide_set_sector(ide_state, (cmd_fis[6] << 16) | (cmd_fis[5] << 8) |
+                           cmd_fis[4]);
+        }
+
+        /* Copy the ACMD field (ATAPI packet, if any) from the AHCI command
+         * table to ide_state->io_buffer
+         */
+        if (opts & AHCI_CMD_ATAPI) {
+            memcpy(ide_state->io_buffer, &cmd_fis[AHCI_COMMAND_TABLE_ACMD], 0x10);
+            ide_state->lcyl = 0x14;
+            ide_state->hcyl = 0xeb;
+            debug_print_fis(ide_state->io_buffer, 0x10);
+            ide_state->feature = IDE_FEATURE_DMA;
+            s->dev[port].done_atapi_packet = 0;
+            /* XXX send PIO setup FIS */
+        }
+
+        ide_state->error = 0;
+
+        /* Reset transferred byte counter */
+        cmd->status = 0;
+
+        /* We're ready to process the command in FIS byte 2. */
+        ide_exec_cmd(&s->dev[port].port, cmd_fis[2]);
+
+        if (s->dev[port].port.ifs[0].status & READY_STAT) {
+            ahci_write_fis_d2h(&s->dev[port], cmd_fis);
+        }
+    }
+
+out:
+    cpu_physical_memory_unmap(cmd_fis, 1, cmd_len, cmd_len);
+
+    if (s->dev[port].port.ifs[0].status & (BUSY_STAT|DRQ_STAT)) {
+        /* async command, complete later */
+        s->dev[port].busy_slot = slot;
+        return -1;
+    }
+
+    /* done handling the command */
+    return 0;
+}
+
+/* DMA dev <-> ram */
+static int ahci_start_transfer(IDEDMA *dma)
+{
+    AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
+    IDEState *s = &ad->port.ifs[0];
+    uint32_t size = (uint32_t)(s->data_end - s->data_ptr);
+    /* write == ram -> device */
+    uint32_t opts = le32_to_cpu(ad->cur_cmd->opts);
+    int is_write = opts & AHCI_CMD_WRITE;
+    int is_atapi = opts & AHCI_CMD_ATAPI;
+    int has_sglist = 0;
+
+    if (is_atapi && !ad->done_atapi_packet) {
+        /* already prepopulated iobuffer */
+        ad->done_atapi_packet = 1;
+        goto out;
+    }
+
+    if (!ahci_populate_sglist(ad, &s->sg)) {
+        has_sglist = 1;
+    }
+
+    DPRINTF(ad->port_no, "%sing %d bytes on %s w/%s sglist\n",
+            is_write ? "writ" : "read", size, is_atapi ? "atapi" : "ata",
+            has_sglist ? "" : "o");
+
+    if (is_write && has_sglist && (s->data_ptr < s->data_end)) {
+        read_from_sglist(s->data_ptr, size, &s->sg);
+    }
+
+    if (!is_write && has_sglist && (s->data_ptr < s->data_end)) {
+        write_to_sglist(s->data_ptr, size, &s->sg);
+    }
+
+    /* update number of transferred bytes */
+    ad->cur_cmd->status = cpu_to_le32(le32_to_cpu(ad->cur_cmd->status) + size);
+
+out:
+    /* declare that we processed everything */
+    s->data_ptr = s->data_end;
+
+    if (has_sglist) {
+        qemu_sglist_destroy(&s->sg);
+    }
+
+    s->end_transfer_func(s);
+
+    if (!(s->status & DRQ_STAT)) {
+        /* done with DMA */
+        ahci_trigger_irq(ad->hba, ad, PORT_IRQ_STAT_DSS);
+    }
+
+    return 0;
+}
+
+static void ahci_start_dma(IDEDMA *dma, IDEState *s,
+                           BlockDriverCompletionFunc *dma_cb)
+{
+    AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
+
+    DPRINTF(ad->port_no, "\n");
+    ad->dma_cb = dma_cb;
+    ad->dma_status |= BM_STATUS_DMAING;
+    dma_cb(s, 0);
+}
+
+static int ahci_dma_prepare_buf(IDEDMA *dma, int is_write)
+{
+    AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
+    IDEState *s = &ad->port.ifs[0];
+    int i;
+
+    ahci_populate_sglist(ad, &s->sg);
+
+    s->io_buffer_size = 0;
+    for (i = 0; i < s->sg.nsg; i++) {
+        s->io_buffer_size += s->sg.sg[i].len;
+    }
+
+    DPRINTF(ad->port_no, "len=%#x\n", s->io_buffer_size);
+    return s->io_buffer_size != 0;
+}
+
+static int ahci_dma_rw_buf(IDEDMA *dma, int is_write)
+{
+    AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
+    IDEState *s = &ad->port.ifs[0];
+    uint8_t *p = s->io_buffer + s->io_buffer_index;
+    int l = s->io_buffer_size - s->io_buffer_index;
+
+    if (ahci_populate_sglist(ad, &s->sg)) {
+        return 0;
+    }
+
+    if (is_write) {
+        write_to_sglist(p, l, &s->sg);
+    } else {
+        read_from_sglist(p, l, &s->sg);
+    }
+
+    /* update number of transferred bytes */
+    ad->cur_cmd->status = cpu_to_le32(le32_to_cpu(ad->cur_cmd->status) + l);
+    s->io_buffer_index += l;
+
+    DPRINTF(ad->port_no, "len=%#x\n", l);
+
+    return 1;
+}
+
+static int ahci_dma_set_unit(IDEDMA *dma, int unit)
+{
+    /* only a single unit per link */
+    return 0;
+}
+
+static int ahci_dma_add_status(IDEDMA *dma, int status)
+{
+    AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
+    ad->dma_status |= status;
+    DPRINTF(ad->port_no, "set status: %x\n", status);
+
+    if (status & BM_STATUS_INT) {
+        ahci_trigger_irq(ad->hba, ad, PORT_IRQ_STAT_DSS);
+    }
+
+    return 0;
+}
+
+static int ahci_dma_set_inactive(IDEDMA *dma)
+{
+    AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
+
+    DPRINTF(ad->port_no, "dma done\n");
+
+    /* update d2h status */
+    ahci_write_fis_d2h(ad, NULL);
+
+    ad->dma_cb = NULL;
+
+    /* maybe we still have something to process, check later */
+    ad->check_bh = qemu_bh_new(ahci_check_cmd_bh, ad);
+    qemu_bh_schedule(ad->check_bh);
+
+    return 0;
+}
+
+static void ahci_irq_set(void *opaque, int n, int level)
+{
+}
+
+static void ahci_dma_restart_cb(void *opaque, int running, int reason)
+{
+}
+
+static int ahci_dma_reset(IDEDMA *dma)
+{
+    return 0;
+}
+
+static const IDEDMAOps ahci_dma_ops = {
+    .start_dma = ahci_start_dma,
+    .start_transfer = ahci_start_transfer,
+    .prepare_buf = ahci_dma_prepare_buf,
+    .rw_buf = ahci_dma_rw_buf,
+    .set_unit = ahci_dma_set_unit,
+    .add_status = ahci_dma_add_status,
+    .set_inactive = ahci_dma_set_inactive,
+    .restart_cb = ahci_dma_restart_cb,
+    .reset = ahci_dma_reset,
+};
+
+static void ahci_init(AHCIState *s, DeviceState *qdev)
+{
+    qemu_irq *irqs;
+    int i;
+
+    ahci_reg_init(s);
+    s->mem = cpu_register_io_memory(ahci_readfn, ahci_writefn, s,
+                                    DEVICE_LITTLE_ENDIAN);
+    irqs = qemu_allocate_irqs(ahci_irq_set, s, SATA_PORTS);
+
+    for (i = 0; i < SATA_PORTS; i++) {
+        AHCIDevice *ad = &s->dev[i];
+
+        ide_bus_new(&ad->port, qdev, i);
+        ide_init2(&ad->port, irqs[i]);
+
+        ad->hba = s;
+        ad->port_no = i;
+        ad->port.dma = &ad->dma;
+        ad->port.dma->ops = &ahci_dma_ops;
+        ad->port_regs.cmd = PORT_CMD_SPIN_UP | PORT_CMD_POWER_ON;
+    }
+}
+
+static void ahci_pci_map(PCIDevice *pci_dev, int region_num,
+        pcibus_t addr, pcibus_t size, int type)
+{
+    struct AHCIPCIState *d = (struct AHCIPCIState *)pci_dev;
+    AHCIState *s = &d->ahci;
+
+    cpu_register_physical_memory(addr, size, s->mem);
+}
+
+static void ahci_reset(void *opaque)
+{
+    struct AHCIPCIState *d = opaque;
+    int i;
+
+    for (i = 0; i < SATA_PORTS; i++) {
+        ahci_reset_port(&d->ahci, i);
+    }
+}
+
+static int pci_ahci_init(PCIDevice *dev)
+{
+    struct AHCIPCIState *d;
+    d = DO_UPCAST(struct AHCIPCIState, card, dev);
+
+    pci_config_set_vendor_id(d->card.config, PCI_VENDOR_ID_INTEL);
+    pci_config_set_device_id(d->card.config, PCI_DEVICE_ID_INTEL_82801IR);
+
+    pci_config_set_class(d->card.config, PCI_CLASS_STORAGE_SATA);
+    pci_config_set_revision(d->card.config, 0x02);
+    pci_config_set_prog_interface(d->card.config, AHCI_PROGMODE_MAJOR_REV_1);
+
+    d->card.config[PCI_CACHE_LINE_SIZE] = 0x08;  /* Cache line size */
+    d->card.config[PCI_LATENCY_TIMER]   = 0x00;  /* Latency timer */
+    pci_config_set_interrupt_pin(d->card.config, 1);
+
+    qemu_register_reset(ahci_reset, d);
+
+    /* XXX BAR size should be 1k, but that breaks, so bump it to 4k for now */
+    pci_register_bar(&d->card, 5, 0x1000, PCI_BASE_ADDRESS_SPACE_MEMORY,
+                     ahci_pci_map);
+
+    msi_init(dev, 0x50, 1, true, false);
+
+    ahci_init(&d->ahci, &dev->qdev);
+    d->ahci.irq = d->card.irq[0];
+
+    return 0;
+}
+
+static int pci_ahci_uninit(PCIDevice *dev)
+{
+    struct AHCIPCIState *d;
+    d = DO_UPCAST(struct AHCIPCIState, card, dev);
+
+    if (msi_enabled(dev)) {
+        msi_uninit(dev);
+    }
+
+    qemu_unregister_reset(ahci_reset, d);
+
+    return 0;
+}
+
+static void pci_ahci_write_config(PCIDevice *pci, uint32_t addr,
+                                  uint32_t val, int len)
+{
+    pci_default_write_config(pci, addr, val, len);
+    msi_write_config(pci, addr, val, len);
+}
+
+static PCIDeviceInfo ahci_info = {
+    .qdev.name  = "ahci",
+    .qdev.size  = sizeof(AHCIPCIState),
+    .init       = pci_ahci_init,
+    .exit       = pci_ahci_uninit,
+    .config_write = pci_ahci_write_config,
+};
+
+static void ahci_pci_register_devices(void)
+{
+    pci_qdev_register(&ahci_info);
+}
+
+device_init(ahci_pci_register_devices)
commit 1a5a86fb7a9d98d05fe38c78d49a6fe4b923d3d2
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Dec 14 01:34:39 2010 +0100

    pci: add ich9 pci id
    
    We need a PCI ID for our new AHCI adapter. I just picked an ICH-9
    because that's the one in the Q35 chipset.
    
    This patch adds a PCI ID define for an ICH-9 AHCI adapter.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/pci.h b/hw/pci.h
index aa3afe9..17744dc 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -62,6 +62,7 @@
 /* Intel (0x8086) */
 #define PCI_DEVICE_ID_INTEL_82551IT      0x1209
 #define PCI_DEVICE_ID_INTEL_82557        0x1229
+#define PCI_DEVICE_ID_INTEL_82801IR      0x2922
 
 /* Red Hat / Qumranet (for QEMU) -- see pci-ids.txt */
 #define PCI_VENDOR_ID_REDHAT_QUMRANET    0x1af4
commit 6ed6c24a2d4a23c11ac7397a9fb12d5c143333eb
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Dec 14 01:34:38 2010 +0100

    pci: add storage class for sata
    
    This patch adds the storage sata class id.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/pci_ids.h b/hw/pci_ids.h
index 82cba7e..ea3418c 100644
--- a/hw/pci_ids.h
+++ b/hw/pci_ids.h
@@ -15,6 +15,7 @@
 
 #define PCI_CLASS_STORAGE_SCSI           0x0100
 #define PCI_CLASS_STORAGE_IDE            0x0101
+#define PCI_CLASS_STORAGE_SATA           0x0106
 #define PCI_CLASS_STORAGE_OTHER          0x0180
 
 #define PCI_CLASS_NETWORK_ETHERNET       0x0200
commit ccf0fd8b056dec1fa610842dc3eb2f560ca65753
Author: Roland Elek <elek.roland at gmail.com>
Date:   Tue Dec 14 01:34:37 2010 +0100

    ide: add ncq identify data for ahci sata drives
    
    I modified ide_identify() to include the zero-based queue length
    value in word 75, and set bit 8 in word 76 to signal NCQ support
    in the identify data for AHCI SATA drives.
    
    Signed-off-by: Roland Elek <elek.roland at gmail.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/ide/core.c b/hw/ide/core.c
index 228911d..9e1d4e6 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -140,6 +140,13 @@ static void ide_identify(IDEState *s)
     put_le16(p + 66, 120);
     put_le16(p + 67, 120);
     put_le16(p + 68, 120);
+
+    if (s->ncq_queues) {
+        put_le16(p + 75, s->ncq_queues - 1);
+        /* NCQ supported */
+        put_le16(p + 76, (1 << 8));
+    }
+
     put_le16(p + 80, 0xf0); /* ata3 -> ata6 supported */
     put_le16(p + 81, 0x16); /* conforms to ata5 */
     /* 14=NOP supported, 5=WCACHE supported, 0=SMART supported */
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index aadb505..697c3b4 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -447,6 +447,8 @@ struct IDEState {
     int smart_errors;
     uint8_t smart_selftest_count;
     uint8_t *smart_selftest_data;
+    /* AHCI */
+    int ncq_queues;
 };
 
 struct IDEDMAOps {
commit 2ff61ff1955cb5268a2604aba8f6aa0c4c658505
Author: Alexander Graf <agraf at suse.de>
Date:   Wed Dec 15 00:23:01 2010 +0100

    ide: move transfer_start after variable modification
    
    We hook into transfer_start and immediately call the end function
    for ahci. This means that everything needs to be in place for the
    end function when we start the transfer, so let's move the function
    down to where all state is in place.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/ide/core.c b/hw/ide/core.c
index 2032e20..228911d 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -814,11 +814,11 @@ static void ide_atapi_cmd_reply_end(IDEState *s)
             size = s->cd_sector_size - s->io_buffer_index;
             if (size > s->elementary_transfer_size)
                 size = s->elementary_transfer_size;
-            ide_transfer_start(s, s->io_buffer + s->io_buffer_index,
-                               size, ide_atapi_cmd_reply_end);
             s->packet_transfer_size -= size;
             s->elementary_transfer_size -= size;
             s->io_buffer_index += size;
+            ide_transfer_start(s, s->io_buffer + s->io_buffer_index - size,
+                               size, ide_atapi_cmd_reply_end);
         } else {
             /* a new transfer is needed */
             s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO;
@@ -843,11 +843,11 @@ static void ide_atapi_cmd_reply_end(IDEState *s)
                 if (size > (s->cd_sector_size - s->io_buffer_index))
                     size = (s->cd_sector_size - s->io_buffer_index);
             }
-            ide_transfer_start(s, s->io_buffer + s->io_buffer_index,
-                               size, ide_atapi_cmd_reply_end);
             s->packet_transfer_size -= size;
             s->elementary_transfer_size -= size;
             s->io_buffer_index += size;
+            ide_transfer_start(s, s->io_buffer + s->io_buffer_index - size,
+                               size, ide_atapi_cmd_reply_end);
             ide_set_irq(s->bus);
 #ifdef DEBUG_IDE_ATAPI
             printf("status=0x%x\n", s->status);
commit 40a6238a20134a4687f67072d9be99cd97aab59a
Author: Alexander Graf <agraf at suse.de>
Date:   Wed Dec 15 00:23:00 2010 +0100

    ide: Split out BMDMA code from ATA core
    
    The ATA core is currently heavily intertwined with BMDMA code. Let's loosen
    that a bit, so we can happily replace the DMA backend with different
    implementations.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c
index ea5d2dc..e191ee6 100644
--- a/hw/ide/cmd646.c
+++ b/hw/ide/cmd646.c
@@ -167,9 +167,10 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num,
 
     for(i = 0;i < 2; i++) {
         BMDMAState *bm = &d->bmdma[i];
-        d->bus[i].bmdma = bm;
+        bmdma_init(&d->bus[i], bm);
         bm->bus = d->bus+i;
-        qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm);
+        qemu_add_vm_change_state_handler(d->bus[i].dma->ops->restart_cb,
+                                         &bm->dma);
 
         if (i == 0) {
             register_ioport_write(addr, 4, 1, bmdma_writeb_0, d);
@@ -218,7 +219,6 @@ static void cmd646_reset(void *opaque)
 
     for (i = 0; i < 2; i++) {
         ide_bus_reset(&d->bus[i]);
-        ide_dma_reset(&d->bmdma[i]);
     }
 }
 
diff --git a/hw/ide/core.c b/hw/ide/core.c
index ed6854d..2032e20 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -34,8 +34,6 @@
 
 #include <hw/ide/internal.h>
 
-#define IDE_PAGE_SIZE 4096
-
 static const int smart_attributes[][5] = {
     /* id,  flags, val, wrst, thrsh */
     { 0x01, 0x03, 0x64, 0x64, 0x06}, /* raw read */
@@ -61,11 +59,8 @@ static inline int media_is_cd(IDEState *s)
     return (media_present(s) && s->nb_sectors <= CD_MAX_SECTORS);
 }
 
-static void ide_dma_start(IDEState *s, BlockDriverCompletionFunc *dma_cb);
-static void ide_dma_restart(IDEState *s, int is_read);
 static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret);
 static int ide_handle_rw_error(IDEState *s, int error, int op);
-static void ide_flush_cache(IDEState *s);
 
 static void padstr(char *str, const char *src, int len)
 {
@@ -314,11 +309,11 @@ static inline void ide_abort_command(IDEState *s)
 }
 
 static inline void ide_dma_submit_check(IDEState *s,
-          BlockDriverCompletionFunc *dma_cb, BMDMAState *bm)
+          BlockDriverCompletionFunc *dma_cb)
 {
-    if (bm->aiocb)
+    if (s->bus->dma->aiocb)
 	return;
-    dma_cb(bm, -1);
+    dma_cb(s, -1);
 }
 
 /* prepare data transfer and tell what to do after */
@@ -328,8 +323,10 @@ static void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
     s->end_transfer_func = end_transfer_func;
     s->data_ptr = buf;
     s->data_end = buf + size;
-    if (!(s->status & ERR_STAT))
+    if (!(s->status & ERR_STAT)) {
         s->status |= DRQ_STAT;
+    }
+    s->bus->dma->ops->start_transfer(s->bus->dma);
 }
 
 static void ide_transfer_stop(IDEState *s)
@@ -394,7 +391,7 @@ static void ide_rw_error(IDEState *s) {
     ide_set_irq(s->bus);
 }
 
-static void ide_sector_read(IDEState *s)
+void ide_sector_read(IDEState *s)
 {
     int64_t sector_num;
     int ret, n;
@@ -427,58 +424,15 @@ static void ide_sector_read(IDEState *s)
     }
 }
 
-
-/* return 0 if buffer completed */
-static int dma_buf_prepare(BMDMAState *bm, int is_write)
-{
-    IDEState *s = bmdma_active_if(bm);
-    struct {
-        uint32_t addr;
-        uint32_t size;
-    } prd;
-    int l, len;
-
-    qemu_sglist_init(&s->sg, s->nsector / (IDE_PAGE_SIZE / 512) + 1);
-    s->io_buffer_size = 0;
-    for(;;) {
-        if (bm->cur_prd_len == 0) {
-            /* end of table (with a fail safe of one page) */
-            if (bm->cur_prd_last ||
-                (bm->cur_addr - bm->addr) >= IDE_PAGE_SIZE)
-                return s->io_buffer_size != 0;
-            cpu_physical_memory_read(bm->cur_addr, (uint8_t *)&prd, 8);
-            bm->cur_addr += 8;
-            prd.addr = le32_to_cpu(prd.addr);
-            prd.size = le32_to_cpu(prd.size);
-            len = prd.size & 0xfffe;
-            if (len == 0)
-                len = 0x10000;
-            bm->cur_prd_len = len;
-            bm->cur_prd_addr = prd.addr;
-            bm->cur_prd_last = (prd.size & 0x80000000);
-        }
-        l = bm->cur_prd_len;
-        if (l > 0) {
-            qemu_sglist_add(&s->sg, bm->cur_prd_addr, l);
-            bm->cur_prd_addr += l;
-            bm->cur_prd_len -= l;
-            s->io_buffer_size += l;
-        }
-    }
-    return 1;
-}
-
 static void dma_buf_commit(IDEState *s, int is_write)
 {
     qemu_sglist_destroy(&s->sg);
 }
 
-static void ide_dma_set_inactive(BMDMAState *bm)
+static void ide_set_inactive(IDEState *s)
 {
-    bm->status &= ~BM_STATUS_DMAING;
-    bm->dma_cb = NULL;
-    bm->unit = -1;
-    bm->aiocb = NULL;
+    s->bus->dma->aiocb = NULL;
+    s->bus->dma->ops->set_inactive(s->bus->dma);
 }
 
 void ide_dma_error(IDEState *s)
@@ -486,8 +440,8 @@ void ide_dma_error(IDEState *s)
     ide_transfer_stop(s);
     s->error = ABRT_ERR;
     s->status = READY_STAT | ERR_STAT;
-    ide_dma_set_inactive(s->bus->bmdma);
-    s->bus->bmdma->status |= BM_STATUS_INT;
+    ide_set_inactive(s);
+    s->bus->dma->ops->add_status(s->bus->dma, BM_STATUS_INT);
     ide_set_irq(s->bus);
 }
 
@@ -503,8 +457,8 @@ static int ide_handle_rw_error(IDEState *s, int error, int op)
 
     if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC)
             || action == BLOCK_ERR_STOP_ANY) {
-        s->bus->bmdma->unit = s->unit;
-        s->bus->bmdma->status |= op;
+        s->bus->dma->ops->set_unit(s->bus->dma, s->unit);
+        s->bus->dma->ops->add_status(s->bus->dma, op);
         bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read);
         vm_stop(0);
     } else {
@@ -520,58 +474,9 @@ static int ide_handle_rw_error(IDEState *s, int error, int op)
     return 1;
 }
 
-/* return 0 if buffer completed */
-static int dma_buf_rw(BMDMAState *bm, int is_write)
+void ide_read_dma_cb(void *opaque, int ret)
 {
-    IDEState *s = bmdma_active_if(bm);
-    struct {
-        uint32_t addr;
-        uint32_t size;
-    } prd;
-    int l, len;
-
-    for(;;) {
-        l = s->io_buffer_size - s->io_buffer_index;
-        if (l <= 0)
-            break;
-        if (bm->cur_prd_len == 0) {
-            /* end of table (with a fail safe of one page) */
-            if (bm->cur_prd_last ||
-                (bm->cur_addr - bm->addr) >= IDE_PAGE_SIZE)
-                return 0;
-            cpu_physical_memory_read(bm->cur_addr, (uint8_t *)&prd, 8);
-            bm->cur_addr += 8;
-            prd.addr = le32_to_cpu(prd.addr);
-            prd.size = le32_to_cpu(prd.size);
-            len = prd.size & 0xfffe;
-            if (len == 0)
-                len = 0x10000;
-            bm->cur_prd_len = len;
-            bm->cur_prd_addr = prd.addr;
-            bm->cur_prd_last = (prd.size & 0x80000000);
-        }
-        if (l > bm->cur_prd_len)
-            l = bm->cur_prd_len;
-        if (l > 0) {
-            if (is_write) {
-                cpu_physical_memory_write(bm->cur_prd_addr,
-                                          s->io_buffer + s->io_buffer_index, l);
-            } else {
-                cpu_physical_memory_read(bm->cur_prd_addr,
-                                          s->io_buffer + s->io_buffer_index, l);
-            }
-            bm->cur_prd_addr += l;
-            bm->cur_prd_len -= l;
-            s->io_buffer_index += l;
-        }
-    }
-    return 1;
-}
-
-static void ide_read_dma_cb(void *opaque, int ret)
-{
-    BMDMAState *bm = opaque;
-    IDEState *s = bmdma_active_if(bm);
+    IDEState *s = opaque;
     int n;
     int64_t sector_num;
 
@@ -597,8 +502,8 @@ static void ide_read_dma_cb(void *opaque, int ret)
         s->status = READY_STAT | SEEK_STAT;
         ide_set_irq(s->bus);
     eot:
-        bm->status |= BM_STATUS_INT;
-        ide_dma_set_inactive(bm);
+        s->bus->dma->ops->add_status(s->bus->dma, BM_STATUS_INT);
+        ide_set_inactive(s);
         return;
     }
 
@@ -606,13 +511,13 @@ static void ide_read_dma_cb(void *opaque, int ret)
     n = s->nsector;
     s->io_buffer_index = 0;
     s->io_buffer_size = n * 512;
-    if (dma_buf_prepare(bm, 1) == 0)
+    if (s->bus->dma->ops->prepare_buf(s->bus->dma, 1) == 0)
         goto eot;
 #ifdef DEBUG_AIO
     printf("aio_read: sector_num=%" PRId64 " n=%d\n", sector_num, n);
 #endif
-    bm->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num, ide_read_dma_cb, bm);
-    ide_dma_submit_check(s, ide_read_dma_cb, bm);
+    s->bus->dma->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num, ide_read_dma_cb, s);
+    ide_dma_submit_check(s, ide_read_dma_cb);
 }
 
 static void ide_sector_read_dma(IDEState *s)
@@ -621,7 +526,7 @@ static void ide_sector_read_dma(IDEState *s)
     s->io_buffer_index = 0;
     s->io_buffer_size = 0;
     s->is_read = 1;
-    ide_dma_start(s, ide_read_dma_cb);
+    s->bus->dma->ops->start_dma(s->bus->dma, s, ide_read_dma_cb);
 }
 
 static void ide_sector_write_timer_cb(void *opaque)
@@ -630,7 +535,7 @@ static void ide_sector_write_timer_cb(void *opaque)
     ide_set_irq(s->bus);
 }
 
-static void ide_sector_write(IDEState *s)
+void ide_sector_write(IDEState *s)
 {
     int64_t sector_num;
     int ret, n, n1;
@@ -676,48 +581,9 @@ static void ide_sector_write(IDEState *s)
     }
 }
 
-static void ide_dma_restart_bh(void *opaque)
+void ide_write_dma_cb(void *opaque, int ret)
 {
-    BMDMAState *bm = opaque;
-    int is_read;
-
-    qemu_bh_delete(bm->bh);
-    bm->bh = NULL;
-
-    is_read = !!(bm->status & BM_STATUS_RETRY_READ);
-
-    if (bm->status & BM_STATUS_DMA_RETRY) {
-        bm->status &= ~(BM_STATUS_DMA_RETRY | BM_STATUS_RETRY_READ);
-        ide_dma_restart(bmdma_active_if(bm), is_read);
-    } else if (bm->status & BM_STATUS_PIO_RETRY) {
-        bm->status &= ~(BM_STATUS_PIO_RETRY | BM_STATUS_RETRY_READ);
-        if (is_read) {
-            ide_sector_read(bmdma_active_if(bm));
-        } else {
-            ide_sector_write(bmdma_active_if(bm));
-        }
-    } else if (bm->status & BM_STATUS_RETRY_FLUSH) {
-        ide_flush_cache(bmdma_active_if(bm));
-    }
-}
-
-void ide_dma_restart_cb(void *opaque, int running, int reason)
-{
-    BMDMAState *bm = opaque;
-
-    if (!running)
-        return;
-
-    if (!bm->bh) {
-        bm->bh = qemu_bh_new(ide_dma_restart_bh, bm);
-        qemu_bh_schedule(bm->bh);
-    }
-}
-
-static void ide_write_dma_cb(void *opaque, int ret)
-{
-    BMDMAState *bm = opaque;
-    IDEState *s = bmdma_active_if(bm);
+    IDEState *s = opaque;
     int n;
     int64_t sector_num;
 
@@ -740,21 +606,21 @@ static void ide_write_dma_cb(void *opaque, int ret)
         s->status = READY_STAT | SEEK_STAT;
         ide_set_irq(s->bus);
     eot:
-        bm->status |= BM_STATUS_INT;
-        ide_dma_set_inactive(bm);
+        s->bus->dma->ops->add_status(s->bus->dma, BM_STATUS_INT);
+        ide_set_inactive(s);
         return;
     }
 
     n = s->nsector;
     s->io_buffer_size = n * 512;
     /* launch next transfer */
-    if (dma_buf_prepare(bm, 0) == 0)
+    if (s->bus->dma->ops->prepare_buf(s->bus->dma, 0) == 0)
         goto eot;
 #ifdef DEBUG_AIO
     printf("aio_write: sector_num=%" PRId64 " n=%d\n", sector_num, n);
 #endif
-    bm->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num, ide_write_dma_cb, bm);
-    ide_dma_submit_check(s, ide_write_dma_cb, bm);
+    s->bus->dma->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num, ide_write_dma_cb, s);
+    ide_dma_submit_check(s, ide_write_dma_cb);
 }
 
 static void ide_sector_write_dma(IDEState *s)
@@ -763,7 +629,7 @@ static void ide_sector_write_dma(IDEState *s)
     s->io_buffer_index = 0;
     s->io_buffer_size = 0;
     s->is_read = 0;
-    ide_dma_start(s, ide_write_dma_cb);
+    s->bus->dma->ops->start_dma(s->bus->dma, s, ide_write_dma_cb);
 }
 
 void ide_atapi_cmd_ok(IDEState *s)
@@ -813,7 +679,7 @@ static void ide_flush_cb(void *opaque, int ret)
     ide_set_irq(s->bus);
 }
 
-static void ide_flush_cache(IDEState *s)
+void ide_flush_cache(IDEState *s)
 {
     BlockDriverAIOCB *acb;
 
@@ -1003,7 +869,8 @@ static void ide_atapi_cmd_reply(IDEState *s, int size, int max_size)
 
     if (s->atapi_dma) {
     	s->status = READY_STAT | SEEK_STAT | DRQ_STAT;
-	ide_dma_start(s, ide_atapi_cmd_read_dma_cb);
+        s->bus->dma->ops->start_dma(s->bus->dma, s,
+                                   ide_atapi_cmd_read_dma_cb);
     } else {
     	s->status = READY_STAT | SEEK_STAT;
     	ide_atapi_cmd_reply_end(s);
@@ -1029,8 +896,7 @@ static void ide_atapi_cmd_read_pio(IDEState *s, int lba, int nb_sectors,
 /* XXX: handle read errors */
 static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret)
 {
-    BMDMAState *bm = opaque;
-    IDEState *s = bmdma_active_if(bm);
+    IDEState *s = opaque;
     int data_offset, n;
 
     if (ret < 0) {
@@ -1056,7 +922,7 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret)
 	    s->lba += n;
 	}
         s->packet_transfer_size -= s->io_buffer_size;
-        if (dma_buf_rw(bm, 1) == 0)
+        if (s->bus->dma->ops->rw_buf(s->bus->dma, 1) == 0)
             goto eot;
     }
 
@@ -1065,8 +931,8 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret)
         s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
         ide_set_irq(s->bus);
     eot:
-        bm->status |= BM_STATUS_INT;
-        ide_dma_set_inactive(bm);
+        s->bus->dma->ops->add_status(s->bus->dma, BM_STATUS_INT);
+        ide_set_inactive(s);
         return;
     }
 
@@ -1085,12 +951,13 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret)
 #ifdef DEBUG_AIO
     printf("aio_read_cd: lba=%u n=%d\n", s->lba, n);
 #endif
-    bm->iov.iov_base = (void *)(s->io_buffer + data_offset);
-    bm->iov.iov_len = n * 4 * 512;
-    qemu_iovec_init_external(&bm->qiov, &bm->iov, 1);
-    bm->aiocb = bdrv_aio_readv(s->bs, (int64_t)s->lba << 2, &bm->qiov,
-                               n * 4, ide_atapi_cmd_read_dma_cb, bm);
-    if (!bm->aiocb) {
+    s->bus->dma->iov.iov_base = (void *)(s->io_buffer + data_offset);
+    s->bus->dma->iov.iov_len = n * 4 * 512;
+    qemu_iovec_init_external(&s->bus->dma->qiov, &s->bus->dma->iov, 1);
+    s->bus->dma->aiocb = bdrv_aio_readv(s->bs, (int64_t)s->lba << 2,
+                                       &s->bus->dma->qiov, n * 4,
+                                       ide_atapi_cmd_read_dma_cb, s);
+    if (!s->bus->dma->aiocb) {
         /* Note: media not present is the most likely case */
         ide_atapi_cmd_error(s, SENSE_NOT_READY,
                             ASC_MEDIUM_NOT_PRESENT);
@@ -1111,7 +978,8 @@ static void ide_atapi_cmd_read_dma(IDEState *s, int lba, int nb_sectors,
 
     /* XXX: check if BUSY_STAT should be set */
     s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT;
-    ide_dma_start(s, ide_atapi_cmd_read_dma_cb);
+    s->bus->dma->ops->start_dma(s->bus->dma, s,
+                               ide_atapi_cmd_read_dma_cb);
 }
 
 static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors,
@@ -2638,6 +2506,18 @@ void ide_bus_reset(IDEBus *bus)
     ide_reset(&bus->ifs[0]);
     ide_reset(&bus->ifs[1]);
     ide_clear_hob(bus);
+
+    /* pending async DMA */
+    if (bus->dma->aiocb) {
+#ifdef DEBUG_AIO
+        printf("aio_cancel\n");
+#endif
+        bdrv_aio_cancel(bus->dma->aiocb);
+        bus->dma->aiocb = NULL;
+    }
+
+    /* reset dma provider too */
+    bus->dma->ops->reset(bus->dma);
 }
 
 int ide_init_drive(IDEState *s, BlockDriverState *bs,
@@ -2696,6 +2576,7 @@ int ide_init_drive(IDEState *s, BlockDriverState *bs,
     } else {
         pstrcpy(s->version, sizeof(s->version), QEMU_VERSION);
     }
+
     ide_reset(s);
     bdrv_set_removable(bs, s->drive_kind == IDE_CD);
     return 0;
@@ -2717,6 +2598,42 @@ static void ide_init1(IDEBus *bus, int unit)
                                            ide_sector_write_timer_cb, s);
 }
 
+static void ide_nop_start(IDEDMA *dma, IDEState *s,
+                          BlockDriverCompletionFunc *cb)
+{
+}
+
+static int ide_nop(IDEDMA *dma)
+{
+    return 0;
+}
+
+static int ide_nop_int(IDEDMA *dma, int x)
+{
+    return 0;
+}
+
+static void ide_nop_restart(void *opaque, int x, int y)
+{
+}
+
+static const IDEDMAOps ide_dma_nop_ops = {
+    .start_dma      = ide_nop_start,
+    .start_transfer = ide_nop,
+    .prepare_buf    = ide_nop_int,
+    .rw_buf         = ide_nop_int,
+    .set_unit       = ide_nop_int,
+    .add_status     = ide_nop_int,
+    .set_inactive   = ide_nop,
+    .restart_cb     = ide_nop_restart,
+    .reset          = ide_nop,
+};
+
+static IDEDMA ide_dma_nop = {
+    .ops = &ide_dma_nop_ops,
+    .aiocb = NULL,
+};
+
 void ide_init2(IDEBus *bus, qemu_irq irq)
 {
     int i;
@@ -2726,6 +2643,7 @@ void ide_init2(IDEBus *bus, qemu_irq irq)
         ide_reset(&bus->ifs[i]);
     }
     bus->irq = irq;
+    bus->dma = &ide_dma_nop;
 }
 
 /* TODO convert users to qdev and remove */
@@ -2749,6 +2667,7 @@ void ide_init2_with_non_qdev_drives(IDEBus *bus, DriveInfo *hd0,
         }
     }
     bus->irq = irq;
+    bus->dma = &ide_dma_nop;
 }
 
 void ide_init_ioport(IDEBus *bus, int iobase, int iobase2)
@@ -2916,73 +2835,3 @@ const VMStateDescription vmstate_ide_bus = {
         VMSTATE_END_OF_LIST()
     }
 };
-
-/***********************************************************/
-/* PCI IDE definitions */
-
-static void ide_dma_start(IDEState *s, BlockDriverCompletionFunc *dma_cb)
-{
-    BMDMAState *bm = s->bus->bmdma;
-    if(!bm)
-        return;
-    bm->unit = s->unit;
-    bm->dma_cb = dma_cb;
-    bm->cur_prd_last = 0;
-    bm->cur_prd_addr = 0;
-    bm->cur_prd_len = 0;
-    bm->sector_num = ide_get_sector(s);
-    bm->nsector = s->nsector;
-    if (bm->status & BM_STATUS_DMAING) {
-        bm->dma_cb(bm, 0);
-    }
-}
-
-static void ide_dma_restart(IDEState *s, int is_read)
-{
-    BMDMAState *bm = s->bus->bmdma;
-    ide_set_sector(s, bm->sector_num);
-    s->io_buffer_index = 0;
-    s->io_buffer_size = 0;
-    s->nsector = bm->nsector;
-    bm->cur_addr = bm->addr;
-
-    if (is_read) {
-        bm->dma_cb = ide_read_dma_cb;
-    } else {
-        bm->dma_cb = ide_write_dma_cb;
-    }
-
-    ide_dma_start(s, bm->dma_cb);
-}
-
-void ide_dma_cancel(BMDMAState *bm)
-{
-    if (bm->status & BM_STATUS_DMAING) {
-        if (bm->aiocb) {
-#ifdef DEBUG_AIO
-            printf("aio_cancel\n");
-#endif
-            bdrv_aio_cancel(bm->aiocb);
-        }
-
-        /* cancel DMA request */
-        ide_dma_set_inactive(bm);
-    }
-}
-
-void ide_dma_reset(BMDMAState *bm)
-{
-#ifdef DEBUG_IDE
-    printf("ide: dma_reset\n");
-#endif
-    ide_dma_cancel(bm);
-    bm->cmd = 0;
-    bm->status = 0;
-    bm->addr = 0;
-    bm->cur_addr = 0;
-    bm->cur_prd_last = 0;
-    bm->cur_prd_addr = 0;
-    bm->cur_prd_len = 0;
-    bm->sector_num = 0;
-    bm->nsector = 0;
-}
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index 029c76c..aadb505 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -20,7 +20,8 @@ typedef struct IDEBus IDEBus;
 typedef struct IDEDevice IDEDevice;
 typedef struct IDEDeviceInfo IDEDeviceInfo;
 typedef struct IDEState IDEState;
-typedef struct BMDMAState BMDMAState;
+typedef struct IDEDMA IDEDMA;
+typedef struct IDEDMAOps IDEDMAOps;
 
 /* Bits of HD_STATUS */
 #define ERR_STAT		0x01
@@ -367,6 +368,11 @@ typedef enum { IDE_HD, IDE_CD, IDE_CFATA } IDEDriveKind;
 
 typedef void EndTransferFunc(IDEState *);
 
+typedef void DMAStartFunc(IDEDMA *, IDEState *, BlockDriverCompletionFunc *);
+typedef int DMAFunc(IDEDMA *);
+typedef int DMAIntFunc(IDEDMA *, int);
+typedef void DMARestartFunc(void *, int, int);
+
 /* NOTE: IDEState represents in fact one drive */
 struct IDEState {
     IDEBus *bus;
@@ -443,13 +449,32 @@ struct IDEState {
     uint8_t *smart_selftest_data;
 };
 
+struct IDEDMAOps {
+    DMAStartFunc *start_dma;
+    DMAFunc *start_transfer;
+    DMAIntFunc *prepare_buf;
+    DMAIntFunc *rw_buf;
+    DMAIntFunc *set_unit;
+    DMAIntFunc *add_status;
+    DMAFunc *set_inactive;
+    DMARestartFunc *restart_cb;
+    DMAFunc *reset;
+};
+
+struct IDEDMA {
+    const struct IDEDMAOps *ops;
+    struct iovec iov;
+    QEMUIOVector qiov;
+    BlockDriverAIOCB *aiocb;
+};
+
 struct IDEBus {
     BusState qbus;
     IDEDevice *master;
     IDEDevice *slave;
-    BMDMAState *bmdma;
     IDEState ifs[2];
     int bus_id;
+    IDEDMA *dma;
     uint8_t unit;
     uint8_t cmd;
     qemu_irq irq;
@@ -480,46 +505,14 @@ struct IDEDeviceInfo {
 #define BM_CMD_START     0x01
 #define BM_CMD_READ      0x08
 
-struct BMDMAState {
-    uint8_t cmd;
-    uint8_t status;
-    uint32_t addr;
-
-    IDEBus *bus;
-    /* current transfer state */
-    uint32_t cur_addr;
-    uint32_t cur_prd_last;
-    uint32_t cur_prd_addr;
-    uint32_t cur_prd_len;
-    uint8_t unit;
-    BlockDriverCompletionFunc *dma_cb;
-    BlockDriverAIOCB *aiocb;
-    struct iovec iov;
-    QEMUIOVector qiov;
-    int64_t sector_num;
-    uint32_t nsector;
-    IORange addr_ioport;
-    QEMUBH *bh;
-};
-
 static inline IDEState *idebus_active_if(IDEBus *bus)
 {
     return bus->ifs + bus->unit;
 }
 
-static inline IDEState *bmdma_active_if(BMDMAState *bmdma)
-{
-    assert(bmdma->unit != (uint8_t)-1);
-    return bmdma->bus->ifs + bmdma->unit;
-}
-
 static inline void ide_set_irq(IDEBus *bus)
 {
-    BMDMAState *bm = bus->bmdma;
     if (!(bus->cmd & IDE_CMD_DISABLE_IRQ)) {
-        if (bm) {
-            bm->status |= BM_STATUS_INT;
-        }
         qemu_irq_raise(bus->irq);
     }
 }
@@ -542,10 +535,7 @@ void ide_bus_reset(IDEBus *bus);
 int64_t ide_get_sector(IDEState *s);
 void ide_set_sector(IDEState *s, int64_t sector_num);
 
-void ide_dma_cancel(BMDMAState *bm);
-void ide_dma_restart_cb(void *opaque, int running, int reason);
 void ide_dma_error(IDEState *s);
-void ide_dma_reset(BMDMAState *bm);
 
 void ide_atapi_cmd_ok(IDEState *s);
 void ide_atapi_cmd_error(IDEState *s, int sense_key, int asc);
@@ -568,6 +558,11 @@ void ide_init2_with_non_qdev_drives(IDEBus *bus, DriveInfo *hd0,
 void ide_init_ioport(IDEBus *bus, int iobase, int iobase2);
 
 void ide_exec_cmd(IDEBus *bus, uint32_t val);
+void ide_read_dma_cb(void *opaque, int ret);
+void ide_write_dma_cb(void *opaque, int ret);
+void ide_sector_write(IDEState *s);
+void ide_sector_read(IDEState *s);
+void ide_flush_cache(IDEState *s);
 
 /* hw/ide/qdev.c */
 void ide_bus_new(IDEBus *idebus, DeviceState *dev, int bus_id);
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index ad406ee..510b2de 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -33,6 +33,253 @@
 
 #include <hw/ide/pci.h>
 
+#define BMDMA_PAGE_SIZE 4096
+
+static void bmdma_start_dma(IDEDMA *dma, IDEState *s,
+                            BlockDriverCompletionFunc *dma_cb)
+{
+    BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
+
+    bm->unit = s->unit;
+    bm->dma_cb = dma_cb;
+    bm->cur_prd_last = 0;
+    bm->cur_prd_addr = 0;
+    bm->cur_prd_len = 0;
+    bm->sector_num = ide_get_sector(s);
+    bm->nsector = s->nsector;
+
+    if (bm->status & BM_STATUS_DMAING) {
+        bm->dma_cb(bmdma_active_if(bm), 0);
+    }
+}
+
+/* return 0 if buffer completed */
+static int bmdma_prepare_buf(IDEDMA *dma, int is_write)
+{
+    BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
+    IDEState *s = bmdma_active_if(bm);
+    struct {
+        uint32_t addr;
+        uint32_t size;
+    } prd;
+    int l, len;
+
+    qemu_sglist_init(&s->sg, s->nsector / (BMDMA_PAGE_SIZE / 512) + 1);
+    s->io_buffer_size = 0;
+    for(;;) {
+        if (bm->cur_prd_len == 0) {
+            /* end of table (with a fail safe of one page) */
+            if (bm->cur_prd_last ||
+                (bm->cur_addr - bm->addr) >= BMDMA_PAGE_SIZE)
+                return s->io_buffer_size != 0;
+            cpu_physical_memory_read(bm->cur_addr, (uint8_t *)&prd, 8);
+            bm->cur_addr += 8;
+            prd.addr = le32_to_cpu(prd.addr);
+            prd.size = le32_to_cpu(prd.size);
+            len = prd.size & 0xfffe;
+            if (len == 0)
+                len = 0x10000;
+            bm->cur_prd_len = len;
+            bm->cur_prd_addr = prd.addr;
+            bm->cur_prd_last = (prd.size & 0x80000000);
+        }
+        l = bm->cur_prd_len;
+        if (l > 0) {
+            qemu_sglist_add(&s->sg, bm->cur_prd_addr, l);
+            bm->cur_prd_addr += l;
+            bm->cur_prd_len -= l;
+            s->io_buffer_size += l;
+        }
+    }
+    return 1;
+}
+
+/* return 0 if buffer completed */
+static int bmdma_rw_buf(IDEDMA *dma, int is_write)
+{
+    BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
+    IDEState *s = bmdma_active_if(bm);
+    struct {
+        uint32_t addr;
+        uint32_t size;
+    } prd;
+    int l, len;
+
+    for(;;) {
+        l = s->io_buffer_size - s->io_buffer_index;
+        if (l <= 0)
+            break;
+        if (bm->cur_prd_len == 0) {
+            /* end of table (with a fail safe of one page) */
+            if (bm->cur_prd_last ||
+                (bm->cur_addr - bm->addr) >= BMDMA_PAGE_SIZE)
+                return 0;
+            cpu_physical_memory_read(bm->cur_addr, (uint8_t *)&prd, 8);
+            bm->cur_addr += 8;
+            prd.addr = le32_to_cpu(prd.addr);
+            prd.size = le32_to_cpu(prd.size);
+            len = prd.size & 0xfffe;
+            if (len == 0)
+                len = 0x10000;
+            bm->cur_prd_len = len;
+            bm->cur_prd_addr = prd.addr;
+            bm->cur_prd_last = (prd.size & 0x80000000);
+        }
+        if (l > bm->cur_prd_len)
+            l = bm->cur_prd_len;
+        if (l > 0) {
+            if (is_write) {
+                cpu_physical_memory_write(bm->cur_prd_addr,
+                                          s->io_buffer + s->io_buffer_index, l);
+            } else {
+                cpu_physical_memory_read(bm->cur_prd_addr,
+                                          s->io_buffer + s->io_buffer_index, l);
+            }
+            bm->cur_prd_addr += l;
+            bm->cur_prd_len -= l;
+            s->io_buffer_index += l;
+        }
+    }
+    return 1;
+}
+
+static int bmdma_set_unit(IDEDMA *dma, int unit)
+{
+    BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
+    bm->unit = unit;
+
+    return 0;
+}
+
+static int bmdma_add_status(IDEDMA *dma, int status)
+{
+    BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
+    bm->status |= status;
+
+    return 0;
+}
+
+static int bmdma_set_inactive(IDEDMA *dma)
+{
+    BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
+
+    bm->status &= ~BM_STATUS_DMAING;
+    bm->dma_cb = NULL;
+    bm->unit = -1;
+
+    return 0;
+}
+
+static void bmdma_restart_dma(BMDMAState *bm, int is_read)
+{
+    IDEState *s = bmdma_active_if(bm);
+
+    ide_set_sector(s, bm->sector_num);
+    s->io_buffer_index = 0;
+    s->io_buffer_size = 0;
+    s->nsector = bm->nsector;
+    bm->cur_addr = bm->addr;
+
+    if (is_read) {
+        bm->dma_cb = ide_read_dma_cb;
+    } else {
+        bm->dma_cb = ide_write_dma_cb;
+    }
+
+    bmdma_start_dma(&bm->dma, s, bm->dma_cb);
+}
+
+static void bmdma_restart_bh(void *opaque)
+{
+    BMDMAState *bm = opaque;
+    int is_read;
+
+    qemu_bh_delete(bm->bh);
+    bm->bh = NULL;
+
+    is_read = !!(bm->status & BM_STATUS_RETRY_READ);
+
+    if (bm->status & BM_STATUS_DMA_RETRY) {
+        bm->status &= ~(BM_STATUS_DMA_RETRY | BM_STATUS_RETRY_READ);
+        bmdma_restart_dma(bm, is_read);
+    } else if (bm->status & BM_STATUS_PIO_RETRY) {
+        bm->status &= ~(BM_STATUS_PIO_RETRY | BM_STATUS_RETRY_READ);
+        if (is_read) {
+            ide_sector_read(bmdma_active_if(bm));
+        } else {
+            ide_sector_write(bmdma_active_if(bm));
+        }
+    } else if (bm->status & BM_STATUS_RETRY_FLUSH) {
+        ide_flush_cache(bmdma_active_if(bm));
+    }
+}
+
+static void bmdma_restart_cb(void *opaque, int running, int reason)
+{
+    IDEDMA *dma = opaque;
+    BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
+
+    if (!running)
+        return;
+
+    if (!bm->bh) {
+        bm->bh = qemu_bh_new(bmdma_restart_bh, &bm->dma);
+        qemu_bh_schedule(bm->bh);
+    }
+}
+
+static void bmdma_cancel(BMDMAState *bm)
+{
+    if (bm->status & BM_STATUS_DMAING) {
+        /* cancel DMA request */
+        bmdma_set_inactive(&bm->dma);
+    }
+}
+
+static int bmdma_reset(IDEDMA *dma)
+{
+    BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
+
+#ifdef DEBUG_IDE
+    printf("ide: dma_reset\n");
+#endif
+    bmdma_cancel(bm);
+    bm->cmd = 0;
+    bm->status = 0;
+    bm->addr = 0;
+    bm->cur_addr = 0;
+    bm->cur_prd_last = 0;
+    bm->cur_prd_addr = 0;
+    bm->cur_prd_len = 0;
+    bm->sector_num = 0;
+    bm->nsector = 0;
+
+    return 0;
+}
+
+static int bmdma_start_transfer(IDEDMA *dma)
+{
+    return 0;
+}
+
+static void bmdma_irq(void *opaque, int n, int level)
+{
+    BMDMAState *bm = opaque;
+
+    if (!level) {
+        /* pass through lower */
+        qemu_set_irq(bm->irq, level);
+        return;
+    }
+
+    if (bm) {
+        bm->status |= BM_STATUS_INT;
+    }
+
+    /* trigger the real irq */
+    qemu_set_irq(bm->irq, level);
+}
+
 void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
 {
     BMDMAState *bm = opaque;
@@ -55,10 +302,10 @@ void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
              * whole DMA operation will be submitted to disk with a single
              * aio operation with preadv/pwritev.
              */
-            if (bm->aiocb) {
+            if (bm->bus->dma->aiocb) {
                 qemu_aio_flush();
 #ifdef DEBUG_IDE
-                if (bm->aiocb)
+                if (bm->bus->dma->aiocb)
                     printf("ide_dma_cancel: aiocb still pending");
                 if (bm->status & BM_STATUS_DMAING)
                     printf("ide_dma_cancel: BM_STATUS_DMAING still pending");
@@ -70,7 +317,7 @@ void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
                 bm->status |= BM_STATUS_DMAING;
                 /* start dma transfer if possible */
                 if (bm->dma_cb)
-                    bm->dma_cb(bm, 0);
+                    bm->dma_cb(bmdma_active_if(bm), 0);
             }
         }
     }
@@ -198,3 +445,30 @@ void pci_ide_create_devs(PCIDevice *dev, DriveInfo **hd_table)
         ide_create_drive(d->bus+bus[i], unit[i], hd_table[i]);
     }
 }
+
+static const struct IDEDMAOps bmdma_ops = {
+    .start_dma = bmdma_start_dma,
+    .start_transfer = bmdma_start_transfer,
+    .prepare_buf = bmdma_prepare_buf,
+    .rw_buf = bmdma_rw_buf,
+    .set_unit = bmdma_set_unit,
+    .add_status = bmdma_add_status,
+    .set_inactive = bmdma_set_inactive,
+    .restart_cb = bmdma_restart_cb,
+    .reset = bmdma_reset,
+};
+
+void bmdma_init(IDEBus *bus, BMDMAState *bm)
+{
+    qemu_irq *irq;
+
+    if (bus->dma == &bm->dma) {
+        return;
+    }
+
+    bm->dma.ops = &bmdma_ops;
+    bus->dma = &bm->dma;
+    bm->irq = bus->irq;
+    irq = qemu_allocate_irqs(bmdma_irq, bm, 1);
+    bus->irq = *irq;
+}
diff --git a/hw/ide/pci.h b/hw/ide/pci.h
index b81b26c..cd72cba 100644
--- a/hw/ide/pci.h
+++ b/hw/ide/pci.h
@@ -3,6 +3,27 @@
 
 #include <hw/ide/internal.h>
 
+typedef struct BMDMAState {
+    IDEDMA dma;
+    uint8_t cmd;
+    uint8_t status;
+    uint32_t addr;
+
+    IDEBus *bus;
+    /* current transfer state */
+    uint32_t cur_addr;
+    uint32_t cur_prd_last;
+    uint32_t cur_prd_addr;
+    uint32_t cur_prd_len;
+    uint8_t unit;
+    BlockDriverCompletionFunc *dma_cb;
+    int64_t sector_num;
+    uint32_t nsector;
+    IORange addr_ioport;
+    QEMUBH *bh;
+    qemu_irq irq;
+} BMDMAState;
+
 typedef struct PCIIDEState {
     PCIDevice dev;
     IDEBus bus[2];
@@ -10,6 +31,15 @@ typedef struct PCIIDEState {
     uint32_t secondary; /* used only for cmd646 */
 } PCIIDEState;
 
+
+static inline IDEState *bmdma_active_if(BMDMAState *bmdma)
+{
+    assert(bmdma->unit != (uint8_t)-1);
+    return bmdma->bus->ifs + bmdma->unit;
+}
+
+
+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 pci_ide_create_devs(PCIDevice *dev, DriveInfo **hd_table);
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index 1c0cb0c..a6b5d92 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -76,9 +76,10 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num,
 
     for(i = 0;i < 2; i++) {
         BMDMAState *bm = &d->bmdma[i];
-        d->bus[i].bmdma = bm;
+        bmdma_init(&d->bus[i], bm);
         bm->bus = d->bus+i;
-        qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm);
+        qemu_add_vm_change_state_handler(d->bus[i].dma->ops->restart_cb,
+                                         &bm->dma);
 
         register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm);
 
@@ -99,7 +100,6 @@ static void piix3_reset(void *opaque)
 
     for (i = 0; i < 2; i++) {
         ide_bus_reset(&d->bus[i]);
-        ide_dma_reset(&d->bmdma[i]);
     }
 
     /* TODO: this is the default. do not override. */
diff --git a/hw/ide/via.c b/hw/ide/via.c
index 78857e8..2603110 100644
--- a/hw/ide/via.c
+++ b/hw/ide/via.c
@@ -78,9 +78,10 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num,
 
     for(i = 0;i < 2; i++) {
         BMDMAState *bm = &d->bmdma[i];
-        d->bus[i].bmdma = bm;
+        bmdma_init(&d->bus[i], bm);
         bm->bus = d->bus+i;
-        qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm);
+        qemu_add_vm_change_state_handler(d->bus[i].dma->ops->restart_cb,
+                                         &bm->dma);
 
         register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm);
 
@@ -101,7 +102,6 @@ static void via_reset(void *opaque)
 
     for (i = 0; i < 2; i++) {
         ide_bus_reset(&d->bus[i]);
-        ide_dma_reset(&d->bmdma[i]);
     }
 
     pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_WAIT);
commit 6ef2ba5ea64e9feffdd1a8ffff66749323f719c8
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Dec 14 01:34:34 2010 +0100

    ide: fix whitespace gap in ide_exec_cmd
    
    Now that we have the function split out, we have to reindent it.
    In order to increase the readability of the actual functional change,
    this is split out.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/ide/core.c b/hw/ide/core.c
index ac4ee71..ed6854d 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -1864,423 +1864,423 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
     int lba48 = 0;
 
 #if defined(DEBUG_IDE)
-        printf("ide: CMD=%02x\n", val);
+    printf("ide: CMD=%02x\n", val);
 #endif
-        s = idebus_active_if(bus);
-        /* ignore commands to non existant slave */
-        if (s != bus->ifs && !s->bs)
-            return;
+    s = idebus_active_if(bus);
+    /* ignore commands to non existant slave */
+    if (s != bus->ifs && !s->bs)
+        return;
 
-        /* Only DEVICE RESET is allowed while BSY or/and DRQ are set */
-        if ((s->status & (BUSY_STAT|DRQ_STAT)) && val != WIN_DEVICE_RESET)
-            return;
+    /* Only DEVICE RESET is allowed while BSY or/and DRQ are set */
+    if ((s->status & (BUSY_STAT|DRQ_STAT)) && val != WIN_DEVICE_RESET)
+        return;
 
-        switch(val) {
-        case WIN_IDENTIFY:
-            if (s->bs && s->drive_kind != IDE_CD) {
-                if (s->drive_kind != IDE_CFATA)
-                    ide_identify(s);
-                else
-                    ide_cfata_identify(s);
-                s->status = READY_STAT | SEEK_STAT;
-                ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);
-            } else {
-                if (s->drive_kind == IDE_CD) {
-                    ide_set_signature(s);
-                }
-                ide_abort_command(s);
-            }
-            ide_set_irq(s->bus);
-            break;
-        case WIN_SPECIFY:
-        case WIN_RECAL:
-            s->error = 0;
+    switch(val) {
+    case WIN_IDENTIFY:
+        if (s->bs && s->drive_kind != IDE_CD) {
+            if (s->drive_kind != IDE_CFATA)
+                ide_identify(s);
+            else
+                ide_cfata_identify(s);
             s->status = READY_STAT | SEEK_STAT;
-            ide_set_irq(s->bus);
-            break;
-        case WIN_SETMULT:
-            if (s->drive_kind == IDE_CFATA && s->nsector == 0) {
-                /* Disable Read and Write Multiple */
-                s->mult_sectors = 0;
-                s->status = READY_STAT | SEEK_STAT;
-            } else if ((s->nsector & 0xff) != 0 &&
-                ((s->nsector & 0xff) > MAX_MULT_SECTORS ||
-                 (s->nsector & (s->nsector - 1)) != 0)) {
-                ide_abort_command(s);
-            } else {
-                s->mult_sectors = s->nsector & 0xff;
-                s->status = READY_STAT | SEEK_STAT;
+            ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);
+        } else {
+            if (s->drive_kind == IDE_CD) {
+                ide_set_signature(s);
             }
-            ide_set_irq(s->bus);
-            break;
-        case WIN_VERIFY_EXT:
-	    lba48 = 1;
-        case WIN_VERIFY:
-        case WIN_VERIFY_ONCE:
-            /* do sector number check ? */
-	    ide_cmd_lba48_transform(s, lba48);
+            ide_abort_command(s);
+        }
+        ide_set_irq(s->bus);
+        break;
+    case WIN_SPECIFY:
+    case WIN_RECAL:
+        s->error = 0;
+        s->status = READY_STAT | SEEK_STAT;
+        ide_set_irq(s->bus);
+        break;
+    case WIN_SETMULT:
+        if (s->drive_kind == IDE_CFATA && s->nsector == 0) {
+            /* Disable Read and Write Multiple */
+            s->mult_sectors = 0;
             s->status = READY_STAT | SEEK_STAT;
-            ide_set_irq(s->bus);
-            break;
+        } else if ((s->nsector & 0xff) != 0 &&
+            ((s->nsector & 0xff) > MAX_MULT_SECTORS ||
+             (s->nsector & (s->nsector - 1)) != 0)) {
+            ide_abort_command(s);
+        } else {
+            s->mult_sectors = s->nsector & 0xff;
+            s->status = READY_STAT | SEEK_STAT;
+        }
+        ide_set_irq(s->bus);
+        break;
+    case WIN_VERIFY_EXT:
+	lba48 = 1;
+    case WIN_VERIFY:
+    case WIN_VERIFY_ONCE:
+        /* do sector number check ? */
+	ide_cmd_lba48_transform(s, lba48);
+        s->status = READY_STAT | SEEK_STAT;
+        ide_set_irq(s->bus);
+        break;
 	case WIN_READ_EXT:
-	    lba48 = 1;
-        case WIN_READ:
-        case WIN_READ_ONCE:
-            if (!s->bs)
-                goto abort_cmd;
-	    ide_cmd_lba48_transform(s, lba48);
-            s->req_nb_sectors = 1;
-            ide_sector_read(s);
-            break;
+	lba48 = 1;
+    case WIN_READ:
+    case WIN_READ_ONCE:
+        if (!s->bs)
+            goto abort_cmd;
+	ide_cmd_lba48_transform(s, lba48);
+        s->req_nb_sectors = 1;
+        ide_sector_read(s);
+        break;
 	case WIN_WRITE_EXT:
-	    lba48 = 1;
-        case WIN_WRITE:
-        case WIN_WRITE_ONCE:
-        case CFA_WRITE_SECT_WO_ERASE:
-        case WIN_WRITE_VERIFY:
-	    ide_cmd_lba48_transform(s, lba48);
-            s->error = 0;
-            s->status = SEEK_STAT | READY_STAT;
-            s->req_nb_sectors = 1;
-            ide_transfer_start(s, s->io_buffer, 512, ide_sector_write);
-            s->media_changed = 1;
-            break;
+	lba48 = 1;
+    case WIN_WRITE:
+    case WIN_WRITE_ONCE:
+    case CFA_WRITE_SECT_WO_ERASE:
+    case WIN_WRITE_VERIFY:
+	ide_cmd_lba48_transform(s, lba48);
+        s->error = 0;
+        s->status = SEEK_STAT | READY_STAT;
+        s->req_nb_sectors = 1;
+        ide_transfer_start(s, s->io_buffer, 512, ide_sector_write);
+        s->media_changed = 1;
+        break;
 	case WIN_MULTREAD_EXT:
-	    lba48 = 1;
-        case WIN_MULTREAD:
-            if (!s->mult_sectors)
-                goto abort_cmd;
-	    ide_cmd_lba48_transform(s, lba48);
-            s->req_nb_sectors = s->mult_sectors;
-            ide_sector_read(s);
-            break;
-        case WIN_MULTWRITE_EXT:
-	    lba48 = 1;
-        case WIN_MULTWRITE:
-        case CFA_WRITE_MULTI_WO_ERASE:
-            if (!s->mult_sectors)
-                goto abort_cmd;
-	    ide_cmd_lba48_transform(s, lba48);
-            s->error = 0;
-            s->status = SEEK_STAT | READY_STAT;
-            s->req_nb_sectors = s->mult_sectors;
-            n = s->nsector;
-            if (n > s->req_nb_sectors)
-                n = s->req_nb_sectors;
-            ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_write);
-            s->media_changed = 1;
-            break;
+	lba48 = 1;
+    case WIN_MULTREAD:
+        if (!s->mult_sectors)
+            goto abort_cmd;
+	ide_cmd_lba48_transform(s, lba48);
+        s->req_nb_sectors = s->mult_sectors;
+        ide_sector_read(s);
+        break;
+    case WIN_MULTWRITE_EXT:
+	lba48 = 1;
+    case WIN_MULTWRITE:
+    case CFA_WRITE_MULTI_WO_ERASE:
+        if (!s->mult_sectors)
+            goto abort_cmd;
+	ide_cmd_lba48_transform(s, lba48);
+        s->error = 0;
+        s->status = SEEK_STAT | READY_STAT;
+        s->req_nb_sectors = s->mult_sectors;
+        n = s->nsector;
+        if (n > s->req_nb_sectors)
+            n = s->req_nb_sectors;
+        ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_write);
+        s->media_changed = 1;
+        break;
 	case WIN_READDMA_EXT:
-	    lba48 = 1;
-        case WIN_READDMA:
-        case WIN_READDMA_ONCE:
-            if (!s->bs)
-                goto abort_cmd;
-	    ide_cmd_lba48_transform(s, lba48);
-            ide_sector_read_dma(s);
-            break;
+	lba48 = 1;
+    case WIN_READDMA:
+    case WIN_READDMA_ONCE:
+        if (!s->bs)
+            goto abort_cmd;
+	ide_cmd_lba48_transform(s, lba48);
+        ide_sector_read_dma(s);
+        break;
 	case WIN_WRITEDMA_EXT:
-	    lba48 = 1;
-        case WIN_WRITEDMA:
-        case WIN_WRITEDMA_ONCE:
-            if (!s->bs)
-                goto abort_cmd;
-	    ide_cmd_lba48_transform(s, lba48);
-            ide_sector_write_dma(s);
-            s->media_changed = 1;
-            break;
-        case WIN_READ_NATIVE_MAX_EXT:
-	    lba48 = 1;
-        case WIN_READ_NATIVE_MAX:
-	    ide_cmd_lba48_transform(s, lba48);
-            ide_set_sector(s, s->nb_sectors - 1);
-            s->status = READY_STAT | SEEK_STAT;
-            ide_set_irq(s->bus);
-            break;
-        case WIN_CHECKPOWERMODE1:
-        case WIN_CHECKPOWERMODE2:
-            s->nsector = 0xff; /* device active or idle */
+	lba48 = 1;
+    case WIN_WRITEDMA:
+    case WIN_WRITEDMA_ONCE:
+        if (!s->bs)
+            goto abort_cmd;
+	ide_cmd_lba48_transform(s, lba48);
+        ide_sector_write_dma(s);
+        s->media_changed = 1;
+        break;
+    case WIN_READ_NATIVE_MAX_EXT:
+	lba48 = 1;
+    case WIN_READ_NATIVE_MAX:
+	ide_cmd_lba48_transform(s, lba48);
+        ide_set_sector(s, s->nb_sectors - 1);
+        s->status = READY_STAT | SEEK_STAT;
+        ide_set_irq(s->bus);
+        break;
+    case WIN_CHECKPOWERMODE1:
+    case WIN_CHECKPOWERMODE2:
+        s->nsector = 0xff; /* device active or idle */
+        s->status = READY_STAT | SEEK_STAT;
+        ide_set_irq(s->bus);
+        break;
+    case WIN_SETFEATURES:
+        if (!s->bs)
+            goto abort_cmd;
+        /* XXX: valid for CDROM ? */
+        switch(s->feature) {
+        case 0xcc: /* reverting to power-on defaults enable */
+        case 0x66: /* reverting to power-on defaults disable */
+        case 0x02: /* write cache enable */
+        case 0x82: /* write cache disable */
+        case 0xaa: /* read look-ahead enable */
+        case 0x55: /* read look-ahead disable */
+        case 0x05: /* set advanced power management mode */
+        case 0x85: /* disable advanced power management mode */
+        case 0x69: /* NOP */
+        case 0x67: /* NOP */
+        case 0x96: /* NOP */
+        case 0x9a: /* NOP */
+        case 0x42: /* enable Automatic Acoustic Mode */
+        case 0xc2: /* disable Automatic Acoustic Mode */
             s->status = READY_STAT | SEEK_STAT;
             ide_set_irq(s->bus);
             break;
-        case WIN_SETFEATURES:
-            if (!s->bs)
-                goto abort_cmd;
-            /* XXX: valid for CDROM ? */
-            switch(s->feature) {
-            case 0xcc: /* reverting to power-on defaults enable */
-            case 0x66: /* reverting to power-on defaults disable */
-            case 0x02: /* write cache enable */
-            case 0x82: /* write cache disable */
-            case 0xaa: /* read look-ahead enable */
-            case 0x55: /* read look-ahead disable */
-            case 0x05: /* set advanced power management mode */
-            case 0x85: /* disable advanced power management mode */
-            case 0x69: /* NOP */
-            case 0x67: /* NOP */
-            case 0x96: /* NOP */
-            case 0x9a: /* NOP */
-            case 0x42: /* enable Automatic Acoustic Mode */
-            case 0xc2: /* disable Automatic Acoustic Mode */
-                s->status = READY_STAT | SEEK_STAT;
-                ide_set_irq(s->bus);
-                break;
-            case 0x03: { /* set transfer mode */
+        case 0x03: { /* set transfer mode */
 		uint8_t val = s->nsector & 0x07;
-                uint16_t *identify_data = (uint16_t *)s->identify_data;
+            uint16_t *identify_data = (uint16_t *)s->identify_data;
 
 		switch (s->nsector >> 3) {
-		    case 0x00: /* pio default */
-		    case 0x01: /* pio mode */
+		case 0x00: /* pio default */
+		case 0x01: /* pio mode */
 			put_le16(identify_data + 62,0x07);
 			put_le16(identify_data + 63,0x07);
 			put_le16(identify_data + 88,0x3f);
 			break;
-                    case 0x02: /* sigle word dma mode*/
+                case 0x02: /* sigle word dma mode*/
 			put_le16(identify_data + 62,0x07 | (1 << (val + 8)));
 			put_le16(identify_data + 63,0x07);
 			put_le16(identify_data + 88,0x3f);
 			break;
-		    case 0x04: /* mdma mode */
+		case 0x04: /* mdma mode */
 			put_le16(identify_data + 62,0x07);
 			put_le16(identify_data + 63,0x07 | (1 << (val + 8)));
 			put_le16(identify_data + 88,0x3f);
 			break;
-		    case 0x08: /* udma mode */
+		case 0x08: /* udma mode */
 			put_le16(identify_data + 62,0x07);
 			put_le16(identify_data + 63,0x07);
 			put_le16(identify_data + 88,0x3f | (1 << (val + 8)));
 			break;
-		    default:
+		default:
 			goto abort_cmd;
 		}
-                s->status = READY_STAT | SEEK_STAT;
-                ide_set_irq(s->bus);
-                break;
-	    }
-            default:
-                goto abort_cmd;
-            }
-            break;
-        case WIN_FLUSH_CACHE:
-        case WIN_FLUSH_CACHE_EXT:
-            ide_flush_cache(s);
-            break;
-        case WIN_STANDBY:
-        case WIN_STANDBY2:
-        case WIN_STANDBYNOW1:
-        case WIN_STANDBYNOW2:
-        case WIN_IDLEIMMEDIATE:
-        case CFA_IDLEIMMEDIATE:
-        case WIN_SETIDLE1:
-        case WIN_SETIDLE2:
-        case WIN_SLEEPNOW1:
-        case WIN_SLEEPNOW2:
-            s->status = READY_STAT;
-            ide_set_irq(s->bus);
-            break;
-        case WIN_SEEK:
-            if(s->drive_kind == IDE_CD)
-                goto abort_cmd;
-            /* XXX: Check that seek is within bounds */
             s->status = READY_STAT | SEEK_STAT;
             ide_set_irq(s->bus);
             break;
-            /* ATAPI commands */
-        case WIN_PIDENTIFY:
-            if (s->drive_kind == IDE_CD) {
-                ide_atapi_identify(s);
-                s->status = READY_STAT | SEEK_STAT;
-                ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);
-            } else {
-                ide_abort_command(s);
-            }
-            ide_set_irq(s->bus);
-            break;
-        case WIN_DIAGNOSE:
-            ide_set_signature(s);
-            if (s->drive_kind == IDE_CD)
-                s->status = 0; /* ATAPI spec (v6) section 9.10 defines packet
-                                * devices to return a clear status register
-                                * with READY_STAT *not* set. */
-            else
-                s->status = READY_STAT | SEEK_STAT;
-            s->error = 0x01; /* Device 0 passed, Device 1 passed or not
-                              * present. 
-                              */
-            ide_set_irq(s->bus);
-            break;
-        case WIN_SRST:
-            if (s->drive_kind != IDE_CD)
-                goto abort_cmd;
-            ide_set_signature(s);
-            s->status = 0x00; /* NOTE: READY is _not_ set */
-            s->error = 0x01;
-            break;
-        case WIN_PACKETCMD:
-            if (s->drive_kind != IDE_CD)
-                goto abort_cmd;
-            /* overlapping commands not supported */
-            if (s->feature & 0x02)
-                goto abort_cmd;
+	}
+        default:
+            goto abort_cmd;
+        }
+        break;
+    case WIN_FLUSH_CACHE:
+    case WIN_FLUSH_CACHE_EXT:
+        ide_flush_cache(s);
+        break;
+    case WIN_STANDBY:
+    case WIN_STANDBY2:
+    case WIN_STANDBYNOW1:
+    case WIN_STANDBYNOW2:
+    case WIN_IDLEIMMEDIATE:
+    case CFA_IDLEIMMEDIATE:
+    case WIN_SETIDLE1:
+    case WIN_SETIDLE2:
+    case WIN_SLEEPNOW1:
+    case WIN_SLEEPNOW2:
+        s->status = READY_STAT;
+        ide_set_irq(s->bus);
+        break;
+    case WIN_SEEK:
+        if(s->drive_kind == IDE_CD)
+            goto abort_cmd;
+        /* XXX: Check that seek is within bounds */
+        s->status = READY_STAT | SEEK_STAT;
+        ide_set_irq(s->bus);
+        break;
+        /* ATAPI commands */
+    case WIN_PIDENTIFY:
+        if (s->drive_kind == IDE_CD) {
+            ide_atapi_identify(s);
             s->status = READY_STAT | SEEK_STAT;
-            s->atapi_dma = s->feature & 1;
-            s->nsector = 1;
-            ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE,
-                               ide_atapi_cmd);
-            break;
-        /* CF-ATA commands */
-        case CFA_REQ_EXT_ERROR_CODE:
-            if (s->drive_kind != IDE_CFATA)
-                goto abort_cmd;
-            s->error = 0x09;    /* miscellaneous error */
+            ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);
+        } else {
+            ide_abort_command(s);
+        }
+        ide_set_irq(s->bus);
+        break;
+    case WIN_DIAGNOSE:
+        ide_set_signature(s);
+        if (s->drive_kind == IDE_CD)
+            s->status = 0; /* ATAPI spec (v6) section 9.10 defines packet
+                            * devices to return a clear status register
+                            * with READY_STAT *not* set. */
+        else
             s->status = READY_STAT | SEEK_STAT;
-            ide_set_irq(s->bus);
+        s->error = 0x01; /* Device 0 passed, Device 1 passed or not
+                          * present.
+                          */
+        ide_set_irq(s->bus);
+        break;
+    case WIN_SRST:
+        if (s->drive_kind != IDE_CD)
+            goto abort_cmd;
+        ide_set_signature(s);
+        s->status = 0x00; /* NOTE: READY is _not_ set */
+        s->error = 0x01;
+        break;
+    case WIN_PACKETCMD:
+        if (s->drive_kind != IDE_CD)
+            goto abort_cmd;
+        /* overlapping commands not supported */
+        if (s->feature & 0x02)
+            goto abort_cmd;
+        s->status = READY_STAT | SEEK_STAT;
+        s->atapi_dma = s->feature & 1;
+        s->nsector = 1;
+        ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE,
+                           ide_atapi_cmd);
+        break;
+    /* CF-ATA commands */
+    case CFA_REQ_EXT_ERROR_CODE:
+        if (s->drive_kind != IDE_CFATA)
+            goto abort_cmd;
+        s->error = 0x09;    /* miscellaneous error */
+        s->status = READY_STAT | SEEK_STAT;
+        ide_set_irq(s->bus);
+        break;
+    case CFA_ERASE_SECTORS:
+    case CFA_WEAR_LEVEL:
+        if (s->drive_kind != IDE_CFATA)
+            goto abort_cmd;
+        if (val == CFA_WEAR_LEVEL)
+            s->nsector = 0;
+        if (val == CFA_ERASE_SECTORS)
+            s->media_changed = 1;
+        s->error = 0x00;
+        s->status = READY_STAT | SEEK_STAT;
+        ide_set_irq(s->bus);
+        break;
+    case CFA_TRANSLATE_SECTOR:
+        if (s->drive_kind != IDE_CFATA)
+            goto abort_cmd;
+        s->error = 0x00;
+        s->status = READY_STAT | SEEK_STAT;
+        memset(s->io_buffer, 0, 0x200);
+        s->io_buffer[0x00] = s->hcyl;			/* Cyl MSB */
+        s->io_buffer[0x01] = s->lcyl;			/* Cyl LSB */
+        s->io_buffer[0x02] = s->select;			/* Head */
+        s->io_buffer[0x03] = s->sector;			/* Sector */
+        s->io_buffer[0x04] = ide_get_sector(s) >> 16;	/* LBA MSB */
+        s->io_buffer[0x05] = ide_get_sector(s) >> 8;	/* LBA */
+        s->io_buffer[0x06] = ide_get_sector(s) >> 0;	/* LBA LSB */
+        s->io_buffer[0x13] = 0x00;				/* Erase flag */
+        s->io_buffer[0x18] = 0x00;				/* Hot count */
+        s->io_buffer[0x19] = 0x00;				/* Hot count */
+        s->io_buffer[0x1a] = 0x01;				/* Hot count */
+        ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
+        ide_set_irq(s->bus);
+        break;
+    case CFA_ACCESS_METADATA_STORAGE:
+        if (s->drive_kind != IDE_CFATA)
+            goto abort_cmd;
+        switch (s->feature) {
+        case 0x02:	/* Inquiry Metadata Storage */
+            ide_cfata_metadata_inquiry(s);
             break;
-        case CFA_ERASE_SECTORS:
-        case CFA_WEAR_LEVEL:
-            if (s->drive_kind != IDE_CFATA)
-                goto abort_cmd;
-            if (val == CFA_WEAR_LEVEL)
-                s->nsector = 0;
-            if (val == CFA_ERASE_SECTORS)
-                s->media_changed = 1;
-            s->error = 0x00;
-            s->status = READY_STAT | SEEK_STAT;
-            ide_set_irq(s->bus);
+        case 0x03:	/* Read Metadata Storage */
+            ide_cfata_metadata_read(s);
             break;
-        case CFA_TRANSLATE_SECTOR:
-            if (s->drive_kind != IDE_CFATA)
-                goto abort_cmd;
-            s->error = 0x00;
-            s->status = READY_STAT | SEEK_STAT;
-            memset(s->io_buffer, 0, 0x200);
-            s->io_buffer[0x00] = s->hcyl;			/* Cyl MSB */
-            s->io_buffer[0x01] = s->lcyl;			/* Cyl LSB */
-            s->io_buffer[0x02] = s->select;			/* Head */
-            s->io_buffer[0x03] = s->sector;			/* Sector */
-            s->io_buffer[0x04] = ide_get_sector(s) >> 16;	/* LBA MSB */
-            s->io_buffer[0x05] = ide_get_sector(s) >> 8;	/* LBA */
-            s->io_buffer[0x06] = ide_get_sector(s) >> 0;	/* LBA LSB */
-            s->io_buffer[0x13] = 0x00;				/* Erase flag */
-            s->io_buffer[0x18] = 0x00;				/* Hot count */
-            s->io_buffer[0x19] = 0x00;				/* Hot count */
-            s->io_buffer[0x1a] = 0x01;				/* Hot count */
-            ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
-            ide_set_irq(s->bus);
+        case 0x04:	/* Write Metadata Storage */
+            ide_cfata_metadata_write(s);
             break;
-        case CFA_ACCESS_METADATA_STORAGE:
-            if (s->drive_kind != IDE_CFATA)
-                goto abort_cmd;
-            switch (s->feature) {
-            case 0x02:	/* Inquiry Metadata Storage */
-                ide_cfata_metadata_inquiry(s);
-                break;
-            case 0x03:	/* Read Metadata Storage */
-                ide_cfata_metadata_read(s);
-                break;
-            case 0x04:	/* Write Metadata Storage */
-                ide_cfata_metadata_write(s);
-                break;
-            default:
-                goto abort_cmd;
-            }
-            ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
-            s->status = 0x00; /* NOTE: READY is _not_ set */
-            ide_set_irq(s->bus);
-            break;
-        case IBM_SENSE_CONDITION:
-            if (s->drive_kind != IDE_CFATA)
-                goto abort_cmd;
-            switch (s->feature) {
-            case 0x01:  /* sense temperature in device */
-                s->nsector = 0x50;      /* +20 C */
-                break;
-            default:
-                goto abort_cmd;
-            }
-            s->status = READY_STAT | SEEK_STAT;
-            ide_set_irq(s->bus);
+        default:
+            goto abort_cmd;
+        }
+        ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
+        s->status = 0x00; /* NOTE: READY is _not_ set */
+        ide_set_irq(s->bus);
+        break;
+    case IBM_SENSE_CONDITION:
+        if (s->drive_kind != IDE_CFATA)
+            goto abort_cmd;
+        switch (s->feature) {
+        case 0x01:  /* sense temperature in device */
+            s->nsector = 0x50;      /* +20 C */
             break;
+        default:
+            goto abort_cmd;
+        }
+        s->status = READY_STAT | SEEK_STAT;
+        ide_set_irq(s->bus);
+        break;
 
 	case WIN_SMART:
-	    if (s->drive_kind == IDE_CD)
+	if (s->drive_kind == IDE_CD)
 		goto abort_cmd;
-	    if (s->hcyl != 0xc2 || s->lcyl != 0x4f)
+	if (s->hcyl != 0xc2 || s->lcyl != 0x4f)
 		goto abort_cmd;
-	    if (!s->smart_enabled && s->feature != SMART_ENABLE)
+	if (!s->smart_enabled && s->feature != SMART_ENABLE)
 		goto abort_cmd;
-	    switch (s->feature) {
-	    case SMART_DISABLE:
+	switch (s->feature) {
+	case SMART_DISABLE:
 		s->smart_enabled = 0;
 		s->status = READY_STAT | SEEK_STAT;
 		ide_set_irq(s->bus);
 		break;
-	    case SMART_ENABLE:
+	case SMART_ENABLE:
 		s->smart_enabled = 1;
 		s->status = READY_STAT | SEEK_STAT;
 		ide_set_irq(s->bus);
 		break;
-	    case SMART_ATTR_AUTOSAVE:
+	case SMART_ATTR_AUTOSAVE:
 		switch (s->sector) {
 		case 0x00:
-		    s->smart_autosave = 0;
-		    break;
+		s->smart_autosave = 0;
+		break;
 		case 0xf1:
-		    s->smart_autosave = 1;
-		    break;
+		s->smart_autosave = 1;
+		break;
 		default:
-		    goto abort_cmd;
+		goto abort_cmd;
 		}
 		s->status = READY_STAT | SEEK_STAT;
 		ide_set_irq(s->bus);
 		break;
-	    case SMART_STATUS:
+	case SMART_STATUS:
 		if (!s->smart_errors) {
-		    s->hcyl = 0xc2;
-		    s->lcyl = 0x4f;
+		s->hcyl = 0xc2;
+		s->lcyl = 0x4f;
 		} else {
-		    s->hcyl = 0x2c;
-		    s->lcyl = 0xf4;
+		s->hcyl = 0x2c;
+		s->lcyl = 0xf4;
 		}
 		s->status = READY_STAT | SEEK_STAT;
 		ide_set_irq(s->bus);
 		break;
-	    case SMART_READ_THRESH:
+	case SMART_READ_THRESH:
 		memset(s->io_buffer, 0, 0x200);
 		s->io_buffer[0] = 0x01; /* smart struct version */
 		for (n=0; n<30; n++) {
-		    if (smart_attributes[n][0] == 0)
+		if (smart_attributes[n][0] == 0)
 			break;
-		    s->io_buffer[2+0+(n*12)] = smart_attributes[n][0];
-		    s->io_buffer[2+1+(n*12)] = smart_attributes[n][4];
+		s->io_buffer[2+0+(n*12)] = smart_attributes[n][0];
+		s->io_buffer[2+1+(n*12)] = smart_attributes[n][4];
 		}
 		for (n=0; n<511; n++) /* checksum */
-		    s->io_buffer[511] += s->io_buffer[n];
+		s->io_buffer[511] += s->io_buffer[n];
 		s->io_buffer[511] = 0x100 - s->io_buffer[511];
 		s->status = READY_STAT | SEEK_STAT;
 		ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
 		ide_set_irq(s->bus);
 		break;
-	    case SMART_READ_DATA:
+	case SMART_READ_DATA:
 		memset(s->io_buffer, 0, 0x200);
 		s->io_buffer[0] = 0x01; /* smart struct version */
 		for (n=0; n<30; n++) {
-		    if (smart_attributes[n][0] == 0)
+		if (smart_attributes[n][0] == 0)
 			break;
-		    s->io_buffer[2+0+(n*12)] = smart_attributes[n][0];
-		    s->io_buffer[2+1+(n*12)] = smart_attributes[n][1];
-		    s->io_buffer[2+3+(n*12)] = smart_attributes[n][2];
-		    s->io_buffer[2+4+(n*12)] = smart_attributes[n][3];
+		s->io_buffer[2+0+(n*12)] = smart_attributes[n][0];
+		s->io_buffer[2+1+(n*12)] = smart_attributes[n][1];
+		s->io_buffer[2+3+(n*12)] = smart_attributes[n][2];
+		s->io_buffer[2+4+(n*12)] = smart_attributes[n][3];
 		}
 		s->io_buffer[362] = 0x02 | (s->smart_autosave?0x80:0x00);
 		if (s->smart_selftest_count == 0) {
-		    s->io_buffer[363] = 0;
+		s->io_buffer[363] = 0;
 		} else {
-		    s->io_buffer[363] = 
+		s->io_buffer[363] =
 			s->smart_selftest_data[3 + 
-					       (s->smart_selftest_count - 1) * 
-					       24];
+					   (s->smart_selftest_count - 1) *
+					   24];
 		}
 		s->io_buffer[364] = 0x20; 
 		s->io_buffer[365] = 0x01; 
@@ -2294,76 +2294,76 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
 		s->io_buffer[374] = 0x01; /* minutes for poll conveyance */
 
 		for (n=0; n<511; n++) 
-		    s->io_buffer[511] += s->io_buffer[n];
+		s->io_buffer[511] += s->io_buffer[n];
 		s->io_buffer[511] = 0x100 - s->io_buffer[511];
 		s->status = READY_STAT | SEEK_STAT;
 		ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
 		ide_set_irq(s->bus);
 		break;
-	    case SMART_READ_LOG:
+	case SMART_READ_LOG:
 		switch (s->sector) {
 		case 0x01: /* summary smart error log */
-		    memset(s->io_buffer, 0, 0x200);
-		    s->io_buffer[0] = 0x01;
-		    s->io_buffer[1] = 0x00; /* no error entries */
-		    s->io_buffer[452] = s->smart_errors & 0xff;
-		    s->io_buffer[453] = (s->smart_errors & 0xff00) >> 8;
+		memset(s->io_buffer, 0, 0x200);
+		s->io_buffer[0] = 0x01;
+		s->io_buffer[1] = 0x00; /* no error entries */
+		s->io_buffer[452] = s->smart_errors & 0xff;
+		s->io_buffer[453] = (s->smart_errors & 0xff00) >> 8;
 
-		    for (n=0; n<511; n++)
+		for (n=0; n<511; n++)
 			s->io_buffer[511] += s->io_buffer[n];
-		    s->io_buffer[511] = 0x100 - s->io_buffer[511];
-		    break;
+		s->io_buffer[511] = 0x100 - s->io_buffer[511];
+		break;
 		case 0x06: /* smart self test log */
-		    memset(s->io_buffer, 0, 0x200);
-		    s->io_buffer[0] = 0x01; 
-		    if (s->smart_selftest_count == 0) {
+		memset(s->io_buffer, 0, 0x200);
+		s->io_buffer[0] = 0x01;
+		if (s->smart_selftest_count == 0) {
 			s->io_buffer[508] = 0;
-		    } else {
+		} else {
 			s->io_buffer[508] = s->smart_selftest_count;
 			for (n=2; n<506; n++) 
-			    s->io_buffer[n] = s->smart_selftest_data[n];
-		    }		    
-		    for (n=0; n<511; n++)
+			s->io_buffer[n] = s->smart_selftest_data[n];
+		}
+		for (n=0; n<511; n++)
 			s->io_buffer[511] += s->io_buffer[n];
-		    s->io_buffer[511] = 0x100 - s->io_buffer[511];
-		    break;
+		s->io_buffer[511] = 0x100 - s->io_buffer[511];
+		break;
 		default:
-		    goto abort_cmd;
+		goto abort_cmd;
 		}
 		s->status = READY_STAT | SEEK_STAT;
 		ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
 		ide_set_irq(s->bus);
 		break;
-	    case SMART_EXECUTE_OFFLINE:
+	case SMART_EXECUTE_OFFLINE:
 		switch (s->sector) {
 		case 0: /* off-line routine */
 		case 1: /* short self test */
 		case 2: /* extended self test */
-		    s->smart_selftest_count++;
-		    if(s->smart_selftest_count > 21)
+		s->smart_selftest_count++;
+		if(s->smart_selftest_count > 21)
 			s->smart_selftest_count = 0;
-		    n = 2 + (s->smart_selftest_count - 1) * 24;
-		    s->smart_selftest_data[n] = s->sector;
-		    s->smart_selftest_data[n+1] = 0x00; /* OK and finished */
-		    s->smart_selftest_data[n+2] = 0x34; /* hour count lsb */
-		    s->smart_selftest_data[n+3] = 0x12; /* hour count msb */
-		    s->status = READY_STAT | SEEK_STAT;
-		    ide_set_irq(s->bus);
-		    break;
+		n = 2 + (s->smart_selftest_count - 1) * 24;
+		s->smart_selftest_data[n] = s->sector;
+		s->smart_selftest_data[n+1] = 0x00; /* OK and finished */
+		s->smart_selftest_data[n+2] = 0x34; /* hour count lsb */
+		s->smart_selftest_data[n+3] = 0x12; /* hour count msb */
+		s->status = READY_STAT | SEEK_STAT;
+		ide_set_irq(s->bus);
+		break;
 		default:
-		    goto abort_cmd;
+		goto abort_cmd;
 		}
 		break;
-	    default:
+	default:
 		goto abort_cmd;
-	    }
-	    break;
-        default:
-        abort_cmd:
-            ide_abort_command(s);
-            ide_set_irq(s->bus);
-            break;
-        }
+	}
+	break;
+    default:
+    abort_cmd:
+        ide_abort_command(s);
+        ide_set_irq(s->bus);
+        break;
+    }
 }
 
 uint32_t ide_ioport_read(void *opaque, uint32_t addr1)
commit 7cff87ff6ab117799e32e42c2e4dc4c0588e583a
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Dec 14 01:34:33 2010 +0100

    ide: split ide command interpretation off
    
    The ATA command interpretation code can be used for PATA and SATA
    interfaces alike. So let's split it out into a separate function.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/ide/core.c b/hw/ide/core.c
index 430350f..ac4ee71 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -1791,9 +1791,6 @@ static void ide_clear_hob(IDEBus *bus)
 void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 {
     IDEBus *bus = opaque;
-    IDEState *s;
-    int n;
-    int lba48 = 0;
 
 #ifdef DEBUG_IDE
     printf("IDE: write addr=0x%x val=0x%02x\n", addr, val);
@@ -1854,17 +1851,29 @@ void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
     default:
     case 7:
         /* command */
+        ide_exec_cmd(bus, val);
+        break;
+    }
+}
+
+
+void ide_exec_cmd(IDEBus *bus, uint32_t val)
+{
+    IDEState *s;
+    int n;
+    int lba48 = 0;
+
 #if defined(DEBUG_IDE)
         printf("ide: CMD=%02x\n", val);
 #endif
         s = idebus_active_if(bus);
         /* ignore commands to non existant slave */
         if (s != bus->ifs && !s->bs)
-            break;
+            return;
 
         /* Only DEVICE RESET is allowed while BSY or/and DRQ are set */
         if ((s->status & (BUSY_STAT|DRQ_STAT)) && val != WIN_DEVICE_RESET)
-            break;
+            return;
 
         switch(val) {
         case WIN_IDENTIFY:
@@ -2355,7 +2364,6 @@ void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
             ide_set_irq(s->bus);
             break;
         }
-    }
 }
 
 uint32_t ide_ioport_read(void *opaque, uint32_t addr1)
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index 71af66f..029c76c 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -567,6 +567,8 @@ void ide_init2_with_non_qdev_drives(IDEBus *bus, DriveInfo *hd0,
                                     DriveInfo *hd1, qemu_irq irq);
 void ide_init_ioport(IDEBus *bus, int iobase, int iobase2);
 
+void ide_exec_cmd(IDEBus *bus, uint32_t val);
+
 /* hw/ide/qdev.c */
 void ide_bus_new(IDEBus *idebus, DeviceState *dev, int bus_id);
 IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive);
commit 1da7cfbd0117eeb0aa29b187bb01426d9290e8ab
Author: Jes Sorensen <Jes.Sorensen at redhat.com>
Date:   Thu Dec 9 14:17:25 2010 +0100

    qemu-img.c: Clean up handling of image size in img_create()
    
    This cleans up the handling of image size in img_create() by parsing
    the value early, and then only setting it once if a value has been
    added as the last argument to the command line.
    
    Signed-off-by: Jes Sorensen <Jes.Sorensen at redhat.com>
    Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/qemu-img.c b/qemu-img.c
index 52282e3..1d936ed 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -282,6 +282,7 @@ static int add_old_style_options(const char *fmt, QEMUOptionParameter *list,
 static int img_create(int argc, char **argv)
 {
     int c, ret = 0;
+    uint64_t img_size = -1;
     const char *fmt = "raw";
     const char *base_fmt = NULL;
     const char *filename;
@@ -330,6 +331,20 @@ static int img_create(int argc, char **argv)
     }
     filename = argv[optind++];
 
+    /* Get image size, if specified */
+    if (optind < argc) {
+        ssize_t sval;
+        sval = strtosz_suffix(argv[optind++], NULL, STRTOSZ_DEFSUFFIX_B);
+        if (sval < 0) {
+            error("Invalid image size specified! You may use k, M, G or "
+                  "T suffixes for ");
+            error("kilobytes, megabytes, gigabytes and terabytes.");
+            ret = -1;
+            goto out;
+        }
+        img_size = (uint64_t)sval;
+    }
+
     if (options && !strcmp(options, "?")) {
         ret = print_block_option_help(filename, fmt);
         goto out;
@@ -357,7 +372,8 @@ static int img_create(int argc, char **argv)
 
     /* Create parameter list with default values */
     param = parse_option_parameters("", create_options, param);
-    set_option_parameter_int(param, BLOCK_OPT_SIZE, -1);
+
+    set_option_parameter_int(param, BLOCK_OPT_SIZE, img_size);
 
     /* Parse -o options */
     if (options) {
@@ -369,11 +385,6 @@ static int img_create(int argc, char **argv)
         }
     }
 
-    /* Add size to parameters */
-    if (optind < argc) {
-        set_option_parameter(param, BLOCK_OPT_SIZE, argv[optind++]);
-    }
-
     /* Add old-style options to parameters */
     ret = add_old_style_options(fmt, param, base_filename, base_fmt);
     if (ret < 0) {
commit d8427002dc1be0a9337cde3ef505ee6e57718675
Author: Jes Sorensen <Jes.Sorensen at redhat.com>
Date:   Thu Dec 9 14:17:24 2010 +0100

    Introduce strtosz_suffix()
    
    This introduces strtosz_suffix() which allows the caller to specify a
    default suffix in case the non default of MB is wanted.
    
    strtosz() is kept as a wrapper for strtosz_suffix() which keeps it's
    current default of MB.
    
    Signed-off-by: Jes Sorensen <Jes.Sorensen at redhat.com>
    Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/cutils.c b/cutils.c
index 28089aa..7984bc1 100644
--- a/cutils.c
+++ b/cutils.c
@@ -291,10 +291,10 @@ int fcntl_setfl(int fd, int flag)
  * value must be terminated by whitespace, ',' or '\0'. Return -1 on
  * error.
  */
-ssize_t strtosz(const char *nptr, char **end)
+ssize_t strtosz_suffix(const char *nptr, char **end, const char default_suffix)
 {
     ssize_t retval = -1;
-    char *endptr, c;
+    char *endptr, c, d;
     int mul_required = 0;
     double val, mul, integral, fraction;
 
@@ -313,10 +313,16 @@ ssize_t strtosz(const char *nptr, char **end)
      * part of a multi token argument.
      */
     c = *endptr;
+    d = c;
     if (isspace(c) || c == '\0' || c == ',') {
         c = 0;
+        if (default_suffix) {
+            d = default_suffix;
+        } else {
+            d = c;
+        }
     }
-    switch (c) {
+    switch (d) {
     case 'B':
     case 'b':
         mul = 1;
@@ -371,3 +377,8 @@ fail:
 
     return retval;
 }
+
+ssize_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 de82c2e..1ed32e5 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -149,7 +149,14 @@ time_t mktimegm(struct tm *tm);
 int qemu_fls(int i);
 int qemu_fdatasync(int fd);
 int fcntl_setfl(int fd, int flag);
+
+#define STRTOSZ_DEFSUFFIX_TB	'T'
+#define STRTOSZ_DEFSUFFIX_GB	'G'
+#define STRTOSZ_DEFSUFFIX_MB	'M'
+#define STRTOSZ_DEFSUFFIX_KB	'K'
+#define STRTOSZ_DEFSUFFIX_B	'B'
 ssize_t strtosz(const char *nptr, char **end);
+ssize_t strtosz_suffix(const char *nptr, char **end, const char default_suffix);
 
 /* path.c */
 void init_paths(const char *prefix);
commit df2dbb4a508ebea7bcacff3f07caecbae969d528
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Thu Dec 2 16:54:13 2010 +0000

    block: Fix the use of protocols in backing files
    
    Backing filenames may contain a protocol.  The code currently doesn't
    consider this case and produces filenames that embed "<protocol>:".
    Don't combine filenames if the backing filename contains a protocol.
    
    Based on an earlier patch by Anthony Liguori <aliguori at us.ibm.com>.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index 65fce80..b4aaf41 100644
--- a/block.c
+++ b/block.c
@@ -611,10 +611,18 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
         BlockDriver *back_drv = NULL;
 
         bs->backing_hd = bdrv_new("");
-        path_combine(backing_filename, sizeof(backing_filename),
-                     filename, bs->backing_file);
-        if (bs->backing_format[0] != '\0')
+
+        if (path_has_protocol(bs->backing_file)) {
+            pstrcpy(backing_filename, sizeof(backing_filename),
+                    bs->backing_file);
+        } else {
+            path_combine(backing_filename, sizeof(backing_filename),
+                         filename, bs->backing_file);
+        }
+
+        if (bs->backing_format[0] != '\0') {
             back_drv = bdrv_find_format(bs->backing_format);
+        }
 
         /* backing files always opened read-only */
         back_flags =
commit 9e0b22f4f2c4122bb3544bb44fb7ce2fd7964c12
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Thu Dec 9 11:53:00 2010 +0000

    block: Introduce path_has_protocol() function
    
    The bdrv_find_protocol() function returns NULL if an unknown protocol
    name is given.  It returns the "file" protocol when the filename
    contains no protocol at all.  This makes it difficult to distinguish
    between paths which contain a protocol and those which do not.
    
    Factor out a helper function that tests whether or not a filename has a
    protocol.  The next patch makes use of this function.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index e7a986c..65fce80 100644
--- a/block.c
+++ b/block.c
@@ -70,6 +70,39 @@ static BlockDriverState *bs_snapshots;
 /* If non-zero, use only whitelisted block drivers */
 static int use_bdrv_whitelist;
 
+#ifdef _WIN32
+static int is_windows_drive_prefix(const char *filename)
+{
+    return (((filename[0] >= 'a' && filename[0] <= 'z') ||
+             (filename[0] >= 'A' && filename[0] <= 'Z')) &&
+            filename[1] == ':');
+}
+
+int is_windows_drive(const char *filename)
+{
+    if (is_windows_drive_prefix(filename) &&
+        filename[2] == '\0')
+        return 1;
+    if (strstart(filename, "\\\\.\\", NULL) ||
+        strstart(filename, "//./", NULL))
+        return 1;
+    return 0;
+}
+#endif
+
+/* check if the path starts with "<protocol>:" */
+static int path_has_protocol(const char *path)
+{
+#ifdef _WIN32
+    if (is_windows_drive(path) ||
+        is_windows_drive_prefix(path)) {
+        return 0;
+    }
+#endif
+
+    return strchr(path, ':') != NULL;
+}
+
 int path_is_absolute(const char *path)
 {
     const char *p;
@@ -244,26 +277,6 @@ void get_tmp_filename(char *filename, int size)
 }
 #endif
 
-#ifdef _WIN32
-static int is_windows_drive_prefix(const char *filename)
-{
-    return (((filename[0] >= 'a' && filename[0] <= 'z') ||
-             (filename[0] >= 'A' && filename[0] <= 'Z')) &&
-            filename[1] == ':');
-}
-
-int is_windows_drive(const char *filename)
-{
-    if (is_windows_drive_prefix(filename) &&
-        filename[2] == '\0')
-        return 1;
-    if (strstart(filename, "\\\\.\\", NULL) ||
-        strstart(filename, "//./", NULL))
-        return 1;
-    return 0;
-}
-#endif
-
 /*
  * Detect host devices. By convention, /dev/cdrom[N] is always
  * recognized as a host CDROM.
@@ -307,16 +320,11 @@ BlockDriver *bdrv_find_protocol(const char *filename)
         return drv1;
     }
 
-#ifdef _WIN32
-     if (is_windows_drive(filename) ||
-         is_windows_drive_prefix(filename))
-         return bdrv_find_format("file");
-#endif
-
-    p = strchr(filename, ':');
-    if (!p) {
+    if (!path_has_protocol(filename)) {
         return bdrv_find_format("file");
     }
+    p = strchr(filename, ':');
+    assert(p != NULL);
     len = p - filename;
     if (len > sizeof(protocol) - 1)
         len = sizeof(protocol) - 1;
commit 0fc0f1fa7f86e9f1d480c6508191ca90ac10b32c
Author: Ryan Harper <ryanh at us.ibm.com>
Date:   Wed Dec 8 10:05:00 2010 -0600

    blockdev: check dinfo ptr before using
    
    If a user decides to punish a guest by revoking its block device via
    drive_del, and subsequently also attempts to remove the pci device
    backing it, and the device is using blockdev_auto_del() then we get a
    segfault when we attempt to access dinfo->auto_del.[1]
    
    The fix is to check if drive_get_by_blockdev() actually returns a valid
    dinfo pointer or not.
    
    1. (qemu) pci_add auto storage file=images/test01.raw,if=virtio,id=block1,snapshot=on
       (qemu) drive_del block1
       (qemu) pci_del 5
       *segfault*
    
    Signed-off-by: Ryan Harper <ryanh at us.ibm.com>
    Tested-by: Luiz Capitulino <lcapitulino at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/blockdev.c b/blockdev.c
index f6ac439..3b3b82d 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -30,14 +30,16 @@ void blockdev_mark_auto_del(BlockDriverState *bs)
 {
     DriveInfo *dinfo = drive_get_by_blockdev(bs);
 
-    dinfo->auto_del = 1;
+    if (dinfo) {
+        dinfo->auto_del = 1;
+    }
 }
 
 void blockdev_auto_del(BlockDriverState *bs)
 {
     DriveInfo *dinfo = drive_get_by_blockdev(bs);
 
-    if (dinfo->auto_del) {
+    if (dinfo && dinfo->auto_del) {
         drive_uninit(dinfo);
     }
 }
commit 9d861fa595c93f22d1d55b723a691531c36c9672
Merge: 4a493c6... 72f24d1...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Dec 17 08:25:17 2010 -0600

    Merge remote branch 'arm/for-anthony' into staging

commit 4a493c6fac4db5d9094906a1e9b6d19c1dfff1ed
Merge: fef3957... 5eeaad5...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Dec 17 08:23:53 2010 -0600

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

commit fef395782d76fa497bfc89cea741173706669b2e
Merge: 2e44928... 3a019b6...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Dec 17 08:23:05 2010 -0600

    Merge remote branch 'qmp/for-anthony' into staging

commit 2e44928e3c1b9425c17d0786f7d9139871bba43f
Merge: b254b0d... 3867142...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Dec 17 08:22:31 2010 -0600

    Merge remote branch 'jvrao/for-anthony' into staging

commit b254b0d15d48efc3bd43ae535158ded3c1519257
Merge: 36888c6... 513691b...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Dec 17 08:21:29 2010 -0600

    Merge remote branch 'mst/for_anthony' into staging

commit 5eeaad5a57b94d26747ed8a96fab69494baef75d
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Tue Dec 7 09:35:56 2010 +0000

    qemu-img: Fail creation if backing format is invalid
    
    The qemu-img create command should check the backing format to ensure
    only image files with valid backing formats are created.  By checking in
    qemu-img.c we can print a useful error message.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/qemu-img.c b/qemu-img.c
index c5a173c..52282e3 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -288,6 +288,7 @@ static int img_create(int argc, char **argv)
     const char *base_filename = NULL;
     BlockDriver *drv, *proto_drv;
     QEMUOptionParameter *param = NULL, *create_options = NULL;
+    QEMUOptionParameter *backing_fmt = NULL;
     char *options = NULL;
 
     for(;;) {
@@ -379,14 +380,22 @@ static int img_create(int argc, char **argv)
         goto out;
     }
 
+    backing_fmt = get_option_parameter(param, BLOCK_OPT_BACKING_FMT);
+    if (backing_fmt && backing_fmt->value.s) {
+        if (!bdrv_find_format(backing_fmt->value.s)) {
+            error("Unknown backing file format '%s'",
+                  backing_fmt->value.s);
+            ret = -1;
+            goto out;
+        }
+    }
+
     // The size for the image must always be specified, with one exception:
     // If we are using a backing file, we can obtain the size from there
     if (get_option_parameter(param, BLOCK_OPT_SIZE)->value.n == -1) {
 
         QEMUOptionParameter *backing_file =
             get_option_parameter(param, BLOCK_OPT_BACKING_FILE);
-        QEMUOptionParameter *backing_fmt =
-            get_option_parameter(param, BLOCK_OPT_BACKING_FMT);
 
         if (backing_file && backing_file->value.s) {
             BlockDriverState *bs;
@@ -395,14 +404,7 @@ static int img_create(int argc, char **argv)
             char buf[32];
 
             if (backing_fmt && backing_fmt->value.s) {
-                 if (bdrv_find_format(backing_fmt->value.s)) {
-                     fmt = backing_fmt->value.s;
-                } else {
-                     error("Unknown backing file format '%s'",
-                        backing_fmt->value.s);
-                     ret = -1;
-                     goto out;
-                }
+                fmt = backing_fmt->value.s;
             }
 
             bs = bdrv_new_open(backing_file->value.s, fmt, BDRV_O_FLAGS);
commit a87a6721db3975c93798b6fd6fa42996e9aa695a
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Tue Dec 7 09:35:55 2010 +0000

    qemu-img: Free option parameter lists in img_create()
    
    Free option parameter lists in the img_create() error return path.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/qemu-img.c b/qemu-img.c
index d146d8c..c5a173c 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -428,8 +428,6 @@ static int img_create(int argc, char **argv)
     puts("");
 
     ret = bdrv_create(drv, filename, param);
-    free_option_parameters(create_options);
-    free_option_parameters(param);
 
     if (ret < 0) {
         if (ret == -ENOTSUP) {
@@ -441,6 +439,8 @@ static int img_create(int argc, char **argv)
         }
     }
 out:
+    free_option_parameters(create_options);
+    free_option_parameters(param);
     if (ret) {
         return 1;
     }
commit 0e72e753c226b2d6711ca5edc1d956b810fefbcf
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Tue Dec 7 09:35:54 2010 +0000

    qemu-option: Fix parse_option_parameters() documentation typo
    
    Yoda said, "list is the templace is".  Fix this.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/qemu-option.c b/qemu-option.c
index e380fc1..65db542 100644
--- a/qemu-option.c
+++ b/qemu-option.c
@@ -394,8 +394,8 @@ QEMUOptionParameter *append_option_parameters(QEMUOptionParameter *dest,
 /*
  * Parses a parameter string (param) into an option list (dest).
  *
- * list is the templace is. If dest is NULL, a new copy of list is created for
- * it. If list is NULL, this function fails.
+ * list is the template option list. If dest is NULL, a new copy of list is
+ * created. If list is NULL, this function fails.
  *
  * A parameter string consists of one or more parameters, separated by commas.
  * Each parameter consists of its name and possibly of a value. In the latter
commit 898c257ba8b611a01bbcd1a88836a5d217ca9568
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Tue Dec 7 09:35:53 2010 +0000

    qemu-option: Don't reinvent append_option_parameters()
    
    parse_option_parameters() may need to create a new option parameter list
    from a template list.  Use append_option_parameters() instead of
    duplicating the code.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/qemu-option.c b/qemu-option.c
index 1f8f41a..e380fc1 100644
--- a/qemu-option.c
+++ b/qemu-option.c
@@ -416,20 +416,13 @@ QEMUOptionParameter *parse_option_parameters(const char *param,
     char value[256];
     char *param_delim, *value_delim;
     char next_delim;
-    size_t num_options;
 
     if (list == NULL) {
         return NULL;
     }
 
     if (dest == NULL) {
-        // Count valid options
-        num_options = count_option_parameters(list);
-
-        // Create a copy of the option list to fill in values
-        dest = qemu_mallocz((num_options + 1) * sizeof(QEMUOptionParameter));
-        allocated = dest;
-        memcpy(dest, list, (num_options + 1) * sizeof(QEMUOptionParameter));
+        dest = allocated = append_option_parameters(NULL, list);
     }
 
     while (*param) {
commit eec77d9e712bd4157a4e1c0b5a9249d168add738
Author: Jes Sorensen <Jes.Sorensen at redhat.com>
Date:   Tue Dec 7 17:44:34 2010 +0100

    qemu-img: Deprecate obsolete -6 and -e options
    
    If -6 or -e is specified, an error message is printed and we exit. It
    does not print help() to avoid the error message getting lost in the
    noise.
    
    Signed-off-by: Jes Sorensen <Jes.Sorensen at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block_int.h b/block_int.h
index 0a0e47d..6b3b098 100644
--- a/block_int.h
+++ b/block_int.h
@@ -29,7 +29,6 @@
 #include "qemu-queue.h"
 
 #define BLOCK_FLAG_ENCRYPT	1
-#define BLOCK_FLAG_COMPRESS	2
 #define BLOCK_FLAG_COMPAT6	4
 
 #define BLOCK_OPT_SIZE          "size"
diff --git a/qemu-img.c b/qemu-img.c
index 5b6e648..d146d8c 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -261,21 +261,9 @@ fail:
 }
 
 static int add_old_style_options(const char *fmt, QEMUOptionParameter *list,
-    int flags, const char *base_filename, const char *base_fmt)
+                                 const char *base_filename,
+                                 const char *base_fmt)
 {
-    if (flags & BLOCK_FLAG_ENCRYPT) {
-        if (set_option_parameter(list, BLOCK_OPT_ENCRYPT, "on")) {
-            error("Encryption not supported for file format '%s'", fmt);
-            return -1;
-        }
-    }
-    if (flags & BLOCK_FLAG_COMPAT6) {
-        if (set_option_parameter(list, BLOCK_OPT_COMPAT6, "on")) {
-            error("VMDK version 6 not supported for file format '%s'", fmt);
-            return -1;
-        }
-    }
-
     if (base_filename) {
         if (set_option_parameter(list, BLOCK_OPT_BACKING_FILE, base_filename)) {
             error("Backing file not supported for file format '%s'", fmt);
@@ -293,7 +281,7 @@ static int add_old_style_options(const char *fmt, QEMUOptionParameter *list,
 
 static int img_create(int argc, char **argv)
 {
-    int c, ret = 0, flags;
+    int c, ret = 0;
     const char *fmt = "raw";
     const char *base_fmt = NULL;
     const char *filename;
@@ -302,7 +290,6 @@ static int img_create(int argc, char **argv)
     QEMUOptionParameter *param = NULL, *create_options = NULL;
     char *options = NULL;
 
-    flags = 0;
     for(;;) {
         c = getopt(argc, argv, "F:b:f:he6o:");
         if (c == -1) {
@@ -323,11 +310,13 @@ static int img_create(int argc, char **argv)
             fmt = optarg;
             break;
         case 'e':
-            flags |= BLOCK_FLAG_ENCRYPT;
-            break;
+            error("qemu-img: option -e is deprecated, please use \'-o "
+                  "encryption\' instead!");
+            return 1;
         case '6':
-            flags |= BLOCK_FLAG_COMPAT6;
-            break;
+            error("qemu-img: option -6 is deprecated, please use \'-o "
+                  "compat6\' instead!");
+            return 1;
         case 'o':
             options = optarg;
             break;
@@ -385,7 +374,7 @@ static int img_create(int argc, char **argv)
     }
 
     /* Add old-style options to parameters */
-    ret = add_old_style_options(fmt, param, flags, base_filename, base_fmt);
+    ret = add_old_style_options(fmt, param, base_filename, base_fmt);
     if (ret < 0) {
         goto out;
     }
@@ -674,7 +663,7 @@ static int compare_sectors(const uint8_t *buf1, const uint8_t *buf2, int n,
 
 static int img_convert(int argc, char **argv)
 {
-    int c, ret = 0, n, n1, bs_n, bs_i, flags, cluster_size, cluster_sectors;
+    int c, ret = 0, n, n1, bs_n, bs_i, compress, cluster_size, cluster_sectors;
     const char *fmt, *out_fmt, *out_baseimg, *out_filename;
     BlockDriver *drv, *proto_drv;
     BlockDriverState **bs = NULL, *out_bs = NULL;
@@ -691,7 +680,7 @@ static int img_convert(int argc, char **argv)
     fmt = NULL;
     out_fmt = "raw";
     out_baseimg = NULL;
-    flags = 0;
+    compress = 0;
     for(;;) {
         c = getopt(argc, argv, "f:O:B:s:hce6o:");
         if (c == -1) {
@@ -712,14 +701,16 @@ static int img_convert(int argc, char **argv)
             out_baseimg = optarg;
             break;
         case 'c':
-            flags |= BLOCK_FLAG_COMPRESS;
+            compress = 1;
             break;
         case 'e':
-            flags |= BLOCK_FLAG_ENCRYPT;
-            break;
+            error("qemu-img: option -e is deprecated, please use \'-o "
+                  "encryption\' instead!");
+            return 1;
         case '6':
-            flags |= BLOCK_FLAG_COMPAT6;
-            break;
+            error("qemu-img: option -6 is deprecated, please use \'-o "
+                  "compat6\' instead!");
+            return 1;
         case 'o':
             options = optarg;
             break;
@@ -806,7 +797,7 @@ static int img_convert(int argc, char **argv)
     }
 
     set_option_parameter_int(param, BLOCK_OPT_SIZE, total_sectors * 512);
-    ret = add_old_style_options(out_fmt, param, flags, out_baseimg, NULL);
+    ret = add_old_style_options(out_fmt, param, out_baseimg, NULL);
     if (ret < 0) {
         goto out;
     }
@@ -818,7 +809,7 @@ static int img_convert(int argc, char **argv)
     }
 
     /* Check if compression is supported */
-    if (flags & BLOCK_FLAG_COMPRESS) {
+    if (compress) {
         QEMUOptionParameter *encryption =
             get_option_parameter(param, BLOCK_OPT_ENCRYPT);
 
@@ -860,7 +851,7 @@ static int img_convert(int argc, char **argv)
     bdrv_get_geometry(bs[0], &bs_sectors);
     buf = qemu_malloc(IO_BUF_SIZE);
 
-    if (flags & BLOCK_FLAG_COMPRESS) {
+    if (compress) {
         ret = bdrv_get_info(out_bs, &bdi);
         if (ret < 0) {
             error("could not get block driver info");
commit f27aaf4b531bc0eb4f3e1f7accf4931cae36db0d
Author: Christian Brunner <chb at muc.de>
Date:   Mon Dec 6 20:53:01 2010 +0100

    ceph/rbd block driver for qemu-kvm
    
    RBD is an block driver for the distributed file system Ceph
    (http://ceph.newdream.net/). This driver uses librados (which is part
    of the Ceph server) for direct access to the Ceph object store and is
    running entirely in userspace (Yehuda also wrote a driver for the
    linux kernel, that can be used to access rbd volumes as a block
    device).
    
    Signed-off-by: Yehuda Sadeh <yehuda at hq.newdream.net>
    Signed-off-by: Christian Brunner <chb at muc.de>
    Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/Makefile.objs b/Makefile.objs
index cebb945..b677eb8 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -24,6 +24,7 @@ block-nested-y += parallels.o nbd.o blkdebug.o sheepdog.o blkverify.o
 block-nested-$(CONFIG_WIN32) += raw-win32.o
 block-nested-$(CONFIG_POSIX) += raw-posix.o
 block-nested-$(CONFIG_CURL) += curl.o
+block-nested-$(CONFIG_RBD) += rbd.o
 
 block-obj-y +=  $(addprefix block/, $(block-nested-y))
 
diff --git a/block/rbd.c b/block/rbd.c
new file mode 100644
index 0000000..249a590
--- /dev/null
+++ b/block/rbd.c
@@ -0,0 +1,1059 @@
+/*
+ * QEMU Block driver for RADOS (Ceph)
+ *
+ * Copyright (C) 2010 Christian Brunner <chb at muc.de>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "qemu-error.h"
+
+#include "rbd_types.h"
+#include "block_int.h"
+
+#include <rados/librados.h>
+
+
+
+/*
+ * When specifying the image filename use:
+ *
+ * rbd:poolname/devicename
+ *
+ * poolname must be the name of an existing rados pool
+ *
+ * devicename is the basename for all objects used to
+ * emulate the raw device.
+ *
+ * Metadata information (image size, ...) is stored in an
+ * object with the name "devicename.rbd".
+ *
+ * The raw device is split into 4MB sized objects by default.
+ * The sequencenumber is encoded in a 12 byte long hex-string,
+ * and is attached to the devicename, separated by a dot.
+ * e.g. "devicename.1234567890ab"
+ *
+ */
+
+#define OBJ_MAX_SIZE (1UL << OBJ_DEFAULT_OBJ_ORDER)
+
+typedef struct RBDAIOCB {
+    BlockDriverAIOCB common;
+    QEMUBH *bh;
+    int ret;
+    QEMUIOVector *qiov;
+    char *bounce;
+    int write;
+    int64_t sector_num;
+    int aiocnt;
+    int error;
+    struct BDRVRBDState *s;
+    int cancelled;
+} RBDAIOCB;
+
+typedef struct RADOSCB {
+    int rcbid;
+    RBDAIOCB *acb;
+    struct BDRVRBDState *s;
+    int done;
+    int64_t segsize;
+    char *buf;
+    int ret;
+} RADOSCB;
+
+#define RBD_FD_READ 0
+#define RBD_FD_WRITE 1
+
+typedef struct BDRVRBDState {
+    int fds[2];
+    rados_pool_t pool;
+    rados_pool_t header_pool;
+    char name[RBD_MAX_OBJ_NAME_SIZE];
+    char block_name[RBD_MAX_BLOCK_NAME_SIZE];
+    uint64_t size;
+    uint64_t objsize;
+    int qemu_aio_count;
+    int event_reader_pos;
+    RADOSCB *event_rcb;
+} BDRVRBDState;
+
+typedef struct rbd_obj_header_ondisk RbdHeader1;
+
+static void rbd_aio_bh_cb(void *opaque);
+
+static int rbd_next_tok(char *dst, int dst_len,
+                        char *src, char delim,
+                        const char *name,
+                        char **p)
+{
+    int l;
+    char *end;
+
+    *p = NULL;
+
+    if (delim != '\0') {
+        end = strchr(src, delim);
+        if (end) {
+            *p = end + 1;
+            *end = '\0';
+        }
+    }
+    l = strlen(src);
+    if (l >= dst_len) {
+        error_report("%s too long", name);
+        return -EINVAL;
+    } else if (l == 0) {
+        error_report("%s too short", name);
+        return -EINVAL;
+    }
+
+    pstrcpy(dst, dst_len, src);
+
+    return 0;
+}
+
+static int rbd_parsename(const char *filename,
+                         char *pool, int pool_len,
+                         char *snap, int snap_len,
+                         char *name, int name_len)
+{
+    const char *start;
+    char *p, *buf;
+    int ret;
+
+    if (!strstart(filename, "rbd:", &start)) {
+        return -EINVAL;
+    }
+
+    buf = qemu_strdup(start);
+    p = buf;
+
+    ret = rbd_next_tok(pool, pool_len, p, '/', "pool name", &p);
+    if (ret < 0 || !p) {
+        ret = -EINVAL;
+        goto done;
+    }
+    ret = rbd_next_tok(name, name_len, p, '@', "object name", &p);
+    if (ret < 0) {
+        goto done;
+    }
+    if (!p) {
+        *snap = '\0';
+        goto done;
+    }
+
+    ret = rbd_next_tok(snap, snap_len, p, '\0', "snap name", &p);
+
+done:
+    qemu_free(buf);
+    return ret;
+}
+
+static int create_tmap_op(uint8_t op, const char *name, char **tmap_desc)
+{
+    uint32_t len = strlen(name);
+    uint32_t len_le = cpu_to_le32(len);
+    /* total_len = encoding op + name + empty buffer */
+    uint32_t total_len = 1 + (sizeof(uint32_t) + len) + sizeof(uint32_t);
+    uint8_t *desc = NULL;
+
+    desc = qemu_malloc(total_len);
+
+    *tmap_desc = (char *)desc;
+
+    *desc = op;
+    desc++;
+    memcpy(desc, &len_le, sizeof(len_le));
+    desc += sizeof(len_le);
+    memcpy(desc, name, len);
+    desc += len;
+    len = 0; /* no need for endian conversion for 0 */
+    memcpy(desc, &len, sizeof(len));
+    desc += sizeof(len);
+
+    return (char *)desc - *tmap_desc;
+}
+
+static void free_tmap_op(char *tmap_desc)
+{
+    qemu_free(tmap_desc);
+}
+
+static int rbd_register_image(rados_pool_t pool, const char *name)
+{
+    char *tmap_desc;
+    const char *dir = RBD_DIRECTORY;
+    int ret;
+
+    ret = create_tmap_op(CEPH_OSD_TMAP_SET, name, &tmap_desc);
+    if (ret < 0) {
+        return ret;
+    }
+
+    ret = rados_tmap_update(pool, dir, tmap_desc, ret);
+    free_tmap_op(tmap_desc);
+
+    return ret;
+}
+
+static int touch_rbd_info(rados_pool_t pool, const char *info_oid)
+{
+    int r = rados_write(pool, info_oid, 0, NULL, 0);
+    if (r < 0) {
+        return r;
+    }
+    return 0;
+}
+
+static int rbd_assign_bid(rados_pool_t pool, uint64_t *id)
+{
+    uint64_t out[1];
+    const char *info_oid = RBD_INFO;
+
+    *id = 0;
+
+    int r = touch_rbd_info(pool, info_oid);
+    if (r < 0) {
+        return r;
+    }
+
+    r = rados_exec(pool, info_oid, "rbd", "assign_bid", NULL,
+                   0, (char *)out, sizeof(out));
+    if (r < 0) {
+        return r;
+    }
+
+    le64_to_cpus(out);
+    *id = out[0];
+
+    return 0;
+}
+
+static int rbd_create(const char *filename, QEMUOptionParameter *options)
+{
+    int64_t bytes = 0;
+    int64_t objsize;
+    uint64_t size;
+    time_t mtime;
+    uint8_t obj_order = RBD_DEFAULT_OBJ_ORDER;
+    char pool[RBD_MAX_SEG_NAME_SIZE];
+    char n[RBD_MAX_SEG_NAME_SIZE];
+    char name[RBD_MAX_OBJ_NAME_SIZE];
+    char snap_buf[RBD_MAX_SEG_NAME_SIZE];
+    char *snap = NULL;
+    RbdHeader1 header;
+    rados_pool_t p;
+    uint64_t bid;
+    uint32_t hi, lo;
+    int ret;
+
+    if (rbd_parsename(filename,
+                      pool, sizeof(pool),
+                      snap_buf, sizeof(snap_buf),
+                      name, sizeof(name)) < 0) {
+        return -EINVAL;
+    }
+    if (snap_buf[0] != '\0') {
+        snap = snap_buf;
+    }
+
+    snprintf(n, sizeof(n), "%s%s", name, RBD_SUFFIX);
+
+    /* Read out options */
+    while (options && options->name) {
+        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
+            bytes = options->value.n;
+        } else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) {
+            if (options->value.n) {
+                objsize = options->value.n;
+                if ((objsize - 1) & objsize) {    /* not a power of 2? */
+                    error_report("obj size needs to be power of 2");
+                    return -EINVAL;
+                }
+                if (objsize < 4096) {
+                    error_report("obj size too small");
+                    return -EINVAL;
+                }
+		obj_order = ffs(objsize) - 1;
+            }
+        }
+        options++;
+    }
+
+    memset(&header, 0, sizeof(header));
+    pstrcpy(header.text, sizeof(header.text), RBD_HEADER_TEXT);
+    pstrcpy(header.signature, sizeof(header.signature), RBD_HEADER_SIGNATURE);
+    pstrcpy(header.version, sizeof(header.version), RBD_HEADER_VERSION);
+    header.image_size = cpu_to_le64(bytes);
+    header.options.order = obj_order;
+    header.options.crypt_type = RBD_CRYPT_NONE;
+    header.options.comp_type = RBD_COMP_NONE;
+    header.snap_seq = 0;
+    header.snap_count = 0;
+
+    if (rados_initialize(0, NULL) < 0) {
+        error_report("error initializing");
+        return -EIO;
+    }
+
+    if (rados_open_pool(pool, &p)) {
+        error_report("error opening pool %s", pool);
+        rados_deinitialize();
+        return -EIO;
+    }
+
+    /* check for existing rbd header file */
+    ret = rados_stat(p, n, &size, &mtime);
+    if (ret == 0) {
+        ret=-EEXIST;
+        goto done;
+    }
+
+    ret = rbd_assign_bid(p, &bid);
+    if (ret < 0) {
+        error_report("failed assigning block id");
+        rados_deinitialize();
+        return -EIO;
+    }
+    hi = bid >> 32;
+    lo = bid & 0xFFFFFFFF;
+    snprintf(header.block_name, sizeof(header.block_name), "rb.%x.%x", hi, lo);
+
+    /* create header file */
+    ret = rados_write(p, n, 0, (const char *)&header, sizeof(header));
+    if (ret < 0) {
+        goto done;
+    }
+
+    ret = rbd_register_image(p, name);
+done:
+    rados_close_pool(p);
+    rados_deinitialize();
+
+    return ret;
+}
+
+/*
+ * This aio completion is being called from rbd_aio_event_reader() and
+ * runs in qemu context. It schedules a bh, but just in case the aio
+ * was not cancelled before.
+ */
+static void rbd_complete_aio(RADOSCB *rcb)
+{
+    RBDAIOCB *acb = rcb->acb;
+    int64_t r;
+
+    acb->aiocnt--;
+
+    if (acb->cancelled) {
+        if (!acb->aiocnt) {
+            qemu_vfree(acb->bounce);
+            qemu_aio_release(acb);
+        }
+        goto done;
+    }
+
+    r = rcb->ret;
+
+    if (acb->write) {
+        if (r < 0) {
+            acb->ret = r;
+            acb->error = 1;
+        } else if (!acb->error) {
+            acb->ret += rcb->segsize;
+        }
+    } else {
+        if (r == -ENOENT) {
+            memset(rcb->buf, 0, rcb->segsize);
+            if (!acb->error) {
+                acb->ret += rcb->segsize;
+            }
+        } else if (r < 0) {
+	    memset(rcb->buf, 0, rcb->segsize);
+            acb->ret = r;
+            acb->error = 1;
+        } else if (r < rcb->segsize) {
+            memset(rcb->buf + r, 0, rcb->segsize - r);
+            if (!acb->error) {
+                acb->ret += rcb->segsize;
+            }
+        } else if (!acb->error) {
+            acb->ret += r;
+        }
+    }
+    /* Note that acb->bh can be NULL in case where the aio was cancelled */
+    if (!acb->aiocnt) {
+        acb->bh = qemu_bh_new(rbd_aio_bh_cb, acb);
+        qemu_bh_schedule(acb->bh);
+    }
+done:
+    qemu_free(rcb);
+}
+
+/*
+ * aio fd read handler. It runs in the qemu context and calls the
+ * completion handling of completed rados aio operations.
+ */
+static void rbd_aio_event_reader(void *opaque)
+{
+    BDRVRBDState *s = opaque;
+
+    ssize_t ret;
+
+    do {
+        char *p = (char *)&s->event_rcb;
+
+        /* now read the rcb pointer that was sent from a non qemu thread */
+        if ((ret = read(s->fds[RBD_FD_READ], p + s->event_reader_pos,
+                        sizeof(s->event_rcb) - s->event_reader_pos)) > 0) {
+            if (ret > 0) {
+                s->event_reader_pos += ret;
+                if (s->event_reader_pos == sizeof(s->event_rcb)) {
+                    s->event_reader_pos = 0;
+                    rbd_complete_aio(s->event_rcb);
+                    s->qemu_aio_count --;
+                }
+            }
+        }
+    } while (ret < 0 && errno == EINTR);
+}
+
+static int rbd_aio_flush_cb(void *opaque)
+{
+    BDRVRBDState *s = opaque;
+
+    return (s->qemu_aio_count > 0);
+}
+
+
+static int rbd_set_snapc(rados_pool_t pool, const char *snap, RbdHeader1 *header)
+{
+    uint32_t snap_count = le32_to_cpu(header->snap_count);
+    rados_snap_t *snaps = NULL;
+    rados_snap_t seq;
+    uint32_t i;
+    uint64_t snap_names_len = le64_to_cpu(header->snap_names_len);
+    int r;
+    rados_snap_t snapid = 0;
+
+    if (snap_count) {
+        const char *header_snap = (const char *)&header->snaps[snap_count];
+        const char *end = header_snap + snap_names_len;
+        snaps = qemu_malloc(sizeof(rados_snap_t) * header->snap_count);
+
+        for (i=0; i < snap_count; i++) {
+            snaps[i] = le64_to_cpu(header->snaps[i].id);
+
+            if (snap && strcmp(snap, header_snap) == 0) {
+                snapid = snaps[i];
+            }
+
+            header_snap += strlen(header_snap) + 1;
+            if (header_snap > end) {
+                error_report("bad header, snapshot list broken");
+            }
+        }
+    }
+
+    if (snap && !snapid) {
+        error_report("snapshot not found");
+        qemu_free(snaps);
+        return -ENOENT;
+    }
+    seq = le32_to_cpu(header->snap_seq);
+
+    r = rados_set_snap_context(pool, seq, snaps, snap_count);
+
+    rados_set_snap(pool, snapid);
+
+    qemu_free(snaps);
+
+    return r;
+}
+
+#define BUF_READ_START_LEN    4096
+
+static int rbd_read_header(BDRVRBDState *s, char **hbuf)
+{
+    char *buf = NULL;
+    char n[RBD_MAX_SEG_NAME_SIZE];
+    uint64_t len = BUF_READ_START_LEN;
+    int r;
+
+    snprintf(n, sizeof(n), "%s%s", s->name, RBD_SUFFIX);
+
+    buf = qemu_malloc(len);
+
+    r = rados_read(s->header_pool, n, 0, buf, len);
+    if (r < 0) {
+        goto failed;
+    }
+
+    if (r < len) {
+        goto done;
+    }
+
+    qemu_free(buf);
+    buf = qemu_malloc(len);
+
+    r = rados_stat(s->header_pool, n, &len, NULL);
+    if (r < 0) {
+        goto failed;
+    }
+
+    r = rados_read(s->header_pool, n, 0, buf, len);
+    if (r < 0) {
+        goto failed;
+    }
+
+done:
+    *hbuf = buf;
+    return 0;
+
+failed:
+    qemu_free(buf);
+    return r;
+}
+
+static int rbd_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    BDRVRBDState *s = bs->opaque;
+    RbdHeader1 *header;
+    char pool[RBD_MAX_SEG_NAME_SIZE];
+    char snap_buf[RBD_MAX_SEG_NAME_SIZE];
+    char *snap = NULL;
+    char *hbuf = NULL;
+    int r;
+
+    if (rbd_parsename(filename, pool, sizeof(pool),
+                      snap_buf, sizeof(snap_buf),
+                      s->name, sizeof(s->name)) < 0) {
+        return -EINVAL;
+    }
+    if (snap_buf[0] != '\0') {
+        snap = snap_buf;
+    }
+
+    if ((r = rados_initialize(0, NULL)) < 0) {
+        error_report("error initializing");
+        return r;
+    }
+
+    if ((r = rados_open_pool(pool, &s->pool))) {
+        error_report("error opening pool %s", pool);
+        rados_deinitialize();
+        return r;
+    }
+
+    if ((r = rados_open_pool(pool, &s->header_pool))) {
+        error_report("error opening pool %s", pool);
+        rados_deinitialize();
+        return r;
+    }
+
+    if ((r = rbd_read_header(s, &hbuf)) < 0) {
+        error_report("error reading header from %s", s->name);
+        goto failed;
+    }
+
+    if (memcmp(hbuf + 64, RBD_HEADER_SIGNATURE, 4)) {
+        error_report("Invalid header signature");
+        r = -EMEDIUMTYPE;
+        goto failed;
+    }
+
+    if (memcmp(hbuf + 68, RBD_HEADER_VERSION, 8)) {
+        error_report("Unknown image version");
+        r = -EMEDIUMTYPE;
+        goto failed;
+    }
+
+    header = (RbdHeader1 *) hbuf;
+    s->size = le64_to_cpu(header->image_size);
+    s->objsize = 1ULL << header->options.order;
+    memcpy(s->block_name, header->block_name, sizeof(header->block_name));
+
+    r = rbd_set_snapc(s->pool, snap, header);
+    if (r < 0) {
+        error_report("failed setting snap context: %s", strerror(-r));
+        goto failed;
+    }
+
+    bs->read_only = (snap != NULL);
+
+    s->event_reader_pos = 0;
+    r = qemu_pipe(s->fds);
+    if (r < 0) {
+        error_report("error opening eventfd");
+        goto failed;
+    }
+    fcntl(s->fds[0], F_SETFL, O_NONBLOCK);
+    fcntl(s->fds[1], F_SETFL, O_NONBLOCK);
+    qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], rbd_aio_event_reader, NULL,
+        rbd_aio_flush_cb, NULL, s);
+
+    qemu_free(hbuf);
+
+    return 0;
+
+failed:
+    qemu_free(hbuf);
+
+    rados_close_pool(s->header_pool);
+    rados_close_pool(s->pool);
+    rados_deinitialize();
+    return r;
+}
+
+static void rbd_close(BlockDriverState *bs)
+{
+    BDRVRBDState *s = bs->opaque;
+
+    close(s->fds[0]);
+    close(s->fds[1]);
+    qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], NULL , NULL, NULL, NULL,
+        NULL);
+
+    rados_close_pool(s->header_pool);
+    rados_close_pool(s->pool);
+    rados_deinitialize();
+}
+
+/*
+ * Cancel aio. Since we don't reference acb in a non qemu threads,
+ * it is safe to access it here.
+ */
+static void rbd_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+    RBDAIOCB *acb = (RBDAIOCB *) blockacb;
+    acb->cancelled = 1;
+}
+
+static AIOPool rbd_aio_pool = {
+    .aiocb_size = sizeof(RBDAIOCB),
+    .cancel = rbd_aio_cancel,
+};
+
+/*
+ * This is the callback function for rados_aio_read and _write
+ *
+ * Note: this function is being called from a non qemu thread so
+ * we need to be careful about what we do here. Generally we only
+ * write to the block notification pipe, and do the rest of the
+ * io completion handling from rbd_aio_event_reader() which
+ * runs in a qemu context.
+ */
+static void rbd_finish_aiocb(rados_completion_t c, RADOSCB *rcb)
+{
+    int ret;
+    rcb->ret = rados_aio_get_return_value(c);
+    rados_aio_release(c);
+    while (1) {
+        fd_set wfd;
+        int fd = rcb->s->fds[RBD_FD_WRITE];
+
+        /* send the rcb pointer to the qemu thread that is responsible
+           for the aio completion. Must do it in a qemu thread context */
+        ret = write(fd, (void *)&rcb, sizeof(rcb));
+        if (ret >= 0) {
+            break;
+        }
+        if (errno == EINTR) {
+            continue;
+	}
+        if (errno != EAGAIN) {
+            break;
+	}
+
+        FD_ZERO(&wfd);
+        FD_SET(fd, &wfd);
+        do {
+            ret = select(fd + 1, NULL, &wfd, NULL, NULL);
+        } while (ret < 0 && errno == EINTR);
+    }
+
+    if (ret < 0) {
+        error_report("failed writing to acb->s->fds\n");
+        qemu_free(rcb);
+    }
+}
+
+/* Callback when all queued rados_aio requests are complete */
+
+static void rbd_aio_bh_cb(void *opaque)
+{
+    RBDAIOCB *acb = opaque;
+
+    if (!acb->write) {
+        qemu_iovec_from_buffer(acb->qiov, acb->bounce, acb->qiov->size);
+    }
+    qemu_vfree(acb->bounce);
+    acb->common.cb(acb->common.opaque, (acb->ret > 0 ? 0 : acb->ret));
+    qemu_bh_delete(acb->bh);
+    acb->bh = NULL;
+
+    qemu_aio_release(acb);
+}
+
+static BlockDriverAIOCB *rbd_aio_rw_vector(BlockDriverState *bs,
+                                           int64_t sector_num,
+                                           QEMUIOVector *qiov,
+                                           int nb_sectors,
+                                           BlockDriverCompletionFunc *cb,
+                                           void *opaque, int write)
+{
+    RBDAIOCB *acb;
+    RADOSCB *rcb;
+    rados_completion_t c;
+    char n[RBD_MAX_SEG_NAME_SIZE];
+    int64_t segnr, segoffs, segsize, last_segnr;
+    int64_t off, size;
+    char *buf;
+
+    BDRVRBDState *s = bs->opaque;
+
+    acb = qemu_aio_get(&rbd_aio_pool, bs, cb, opaque);
+    acb->write = write;
+    acb->qiov = qiov;
+    acb->bounce = qemu_blockalign(bs, qiov->size);
+    acb->aiocnt = 0;
+    acb->ret = 0;
+    acb->error = 0;
+    acb->s = s;
+    acb->cancelled = 0;
+    acb->bh = NULL;
+
+    if (write) {
+        qemu_iovec_to_buffer(acb->qiov, acb->bounce);
+    }
+
+    buf = acb->bounce;
+
+    off = sector_num * BDRV_SECTOR_SIZE;
+    size = nb_sectors * BDRV_SECTOR_SIZE;
+    segnr = off / s->objsize;
+    segoffs = off % s->objsize;
+    segsize = s->objsize - segoffs;
+
+    last_segnr = ((off + size - 1) / s->objsize);
+    acb->aiocnt = (last_segnr - segnr) + 1;
+
+    s->qemu_aio_count += acb->aiocnt; /* All the RADOSCB */
+
+    while (size > 0) {
+        if (size < segsize) {
+            segsize = size;
+        }
+
+        snprintf(n, sizeof(n), "%s.%012" PRIx64, s->block_name,
+                 segnr);
+
+        rcb = qemu_malloc(sizeof(RADOSCB));
+        rcb->done = 0;
+        rcb->acb = acb;
+        rcb->segsize = segsize;
+        rcb->buf = buf;
+        rcb->s = acb->s;
+
+        if (write) {
+            rados_aio_create_completion(rcb, NULL,
+                                        (rados_callback_t) rbd_finish_aiocb,
+                                        &c);
+            rados_aio_write(s->pool, n, segoffs, buf, segsize, c);
+        } else {
+            rados_aio_create_completion(rcb,
+                                        (rados_callback_t) rbd_finish_aiocb,
+                                        NULL, &c);
+            rados_aio_read(s->pool, n, segoffs, buf, segsize, c);
+        }
+
+        buf += segsize;
+        size -= segsize;
+        segoffs = 0;
+        segsize = s->objsize;
+        segnr++;
+    }
+
+    return &acb->common;
+}
+
+static BlockDriverAIOCB *rbd_aio_readv(BlockDriverState * bs,
+                                       int64_t sector_num, QEMUIOVector * qiov,
+                                       int nb_sectors,
+                                       BlockDriverCompletionFunc * cb,
+                                       void *opaque)
+{
+    return rbd_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
+}
+
+static BlockDriverAIOCB *rbd_aio_writev(BlockDriverState * bs,
+                                        int64_t sector_num, QEMUIOVector * qiov,
+                                        int nb_sectors,
+                                        BlockDriverCompletionFunc * cb,
+                                        void *opaque)
+{
+    return rbd_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
+}
+
+static int rbd_getinfo(BlockDriverState * bs, BlockDriverInfo * bdi)
+{
+    BDRVRBDState *s = bs->opaque;
+    bdi->cluster_size = s->objsize;
+    return 0;
+}
+
+static int64_t rbd_getlength(BlockDriverState * bs)
+{
+    BDRVRBDState *s = bs->opaque;
+
+    return s->size;
+}
+
+static int rbd_snap_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
+{
+    BDRVRBDState *s = bs->opaque;
+    char inbuf[512], outbuf[128];
+    uint64_t snap_id;
+    int r;
+    char *p = inbuf;
+    char *end = inbuf + sizeof(inbuf);
+    char n[RBD_MAX_SEG_NAME_SIZE];
+    char *hbuf = NULL;
+    RbdHeader1 *header;
+
+    if (sn_info->name[0] == '\0') {
+        return -EINVAL; /* we need a name for rbd snapshots */
+    }
+
+    /*
+     * rbd snapshots are using the name as the user controlled unique identifier
+     * we can't use the rbd snapid for that purpose, as it can't be set
+     */
+    if (sn_info->id_str[0] != '\0' &&
+        strcmp(sn_info->id_str, sn_info->name) != 0) {
+        return -EINVAL;
+    }
+
+    if (strlen(sn_info->name) >= sizeof(sn_info->id_str)) {
+        return -ERANGE;
+    }
+
+    r = rados_selfmanaged_snap_create(s->header_pool, &snap_id);
+    if (r < 0) {
+        error_report("failed to create snap id: %s", strerror(-r));
+        return r;
+    }
+
+    *(uint32_t *)p = strlen(sn_info->name);
+    cpu_to_le32s((uint32_t *)p);
+    p += sizeof(uint32_t);
+    strncpy(p, sn_info->name, end - p);
+    p += strlen(p);
+    if (p + sizeof(snap_id) > end) {
+        error_report("invalid input parameter");
+        return -EINVAL;
+    }
+
+    *(uint64_t *)p = snap_id;
+    cpu_to_le64s((uint64_t *)p);
+
+    snprintf(n, sizeof(n), "%s%s", s->name, RBD_SUFFIX);
+
+    r = rados_exec(s->header_pool, n, "rbd", "snap_add", inbuf,
+                   sizeof(inbuf), outbuf, sizeof(outbuf));
+    if (r < 0) {
+        error_report("rbd.snap_add execution failed failed: %s", strerror(-r));
+        return r;
+    }
+
+    sprintf(sn_info->id_str, "%s", sn_info->name);
+
+    r = rbd_read_header(s, &hbuf);
+    if (r < 0) {
+        error_report("failed reading header: %s", strerror(-r));
+        return r;
+    }
+
+    header = (RbdHeader1 *) hbuf;
+    r = rbd_set_snapc(s->pool, sn_info->name, header);
+    if (r < 0) {
+        error_report("failed setting snap context: %s", strerror(-r));
+        goto failed;
+    }
+
+    return 0;
+
+failed:
+    qemu_free(header);
+    return r;
+}
+
+static int decode32(char **p, const char *end, uint32_t *v)
+{
+    if (*p + 4 > end) {
+	return -ERANGE;
+    }
+
+    *v = *(uint32_t *)(*p);
+    le32_to_cpus(v);
+    *p += 4;
+    return 0;
+}
+
+static int decode64(char **p, const char *end, uint64_t *v)
+{
+    if (*p + 8 > end) {
+        return -ERANGE;
+    }
+
+    *v = *(uint64_t *)(*p);
+    le64_to_cpus(v);
+    *p += 8;
+    return 0;
+}
+
+static int decode_str(char **p, const char *end, char **s)
+{
+    uint32_t len;
+    int r;
+
+    if ((r = decode32(p, end, &len)) < 0) {
+        return r;
+    }
+
+    *s = qemu_malloc(len + 1);
+    memcpy(*s, *p, len);
+    *p += len;
+    (*s)[len] = '\0';
+
+    return len;
+}
+
+static int rbd_snap_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
+{
+    BDRVRBDState *s = bs->opaque;
+    char n[RBD_MAX_SEG_NAME_SIZE];
+    QEMUSnapshotInfo *sn_info, *sn_tab = NULL;
+    RbdHeader1 *header;
+    char *hbuf = NULL;
+    char *outbuf = NULL, *end, *buf;
+    uint64_t len;
+    uint64_t snap_seq;
+    uint32_t snap_count;
+    int r, i;
+
+    /* read header to estimate how much space we need to read the snap
+     * list */
+    if ((r = rbd_read_header(s, &hbuf)) < 0) {
+        goto done_err;
+    }
+    header = (RbdHeader1 *)hbuf;
+    len = le64_to_cpu(header->snap_names_len);
+    len += 1024; /* should have already been enough, but new snapshots might
+                    already been created since we read the header. just allocate
+                    a bit more, so that in most cases it'll suffice anyway */
+    qemu_free(hbuf);
+
+    snprintf(n, sizeof(n), "%s%s", s->name, RBD_SUFFIX);
+    while (1) {
+        qemu_free(outbuf);
+        outbuf = qemu_malloc(len);
+
+        r = rados_exec(s->header_pool, n, "rbd", "snap_list", NULL, 0,
+                       outbuf, len);
+        if (r < 0) {
+            error_report("rbd.snap_list execution failed failed: %s", strerror(-r));
+            goto done_err;
+        }
+        if (r != len) {
+            break;
+	}
+
+        /* if we're here, we probably raced with some snaps creation */
+        len *= 2;
+    }
+    buf = outbuf;
+    end = buf + len;
+
+    if ((r = decode64(&buf, end, &snap_seq)) < 0) {
+        goto done_err;
+    }
+    if ((r = decode32(&buf, end, &snap_count)) < 0) {
+        goto done_err;
+    }
+
+    sn_tab = qemu_mallocz(snap_count * sizeof(QEMUSnapshotInfo));
+    for (i = 0; i < snap_count; i++) {
+        uint64_t id, image_size;
+        char *snap_name;
+
+        if ((r = decode64(&buf, end, &id)) < 0) {
+            goto done_err;
+        }
+        if ((r = decode64(&buf, end, &image_size)) < 0) {
+            goto done_err;
+        }
+        if ((r = decode_str(&buf, end, &snap_name)) < 0) {
+            goto done_err;
+        }
+
+        sn_info = sn_tab + i;
+        pstrcpy(sn_info->id_str, sizeof(sn_info->id_str), snap_name);
+        pstrcpy(sn_info->name, sizeof(sn_info->name), snap_name);
+        qemu_free(snap_name);
+
+        sn_info->vm_state_size = image_size;
+        sn_info->date_sec = 0;
+        sn_info->date_nsec = 0;
+        sn_info->vm_clock_nsec = 0;
+    }
+    *psn_tab = sn_tab;
+    qemu_free(outbuf);
+    return snap_count;
+done_err:
+    qemu_free(sn_tab);
+    qemu_free(outbuf);
+    return r;
+}
+
+static QEMUOptionParameter rbd_create_options[] = {
+    {
+     .name = BLOCK_OPT_SIZE,
+     .type = OPT_SIZE,
+     .help = "Virtual disk size"
+    },
+    {
+     .name = BLOCK_OPT_CLUSTER_SIZE,
+     .type = OPT_SIZE,
+     .help = "RBD object size"
+    },
+    {NULL}
+};
+
+static BlockDriver bdrv_rbd = {
+    .format_name        = "rbd",
+    .instance_size      = sizeof(BDRVRBDState),
+    .bdrv_file_open     = rbd_open,
+    .bdrv_close         = rbd_close,
+    .bdrv_create        = rbd_create,
+    .bdrv_get_info      = rbd_getinfo,
+    .create_options     = rbd_create_options,
+    .bdrv_getlength     = rbd_getlength,
+    .protocol_name      = "rbd",
+
+    .bdrv_aio_readv     = rbd_aio_readv,
+    .bdrv_aio_writev    = rbd_aio_writev,
+
+    .bdrv_snapshot_create = rbd_snap_create,
+    .bdrv_snapshot_list = rbd_snap_list,
+};
+
+static void bdrv_rbd_init(void)
+{
+    bdrv_register(&bdrv_rbd);
+}
+
+block_init(bdrv_rbd_init);
diff --git a/block/rbd_types.h b/block/rbd_types.h
new file mode 100644
index 0000000..f4cca99
--- /dev/null
+++ b/block/rbd_types.h
@@ -0,0 +1,71 @@
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2004-2010 Sage Weil <sage at newdream.net>
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.LIB.
+ *
+ */
+
+#ifndef CEPH_RBD_TYPES_H
+#define CEPH_RBD_TYPES_H
+
+
+/*
+ * rbd image 'foo' consists of objects
+ *   foo.rbd      - image metadata
+ *   foo.00000000
+ *   foo.00000001
+ *   ...          - data
+ */
+
+#define RBD_SUFFIX              ".rbd"
+#define RBD_DIRECTORY           "rbd_directory"
+#define RBD_INFO                "rbd_info"
+
+#define RBD_DEFAULT_OBJ_ORDER   22   /* 4MB */
+
+#define RBD_MAX_OBJ_NAME_SIZE   96
+#define RBD_MAX_BLOCK_NAME_SIZE 24
+#define RBD_MAX_SEG_NAME_SIZE   128
+
+#define RBD_COMP_NONE           0
+#define RBD_CRYPT_NONE          0
+
+#define RBD_HEADER_TEXT         "<<< Rados Block Device Image >>>\n"
+#define RBD_HEADER_SIGNATURE    "RBD"
+#define RBD_HEADER_VERSION      "001.005"
+
+struct rbd_info {
+    uint64_t max_id;
+} __attribute__ ((packed));
+
+struct rbd_obj_snap_ondisk {
+    uint64_t id;
+    uint64_t image_size;
+} __attribute__((packed));
+
+struct rbd_obj_header_ondisk {
+    char text[40];
+    char block_name[RBD_MAX_BLOCK_NAME_SIZE];
+    char signature[4];
+    char version[8];
+    struct {
+        uint8_t order;
+        uint8_t crypt_type;
+        uint8_t comp_type;
+        uint8_t unused;
+    } __attribute__((packed)) options;
+    uint64_t image_size;
+    uint64_t snap_seq;
+    uint32_t snap_count;
+    uint32_t reserved;
+    uint64_t snap_names_len;
+    struct rbd_obj_snap_ondisk snaps[0];
+} __attribute__((packed));
+
+
+#endif
diff --git a/configure b/configure
index 2917874..62defc4 100755
--- a/configure
+++ b/configure
@@ -332,6 +332,7 @@ zero_malloc=""
 trace_backend="nop"
 trace_file="trace"
 spice=""
+rbd=""
 
 # OS specific
 if check_define __linux__ ; then
@@ -741,6 +742,10 @@ for opt do
   ;;
   --*dir)
   ;;
+  --disable-rbd) rbd="no"
+  ;;
+  --enable-rbd) rbd="yes"
+  ;;
   *) echo "ERROR: unknown option $opt"; show_help="yes"
   ;;
   esac
@@ -934,6 +939,7 @@ echo "  --trace-file=NAME        Full PATH,NAME of file to store traces"
 echo "                           Default:trace-<pid>"
 echo "  --disable-spice          disable spice"
 echo "  --enable-spice           enable spice"
+echo "  --enable-rbd             enable building the rados block device (rbd)"
 echo ""
 echo "NOTE: The object files are built at the place where configure is launched"
 exit 1
@@ -1746,6 +1752,48 @@ if test "$mingw32" != yes -a "$pthread" = no; then
 fi
 
 ##########################################
+# rbd probe
+if test "$rbd" != "no" ; then
+  cat > $TMPC <<EOF
+#include <stdio.h>
+#include <rados/librados.h>
+int main(void) { rados_initialize(0, NULL); return 0; }
+EOF
+  rbd_libs="-lrados -lcrypto"
+  if compile_prog "" "$rbd_libs" ; then
+    librados_too_old=no
+    cat > $TMPC <<EOF
+#include <stdio.h>
+#include <rados/librados.h>
+#ifndef CEPH_OSD_TMAP_SET
+#error missing CEPH_OSD_TMAP_SET
+#endif
+int main(void) {
+    int (*func)(const rados_pool_t pool, uint64_t *snapid) = rados_selfmanaged_snap_create;
+    rados_initialize(0, NULL);
+    return 0;
+}
+EOF
+    if compile_prog "" "$rbd_libs" ; then
+      rbd=yes
+      libs_tools="$rbd_libs $libs_tools"
+      libs_softmmu="$rbd_libs $libs_softmmu"
+    else
+      rbd=no
+      librados_too_old=yes
+    fi
+  else
+    if test "$rbd" = "yes" ; then
+      feature_not_found "rados block device"
+    fi
+    rbd=no
+  fi
+  if test "$librados_too_old" = "yes" ; then
+    echo "-> Your librados version is too old - upgrade needed to have rbd support"
+  fi
+fi
+
+##########################################
 # linux-aio probe
 
 if test "$linux_aio" != "no" ; then
@@ -2354,6 +2402,7 @@ echo "vhost-net support $vhost_net"
 echo "Trace backend     $trace_backend"
 echo "Trace output file $trace_file-<pid>"
 echo "spice support     $spice"
+echo "rbd support       $rbd"
 
 if test $sdl_too_old = "yes"; then
 echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -2627,6 +2676,9 @@ echo "CONFIG_UNAME_RELEASE=\"$uname_release\"" >> $config_host_mak
 if test "$zero_malloc" = "yes" ; then
   echo "CONFIG_ZERO_MALLOC=y" >> $config_host_mak
 fi
+if test "$rbd" = "yes" ; then
+  echo "CONFIG_RBD=y" >> $config_host_mak
+fi
 
 # USB host support
 case "$usb" in
commit 2a81998a1af40cbc13a5ab1030ec7f05d13d742c
Author: Jes Sorensen <Jes.Sorensen at redhat.com>
Date:   Mon Dec 6 17:08:31 2010 +0100

    Make error handling more consistent in img_create() and img_resize()
    
    Signed-off-by: Jes Sorensen <Jes.Sorensen at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/qemu-img.c b/qemu-img.c
index 6fd52e9..5b6e648 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -349,13 +349,15 @@ static int img_create(int argc, char **argv)
     drv = bdrv_find_format(fmt);
     if (!drv) {
         error("Unknown file format '%s'", fmt);
-        return 1;
+        ret = -1;
+        goto out;
     }
 
     proto_drv = bdrv_find_protocol(filename);
     if (!proto_drv) {
         error("Unknown protocol '%s'", filename);
-        return 1;
+        ret = -1;
+        goto out;
     }
 
     create_options = append_option_parameters(create_options,
@@ -1492,7 +1494,7 @@ static int img_resize(int argc, char **argv)
     int c, ret, relative;
     const char *filename, *fmt, *size;
     int64_t n, total_size;
-    BlockDriverState *bs;
+    BlockDriverState *bs = NULL;
     QEMUOptionParameter *param;
     QEMUOptionParameter resize_options[] = {
         {
@@ -1544,14 +1546,16 @@ static int img_resize(int argc, char **argv)
     param = parse_option_parameters("", resize_options, NULL);
     if (set_option_parameter(param, BLOCK_OPT_SIZE, size)) {
         /* Error message already printed when size parsing fails */
-        exit(1);
+        ret = -1;
+        goto out;
     }
     n = get_option_parameter(param, BLOCK_OPT_SIZE)->value.n;
     free_option_parameters(param);
 
     bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR);
     if (!bs) {
-        return 1;
+        ret = -1;
+        goto out;
     }
 
     if (relative) {
@@ -1581,7 +1585,9 @@ static int img_resize(int argc, char **argv)
         break;
     }
 out:
-    bdrv_delete(bs);
+    if (bs) {
+        bdrv_delete(bs);
+    }
     if (ret) {
         return 1;
     }
commit ef87394c08f348c95dc831e2e45c488f6466172d
Author: Jes Sorensen <Jes.Sorensen at redhat.com>
Date:   Mon Dec 6 15:25:40 2010 +0100

    Fail if detecting an unknown option
    
    This patch changes qemu-img to exit if an unknown option is detected,
    instead of trying to continue with a set of arguments which may be
    incorrect.
    
    Signed-off-by: Jes Sorensen <Jes.Sorensen at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/qemu-img.c b/qemu-img.c
index cc77048..6fd52e9 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -309,6 +309,7 @@ static int img_create(int argc, char **argv)
             break;
         }
         switch(c) {
+        case '?':
         case 'h':
             help();
             break;
@@ -477,6 +478,7 @@ static int img_check(int argc, char **argv)
             break;
         }
         switch(c) {
+        case '?':
         case 'h':
             help();
             break;
@@ -555,6 +557,7 @@ static int img_commit(int argc, char **argv)
             break;
         }
         switch(c) {
+        case '?':
         case 'h':
             help();
             break;
@@ -693,6 +696,7 @@ static int img_convert(int argc, char **argv)
             break;
         }
         switch(c) {
+        case '?':
         case 'h':
             help();
             break;
@@ -1097,6 +1101,7 @@ static int img_info(int argc, char **argv)
             break;
         }
         switch(c) {
+        case '?':
         case 'h':
             help();
             break;
@@ -1174,6 +1179,7 @@ static int img_snapshot(int argc, char **argv)
             break;
         }
         switch(c) {
+        case '?':
         case 'h':
             help();
             return 0;
@@ -1289,6 +1295,7 @@ static int img_rebase(int argc, char **argv)
             break;
         }
         switch(c) {
+        case '?':
         case 'h':
             help();
             return 0;
@@ -1503,6 +1510,7 @@ static int img_resize(int argc, char **argv)
             break;
         }
         switch(c) {
+        case '?':
         case 'h':
             help();
             break;
commit b8fb60da2d27ad52593bea4ee5fb33a2644ebaa6
Author: Jes Sorensen <Jes.Sorensen at redhat.com>
Date:   Mon Dec 6 15:25:39 2010 +0100

    Fix formatting and missing braces in qemu-img.c
    
    Signed-off-by: Jes Sorensen <Jes.Sorensen at redhat.com>
    Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/qemu-img.c b/qemu-img.c
index 50cfdda..cc77048 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -305,8 +305,9 @@ static int img_create(int argc, char **argv)
     flags = 0;
     for(;;) {
         c = getopt(argc, argv, "F:b:f:he6o:");
-        if (c == -1)
+        if (c == -1) {
             break;
+        }
         switch(c) {
         case 'h':
             help();
@@ -333,8 +334,9 @@ static int img_create(int argc, char **argv)
     }
 
     /* Get the filename */
-    if (optind >= argc)
+    if (optind >= argc) {
         help();
+    }
     filename = argv[optind++];
 
     if (options && !strcmp(options, "?")) {
@@ -471,8 +473,9 @@ static int img_check(int argc, char **argv)
     fmt = NULL;
     for(;;) {
         c = getopt(argc, argv, "f:h");
-        if (c == -1)
+        if (c == -1) {
             break;
+        }
         switch(c) {
         case 'h':
             help();
@@ -482,8 +485,9 @@ static int img_check(int argc, char **argv)
             break;
         }
     }
-    if (optind >= argc)
+    if (optind >= argc) {
         help();
+    }
     filename = argv[optind++];
 
     bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS);
@@ -547,8 +551,9 @@ static int img_commit(int argc, char **argv)
     fmt = NULL;
     for(;;) {
         c = getopt(argc, argv, "f:h");
-        if (c == -1)
+        if (c == -1) {
             break;
+        }
         switch(c) {
         case 'h':
             help();
@@ -558,8 +563,9 @@ static int img_commit(int argc, char **argv)
             break;
         }
     }
-    if (optind >= argc)
+    if (optind >= argc) {
         help();
+    }
     filename = argv[optind++];
 
     bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR);
@@ -683,8 +689,9 @@ static int img_convert(int argc, char **argv)
     flags = 0;
     for(;;) {
         c = getopt(argc, argv, "f:O:B:s:hce6o:");
-        if (c == -1)
+        if (c == -1) {
             break;
+        }
         switch(c) {
         case 'h':
             help();
@@ -717,7 +724,9 @@ static int img_convert(int argc, char **argv)
     }
 
     bs_n = argc - optind - 1;
-    if (bs_n < 1) help();
+    if (bs_n < 1) {
+        help();
+    }
 
     out_filename = argv[argc - 1];
 
@@ -905,8 +914,9 @@ static int img_convert(int argc, char **argv)
             }
             assert (remainder == 0);
 
-            if (n < cluster_sectors)
+            if (n < cluster_sectors) {
                 memset(buf + n * 512, 0, cluster_size - n * 512);
+            }
             if (is_not_zero(buf, cluster_size)) {
                 ret = bdrv_write_compressed(out_bs, sector_num, buf,
                                             cluster_sectors);
@@ -926,12 +936,14 @@ static int img_convert(int argc, char **argv)
         sector_num = 0; // total number of sectors converted so far
         for(;;) {
             nb_sectors = total_sectors - sector_num;
-            if (nb_sectors <= 0)
+            if (nb_sectors <= 0) {
                 break;
-            if (nb_sectors >= (IO_BUF_SIZE / 512))
+            }
+            if (nb_sectors >= (IO_BUF_SIZE / 512)) {
                 n = (IO_BUF_SIZE / 512);
-            else
+            } else {
                 n = nb_sectors;
+            }
 
             while (sector_num - bs_offset >= bs_sectors) {
                 bs_i ++;
@@ -943,8 +955,9 @@ static int img_convert(int argc, char **argv)
                    sector_num, bs_i, bs_offset, bs_sectors); */
             }
 
-            if (n > bs_offset + bs_sectors - sector_num)
+            if (n > bs_offset + bs_sectors - sector_num) {
                 n = bs_offset + bs_sectors - sector_num;
+            }
 
             if (has_zero_init) {
                 /* If the output image is being created as a copy on write image,
@@ -1080,8 +1093,9 @@ static int img_info(int argc, char **argv)
     fmt = NULL;
     for(;;) {
         c = getopt(argc, argv, "f:h");
-        if (c == -1)
+        if (c == -1) {
             break;
+        }
         switch(c) {
         case 'h':
             help();
@@ -1091,8 +1105,9 @@ static int img_info(int argc, char **argv)
             break;
         }
     }
-    if (optind >= argc)
+    if (optind >= argc) {
         help();
+    }
     filename = argv[optind++];
 
     bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_NO_BACKING);
@@ -1103,11 +1118,12 @@ static int img_info(int argc, char **argv)
     bdrv_get_geometry(bs, &total_sectors);
     get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512);
     allocated_size = get_allocated_file_size(filename);
-    if (allocated_size < 0)
+    if (allocated_size < 0) {
         snprintf(dsize_buf, sizeof(dsize_buf), "unavailable");
-    else
+    } else {
         get_human_readable_size(dsize_buf, sizeof(dsize_buf),
                                 allocated_size);
+    }
     printf("image: %s\n"
            "file format: %s\n"
            "virtual size: %s (%" PRId64 " bytes)\n"
@@ -1115,11 +1131,13 @@ static int img_info(int argc, char **argv)
            filename, fmt_name, size_buf,
            (total_sectors * 512),
            dsize_buf);
-    if (bdrv_is_encrypted(bs))
+    if (bdrv_is_encrypted(bs)) {
         printf("encrypted: yes\n");
+    }
     if (bdrv_get_info(bs, &bdi) >= 0) {
-        if (bdi.cluster_size != 0)
+        if (bdi.cluster_size != 0) {
             printf("cluster_size: %d\n", bdi.cluster_size);
+        }
     }
     bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename));
     if (backing_filename[0] != '\0') {
@@ -1152,8 +1170,9 @@ static int img_snapshot(int argc, char **argv)
     /* Parse commandline parameters */
     for(;;) {
         c = getopt(argc, argv, "la:c:d:h");
-        if (c == -1)
+        if (c == -1) {
             break;
+        }
         switch(c) {
         case 'h':
             help();
@@ -1193,8 +1212,9 @@ static int img_snapshot(int argc, char **argv)
         }
     }
 
-    if (optind >= argc)
+    if (optind >= argc) {
         help();
+    }
     filename = argv[optind++];
 
     /* Open the image */
@@ -1218,23 +1238,26 @@ static int img_snapshot(int argc, char **argv)
         sn.date_nsec = tv.tv_usec * 1000;
 
         ret = bdrv_snapshot_create(bs, &sn);
-        if (ret)
+        if (ret) {
             error("Could not create snapshot '%s': %d (%s)",
                 snapshot_name, ret, strerror(-ret));
+        }
         break;
 
     case SNAPSHOT_APPLY:
         ret = bdrv_snapshot_goto(bs, snapshot_name);
-        if (ret)
+        if (ret) {
             error("Could not apply snapshot '%s': %d (%s)",
                 snapshot_name, ret, strerror(-ret));
+        }
         break;
 
     case SNAPSHOT_DELETE:
         ret = bdrv_snapshot_delete(bs, snapshot_name);
-        if (ret)
+        if (ret) {
             error("Could not delete snapshot '%s': %d (%s)",
                 snapshot_name, ret, strerror(-ret));
+        }
         break;
     }
 
@@ -1262,8 +1285,9 @@ static int img_rebase(int argc, char **argv)
 
     for(;;) {
         c = getopt(argc, argv, "uhf:F:b:");
-        if (c == -1)
+        if (c == -1) {
             break;
+        }
         switch(c) {
         case 'h':
             help();
@@ -1283,8 +1307,9 @@ static int img_rebase(int argc, char **argv)
         }
     }
 
-    if ((optind >= argc) || !out_baseimg)
+    if ((optind >= argc) || !out_baseimg) {
         help();
+    }
     filename = argv[optind++];
 
     /*
commit 4ac8aacd954bbc9f3c3006a19cdf13be3caf7ae8
Author: Jes Sorensen <Jes.Sorensen at redhat.com>
Date:   Mon Dec 6 15:25:38 2010 +0100

    Consolidate printing of block driver options
    
    This consolidates the printing of block driver options in
    print_block_option_help() which is called from both img_create() and
    img_convert().
    
    This allows for the "?" detection to be done just after the parsing of
    options and the filename, instead of half way down the codepath of
    these functions.
    
    Signed-off-by: Jes Sorensen <Jes.Sorensen at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/qemu-img.c b/qemu-img.c
index aded72d..50cfdda 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -188,6 +188,33 @@ static int read_password(char *buf, int buf_size)
 }
 #endif
 
+static int print_block_option_help(const char *filename, const char *fmt)
+{
+    BlockDriver *drv, *proto_drv;
+    QEMUOptionParameter *create_options = NULL;
+
+    /* Find driver and parse its options */
+    drv = bdrv_find_format(fmt);
+    if (!drv) {
+        error("Unknown file format '%s'", fmt);
+        return 1;
+    }
+
+    proto_drv = bdrv_find_protocol(filename);
+    if (!proto_drv) {
+        error("Unknown protocol '%s'", filename);
+        return 1;
+    }
+
+    create_options = append_option_parameters(create_options,
+                                              drv->create_options);
+    create_options = append_option_parameters(create_options,
+                                              proto_drv->create_options);
+    print_option_help(create_options);
+    free_option_parameters(create_options);
+    return 0;
+}
+
 static BlockDriverState *bdrv_new_open(const char *filename,
                                        const char *fmt,
                                        int flags)
@@ -310,6 +337,11 @@ static int img_create(int argc, char **argv)
         help();
     filename = argv[optind++];
 
+    if (options && !strcmp(options, "?")) {
+        ret = print_block_option_help(filename, fmt);
+        goto out;
+    }
+
     /* Find driver and parse its options */
     drv = bdrv_find_format(fmt);
     if (!drv) {
@@ -328,11 +360,6 @@ static int img_create(int argc, char **argv)
     create_options = append_option_parameters(create_options,
                                               proto_drv->create_options);
 
-    if (options && !strcmp(options, "?")) {
-        print_option_help(create_options);
-        goto out;
-    }
-
     /* Create parameter list with default values */
     param = parse_option_parameters("", create_options, param);
     set_option_parameter_int(param, BLOCK_OPT_SIZE, -1);
@@ -694,6 +721,11 @@ static int img_convert(int argc, char **argv)
 
     out_filename = argv[argc - 1];
 
+    if (options && !strcmp(options, "?")) {
+        ret = print_block_option_help(out_filename, out_fmt);
+        goto out;
+    }
+
     if (bs_n > 1 && out_baseimg) {
         error("-B makes no sense when concatenating multiple input images");
         ret = -1;
@@ -746,10 +778,6 @@ static int img_convert(int argc, char **argv)
                                               drv->create_options);
     create_options = append_option_parameters(create_options,
                                               proto_drv->create_options);
-    if (options && !strcmp(options, "?")) {
-        print_option_help(create_options);
-        goto out;
-    }
 
     if (options) {
         param = parse_option_parameters(options, create_options, param);
commit 31ca34b8cc2efe1b7e3f726dedb30c450a81abaf
Author: Jes Sorensen <Jes.Sorensen at redhat.com>
Date:   Mon Dec 6 15:25:36 2010 +0100

    img_convert(): Only try to free bs[] entries if bs is valid.
    
    This allows for jumping to 'out:' consistently for error exit.
    
    Signed-off-by: Jes Sorensen <Jes.Sorensen at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/qemu-img.c b/qemu-img.c
index eca99c4..aded72d 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -696,7 +696,8 @@ static int img_convert(int argc, char **argv)
 
     if (bs_n > 1 && out_baseimg) {
         error("-B makes no sense when concatenating multiple input images");
-        return 1;
+        ret = -1;
+        goto out;
     }
         
     bs = qemu_mallocz(bs_n * sizeof(BlockDriverState *));
@@ -974,12 +975,14 @@ out:
     if (out_bs) {
         bdrv_delete(out_bs);
     }
-    for (bs_i = 0; bs_i < bs_n; bs_i++) {
-        if (bs[bs_i]) {
-            bdrv_delete(bs[bs_i]);
+    if (bs) {
+        for (bs_i = 0; bs_i < bs_n; bs_i++) {
+            if (bs[bs_i]) {
+                bdrv_delete(bs[bs_i]);
+            }
         }
+        qemu_free(bs);
     }
-    qemu_free(bs);
     if (ret) {
         return 1;
     }
commit 5bdf61fdd76b5ca7101353abbdbcd1ed692fa9e2
Author: Jes Sorensen <Jes.Sorensen at redhat.com>
Date:   Mon Dec 6 15:25:35 2010 +0100

    Use qemu_mallocz() instead of calloc() in img_convert()
    
    Signed-off-by: Jes Sorensen <Jes.Sorensen at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/qemu-img.c b/qemu-img.c
index fa77ac0..eca99c4 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -699,11 +699,7 @@ static int img_convert(int argc, char **argv)
         return 1;
     }
         
-    bs = calloc(bs_n, sizeof(BlockDriverState *));
-    if (!bs) {
-        error("Out of memory");
-        return 1;
-    }
+    bs = qemu_mallocz(bs_n * sizeof(BlockDriverState *));
 
     total_sectors = 0;
     for (bs_i = 0; bs_i < bs_n; bs_i++) {
@@ -983,7 +979,7 @@ out:
             bdrv_delete(bs[bs_i]);
         }
     }
-    free(bs);
+    qemu_free(bs);
     if (ret) {
         return 1;
     }
commit 236e2376818251382f8811d46503581fde798ea3
Author: Jes Sorensen <Jes.Sorensen at redhat.com>
Date:   Mon Dec 6 15:25:34 2010 +0100

    Add missing tracing to qemu_mallocz()
    
    Signed-off-by: Jes Sorensen <Jes.Sorensen at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/qemu-malloc.c b/qemu-malloc.c
index 28fb05a..b9b3851 100644
--- a/qemu-malloc.c
+++ b/qemu-malloc.c
@@ -64,10 +64,13 @@ void *qemu_realloc(void *ptr, size_t size)
 
 void *qemu_mallocz(size_t size)
 {
+    void *ptr;
     if (!size && !allow_zero_malloc()) {
         abort();
     }
-    return qemu_oom_check(calloc(1, size ? size : 1));
+    ptr = qemu_oom_check(calloc(1, size ? size : 1));
+    trace_qemu_malloc(size, ptr);
+    return ptr;
 }
 
 char *qemu_strdup(const char *str)
commit 16905d717507d3daffa714c7f0fd5403873807b2
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Tue Nov 30 15:14:14 2010 +0000

    block: Make bdrv_create_file() ':' handling consistent
    
    Filenames may start with "<protocol>:" to explicitly use a protocol like
    nbd.  Filenames with unknown protocols are rejected in most of QEMU
    except for bdrv_create_file().  Even if a file with an invalid filename
    can be created, QEMU cannot use it since all the other relevant
    functions reject such paths.  Make bdrv_create_file() consistent.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index 63effd8..e7a986c 100644
--- a/block.c
+++ b/block.c
@@ -215,7 +215,7 @@ int bdrv_create_file(const char* filename, QEMUOptionParameter *options)
 
     drv = bdrv_find_protocol(filename);
     if (drv == NULL) {
-        drv = bdrv_find_format("file");
+        return -ENOENT;
     }
 
     return bdrv_create(drv, filename, options);
commit 36888c6335422f07bbc50bf3443a39f24b90c7c6
Author: Richard W.M. Jones <rjones at redhat.com>
Date:   Fri Sep 24 16:08:06 2010 +0100

    Watchdog: disable watchdog timer when hard-rebooting a guest.
    
    This commit causes the watchdog timer to be reset when a guest is
    hard-rebooted.
    
    The failure case previously was as follows:
    
      (a) guest boots, watchdog is enabled
    
      (b) guest does a reset eg:
            echo 'b' > /proc/sysrq-trigger
        (note that an ordinary /sbin/reboot wouldn't hit this case
        since as the watchdog daemon is shut down, the daemon would
        properly disable the watchdog device)
    
      (c) the reboot takes longer than the remaining time on the
        watchdog
    
      (d) the watchdog therefore fires during the reboot
    
      (e) probably the VM would just reboot again at this point which
        is pretty benign, but it could depend on the action that the
        user had selected for the watchdog
    
    Now we use the qdev reset function to register a reset handler
    which disables the timer.  Note the handler is called _either_
    just after init _or_ when the guest reboots.
    
    In the i6300esb case there is a small refactoring of the code so
    that the device's internal state is now fully restored to defaults
    on a reboot.
    
    Signed-off-by: Richard W.M. Jones <rjones at redhat.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/wdt_i6300esb.c b/hw/wdt_i6300esb.c
index 8443b41..90bf5f6 100644
--- a/hw/wdt_i6300esb.c
+++ b/hw/wdt_i6300esb.c
@@ -149,6 +149,8 @@ static void i6300esb_reset(DeviceState *dev)
 
     i6300esb_disable_timer(d);
 
+    /* NB: Don't change d->previous_reboot_flag in this function. */
+
     d->reboot_enabled = 1;
     d->clock_scale = CLOCK_SCALE_1KHZ;
     d->int_type = INT_TYPE_IRQ;
@@ -159,7 +161,6 @@ static void i6300esb_reset(DeviceState *dev)
     d->timer2_preload = 0xfffff;
     d->stage = 1;
     d->unlock_state = 0;
-    d->previous_reboot_flag = 0;
 }
 
 /* This function is called when the watchdog expires.  Note that
@@ -193,6 +194,7 @@ static void i6300esb_timer_expired(void *vp)
         if (d->reboot_enabled) {
             d->previous_reboot_flag = 1;
             watchdog_perform_action(); /* This reboots, exits, etc */
+            i6300esb_reset(&d->dev.qdev);
         }
 
         /* In "free running mode" we start stage 1 again. */
@@ -409,6 +411,7 @@ static int i6300esb_init(PCIDevice *dev)
     i6300esb_debug("I6300State = %p\n", d);
 
     d->timer = qemu_new_timer(vm_clock, i6300esb_timer_expired, d);
+    d->previous_reboot_flag = 0;
 
     pci_conf = d->dev.config;
     pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
diff --git a/hw/wdt_ib700.c b/hw/wdt_ib700.c
index c34687b..b6235eb 100644
--- a/hw/wdt_ib700.c
+++ b/hw/wdt_ib700.c
@@ -97,6 +97,8 @@ static int wdt_ib700_init(ISADevice *dev)
 {
     IB700State *s = DO_UPCAST(IB700State, dev, dev);
 
+    ib700_debug("watchdog init\n");
+
     s->timer = qemu_new_timer(vm_clock, ib700_timer_expired, s);
     register_ioport_write(0x441, 2, 1, ib700_write_disable_reg, s);
     register_ioport_write(0x443, 2, 1, ib700_write_enable_reg, s);
@@ -104,16 +106,26 @@ static int wdt_ib700_init(ISADevice *dev)
     return 0;
 }
 
+static void wdt_ib700_reset(DeviceState *dev)
+{
+    IB700State *s = DO_UPCAST(IB700State, dev.qdev, dev);
+
+    ib700_debug("watchdog reset\n");
+
+    qemu_del_timer(s->timer);
+}
+
 static WatchdogTimerModel model = {
     .wdt_name = "ib700",
     .wdt_description = "iBASE 700",
 };
 
 static ISADeviceInfo wdt_ib700_info = {
-    .qdev.name = "ib700",
-    .qdev.size = sizeof(IB700State),
-    .qdev.vmsd = &vmstate_ib700,
-    .init      = wdt_ib700_init,
+    .qdev.name  = "ib700",
+    .qdev.size  = sizeof(IB700State),
+    .qdev.vmsd  = &vmstate_ib700,
+    .qdev.reset = wdt_ib700_reset,
+    .init       = wdt_ib700_init,
 };
 
 static void wdt_ib700_register_devices(void)
commit 962630f207a33b7de4316022884b5241e05491cd
Author: Gleb Natapov <gleb at redhat.com>
Date:   Wed Dec 8 13:35:09 2010 +0200

    Pass boot device list to firmware.
    
    Signed-off-by: Gleb Natapov <gleb at redhat.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c
index 957466d..85c8c3c 100644
--- a/hw/fw_cfg.c
+++ b/hw/fw_cfg.c
@@ -53,6 +53,7 @@ struct FWCfgState {
     FWCfgFiles *files;
     uint16_t cur_entry;
     uint32_t cur_offset;
+    Notifier machine_ready;
 };
 
 static void fw_cfg_write(FWCfgState *s, uint8_t value)
@@ -315,6 +316,15 @@ int fw_cfg_add_file(FWCfgState *s,  const char *filename, uint8_t *data,
     return 1;
 }
 
+static void fw_cfg_machine_ready(struct Notifier* n)
+{
+    uint32_t len;
+    FWCfgState *s = container_of(n, FWCfgState, machine_ready);
+    char *bootindex = get_boot_devices_list(&len);
+
+    fw_cfg_add_file(s, "bootorder", (uint8_t*)bootindex, len);
+}
+
 FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
                         target_phys_addr_t ctl_addr, target_phys_addr_t data_addr)
 {
@@ -343,6 +353,10 @@ FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
     fw_cfg_add_i16(s, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
     fw_cfg_add_i16(s, FW_CFG_BOOT_MENU, (uint16_t)boot_menu);
 
+
+    s->machine_ready.notify = fw_cfg_machine_ready;
+    qemu_add_machine_init_done_notifier(&s->machine_ready);
+
     return s;
 }
 
diff --git a/sysemu.h b/sysemu.h
index c42f33a..38a20a3 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -196,4 +196,5 @@ void register_devices(void);
 
 void add_boot_device_path(int32_t bootindex, DeviceState *dev,
                           const char *suffix);
+char *get_boot_devices_list(uint32_t *size);
 #endif
diff --git a/vl.c b/vl.c
index 0d20d26..c4d3fc0 100644
--- a/vl.c
+++ b/vl.c
@@ -736,6 +736,54 @@ void add_boot_device_path(int32_t bootindex, DeviceState *dev,
     QTAILQ_INSERT_TAIL(&fw_boot_order, node, link);
 }
 
+/*
+ * This function returns null terminated string that consist of new line
+ * separated device pathes.
+ *
+ * memory pointed by "size" is assigned total length of the array in bytes
+ *
+ */
+char *get_boot_devices_list(uint32_t *size)
+{
+    FWBootEntry *i;
+    uint32_t total = 0;
+    char *list = NULL;
+
+    QTAILQ_FOREACH(i, &fw_boot_order, link) {
+        char *devpath = NULL, *bootpath;
+        int len;
+
+        if (i->dev) {
+            devpath = qdev_get_fw_dev_path(i->dev);
+            assert(devpath);
+        }
+
+        if (i->suffix && devpath) {
+            bootpath = qemu_malloc(strlen(devpath) + strlen(i->suffix) + 1);
+            sprintf(bootpath, "%s%s", devpath, i->suffix);
+            qemu_free(devpath);
+        } else if (devpath) {
+            bootpath = devpath;
+        } else {
+            bootpath = strdup(i->suffix);
+            assert(bootpath);
+        }
+
+        if (total) {
+            list[total-1] = '\n';
+        }
+        len = strlen(bootpath) + 1;
+        list = qemu_realloc(list, total + len);
+        memcpy(&list[total], bootpath, len);
+        total += len;
+        qemu_free(bootpath);
+    }
+
+    *size = total;
+
+    return list;
+}
+
 static void numa_add(const char *optarg)
 {
     char option[128];
commit 4cab946a4adc3094a846dd3c7ea104abe7bdc5f1
Author: Gleb Natapov <gleb at redhat.com>
Date:   Wed Dec 8 13:35:08 2010 +0200

    Add notifier that will be called when machine is fully created.
    
    Action that depends on fully initialized device model should register
    with this notifier chain.
    
    Signed-off-by: Gleb Natapov <gleb at redhat.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/sysemu.h b/sysemu.h
index 48f8eee..c42f33a 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -60,6 +60,8 @@ void qemu_system_reset(void);
 void qemu_add_exit_notifier(Notifier *notify);
 void qemu_remove_exit_notifier(Notifier *notify);
 
+void qemu_add_machine_init_done_notifier(Notifier *notify);
+
 void do_savevm(Monitor *mon, const QDict *qdict);
 int load_vmstate(const char *name);
 void do_delvm(Monitor *mon, const QDict *qdict);
diff --git a/vl.c b/vl.c
index 844d6a5..0d20d26 100644
--- a/vl.c
+++ b/vl.c
@@ -254,6 +254,9 @@ static void *boot_set_opaque;
 static NotifierList exit_notifiers =
     NOTIFIER_LIST_INITIALIZER(exit_notifiers);
 
+static NotifierList machine_init_done_notifiers =
+    NOTIFIER_LIST_INITIALIZER(machine_init_done_notifiers);
+
 int kvm_allowed = 0;
 uint32_t xen_domid;
 enum xen_mode xen_mode = XEN_EMULATE;
@@ -1782,6 +1785,16 @@ static void qemu_run_exit_notifiers(void)
     notifier_list_notify(&exit_notifiers);
 }
 
+void qemu_add_machine_init_done_notifier(Notifier *notify)
+{
+    notifier_list_add(&machine_init_done_notifiers, notify);
+}
+
+static void qemu_run_machine_init_done_notifiers(void)
+{
+    notifier_list_notify(&machine_init_done_notifiers);
+}
+
 static const QEMUOption *lookup_opt(int argc, char **argv,
                                     const char **poptarg, int *poptind)
 {
@@ -3028,6 +3041,8 @@ int main(int argc, char **argv, char **envp)
     }
 
     qemu_register_reset((void *)qbus_reset_all, sysbus_get_default());
+    qemu_run_machine_init_done_notifiers();
+
     qemu_system_reset();
     if (loadvm) {
         if (load_vmstate(loadvm) < 0) {
commit 2e55e84282c545aeab8f5c9dd52a8073deaf3dbc
Author: Gleb Natapov <gleb at redhat.com>
Date:   Wed Dec 8 13:35:07 2010 +0200

    Add bootindex for option roms.
    
    Extend -option-rom command to have additional parameter ,bootindex=.
    
    Signed-off-by: Gleb Natapov <gleb at redhat.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/loader.c b/hw/loader.c
index 1e98326..eb198f6 100644
--- a/hw/loader.c
+++ b/hw/loader.c
@@ -107,7 +107,7 @@ int load_image_targphys(const char *filename,
 
     size = get_image_size(filename);
     if (size > 0)
-        rom_add_file_fixed(filename, addr);
+        rom_add_file_fixed(filename, addr, -1);
     return size;
 }
 
@@ -557,10 +557,11 @@ static void rom_insert(Rom *rom)
 }
 
 int rom_add_file(const char *file, const char *fw_dir,
-                 target_phys_addr_t addr)
+                 target_phys_addr_t addr, int32_t bootindex)
 {
     Rom *rom;
     int rc, fd = -1;
+    char devpath[100];
 
     rom = qemu_mallocz(sizeof(*rom));
     rom->name = qemu_strdup(file);
@@ -605,7 +606,12 @@ int rom_add_file(const char *file, const char *fw_dir,
         snprintf(fw_file_name, sizeof(fw_file_name), "%s/%s", rom->fw_dir,
                  basename);
         fw_cfg_add_file(fw_cfg, fw_file_name, rom->data, rom->romsize);
+        snprintf(devpath, sizeof(devpath), "/rom@%s", fw_file_name);
+    } else {
+        snprintf(devpath, sizeof(devpath), "/rom@" TARGET_FMT_plx, addr);
     }
+
+    add_boot_device_path(bootindex, NULL, devpath);
     return 0;
 
 err:
@@ -635,12 +641,12 @@ int rom_add_blob(const char *name, const void *blob, size_t len,
 
 int rom_add_vga(const char *file)
 {
-    return rom_add_file(file, "vgaroms", 0);
+    return rom_add_file(file, "vgaroms", 0, -1);
 }
 
-int rom_add_option(const char *file)
+int rom_add_option(const char *file, int32_t bootindex)
 {
-    return rom_add_file(file, "genroms", 0);
+    return rom_add_file(file, "genroms", 0, bootindex);
 }
 
 static void rom_reset(void *unused)
diff --git a/hw/loader.h b/hw/loader.h
index 1f82fc5..fc6bdff 100644
--- a/hw/loader.h
+++ b/hw/loader.h
@@ -22,7 +22,7 @@ void pstrcpy_targphys(const char *name,
 
 
 int rom_add_file(const char *file, const char *fw_dir,
-                 target_phys_addr_t addr);
+                 target_phys_addr_t addr, int32_t bootindex);
 int rom_add_blob(const char *name, const void *blob, size_t len,
                  target_phys_addr_t addr);
 int rom_load_all(void);
@@ -31,8 +31,8 @@ int rom_copy(uint8_t *dest, target_phys_addr_t addr, size_t size);
 void *rom_ptr(target_phys_addr_t addr);
 void do_info_roms(Monitor *mon);
 
-#define rom_add_file_fixed(_f, _a)              \
-    rom_add_file(_f, NULL, _a)
+#define rom_add_file_fixed(_f, _a, _i)          \
+    rom_add_file(_f, NULL, _a, _i)
 #define rom_add_blob_fixed(_f, _b, _l, _a)      \
     rom_add_blob(_f, _b, _l, _a)
 
@@ -43,6 +43,6 @@ void do_info_roms(Monitor *mon);
 #define PC_ROM_SIZE        (PC_ROM_MAX - PC_ROM_MIN_VGA)
 
 int rom_add_vga(const char *file);
-int rom_add_option(const char *file);
+int rom_add_option(const char *file, int32_t bootindex);
 
 #endif
diff --git a/hw/multiboot.c b/hw/multiboot.c
index e710bbb..7cc3055 100644
--- a/hw/multiboot.c
+++ b/hw/multiboot.c
@@ -331,7 +331,8 @@ int load_multiboot(void *fw_cfg,
     fw_cfg_add_bytes(fw_cfg, FW_CFG_INITRD_DATA, mb_bootinfo_data,
                      sizeof(bootinfo));
 
-    option_rom[nb_option_roms] = "multiboot.bin";
+    option_rom[nb_option_roms].name = "multiboot.bin";
+    option_rom[nb_option_roms].bootindex = 0;
     nb_option_roms++;
 
     return 1; /* yes, we are multiboot */
diff --git a/hw/ne2000.c b/hw/ne2000.c
index a030106..5966359 100644
--- a/hw/ne2000.c
+++ b/hw/ne2000.c
@@ -742,7 +742,7 @@ static int pci_ne2000_init(PCIDevice *pci_dev)
     if (!pci_dev->qdev.hotplugged) {
         static int loaded = 0;
         if (!loaded) {
-            rom_add_option("pxe-ne2k_pci.bin");
+            rom_add_option("pxe-ne2k_pci.bin", -1);
             loaded = 1;
         }
     }
diff --git a/hw/nseries.c b/hw/nseries.c
index 04a028d..2f6f473 100644
--- a/hw/nseries.c
+++ b/hw/nseries.c
@@ -1326,7 +1326,7 @@ static void n8x0_init(ram_addr_t ram_size, const char *boot_device,
         qemu_register_reset(n8x0_boot_init, s);
     }
 
-    if (option_rom[0] && (boot_device[0] == 'n' || !kernel_filename)) {
+    if (option_rom[0].name && (boot_device[0] == 'n' || !kernel_filename)) {
         int rom_size;
         uint8_t nolo_tags[0x10000];
         /* No, wait, better start at the ROM.  */
@@ -1341,7 +1341,7 @@ static void n8x0_init(ram_addr_t ram_size, const char *boot_device,
          *
          * The code above is for loading the `zImage' file from Nokia
          * images.  */
-        rom_size = load_image_targphys(option_rom[0],
+        rom_size = load_image_targphys(option_rom[0].name,
                                        OMAP2_Q2_BASE + 0x400000,
                                        sdram_size - 0x400000);
         printf("%i bytes of image loaded\n", rom_size);
diff --git a/hw/palm.c b/hw/palm.c
index dd8d1e5..f22d777 100644
--- a/hw/palm.c
+++ b/hw/palm.c
@@ -238,20 +238,20 @@ static void palmte_init(ram_addr_t ram_size,
 
     /* Setup initial (reset) machine state */
     if (nb_option_roms) {
-        rom_size = get_image_size(option_rom[0]);
+        rom_size = get_image_size(option_rom[0].name);
         if (rom_size > flash_size) {
             fprintf(stderr, "%s: ROM image too big (%x > %x)\n",
                             __FUNCTION__, rom_size, flash_size);
             rom_size = 0;
         }
         if (rom_size > 0) {
-            rom_size = load_image_targphys(option_rom[0], OMAP_CS0_BASE,
+            rom_size = load_image_targphys(option_rom[0].name, OMAP_CS0_BASE,
                                            flash_size);
             rom_loaded = 1;
         }
         if (rom_size < 0) {
             fprintf(stderr, "%s: error loading '%s'\n",
-                            __FUNCTION__, option_rom[0]);
+                            __FUNCTION__, option_rom[0].name);
         }
     }
 
diff --git a/hw/pc.c b/hw/pc.c
index 119c110..e1b2667 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -733,7 +733,8 @@ static void load_linux(void *fw_cfg,
     fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_SIZE, setup_size);
     fw_cfg_add_bytes(fw_cfg, FW_CFG_SETUP_DATA, setup, setup_size);
 
-    option_rom[nb_option_roms] = "linuxboot.bin";
+    option_rom[nb_option_roms].name = "linuxboot.bin";
+    option_rom[nb_option_roms].bootindex = 0;
     nb_option_roms++;
 }
 
@@ -937,7 +938,7 @@ void pc_memory_init(ram_addr_t ram_size,
         goto bios_error;
     }
     bios_offset = qemu_ram_alloc(NULL, "pc.bios", bios_size);
-    ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size));
+    ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1);
     if (ret != 0) {
     bios_error:
         fprintf(stderr, "qemu: could not load PC BIOS '%s'\n", bios_name);
@@ -969,7 +970,7 @@ void pc_memory_init(ram_addr_t ram_size,
     }
 
     for (i = 0; i < nb_option_roms; i++) {
-        rom_add_option(option_rom[i]);
+        rom_add_option(option_rom[i].name, option_rom[i].bootindex);
     }
 }
 
diff --git a/hw/pci.c b/hw/pci.c
index e7ea907..24e650a 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -1832,7 +1832,7 @@ static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom)
         if (class == 0x0300) {
             rom_add_vga(pdev->romfile);
         } else {
-            rom_add_option(pdev->romfile);
+            rom_add_option(pdev->romfile, -1);
         }
         return 0;
     }
diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c
index 5c5bd21..339a401 100644
--- a/hw/pcnet-pci.c
+++ b/hw/pcnet-pci.c
@@ -310,7 +310,7 @@ static int pci_pcnet_init(PCIDevice *pci_dev)
     if (!pci_dev->qdev.hotplugged) {
         static int loaded = 0;
         if (!loaded) {
-            rom_add_option("pxe-pcnet.bin");
+            rom_add_option("pxe-pcnet.bin", -1);
             loaded = 1;
         }
     }
diff --git a/qemu-config.c b/qemu-config.c
index 52f18be..965fa46 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -429,6 +429,22 @@ QemuOptsList qemu_spice_opts = {
     },
 };
 
+QemuOptsList qemu_option_rom_opts = {
+    .name = "option-rom",
+    .implied_opt_name = "romfile",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_option_rom_opts.head),
+    .desc = {
+        {
+            .name = "bootindex",
+            .type = QEMU_OPT_NUMBER,
+        }, {
+            .name = "romfile",
+            .type = QEMU_OPT_STRING,
+        },
+        { /* end if list */ }
+    },
+};
+
 static QemuOptsList *vm_config_groups[32] = {
     &qemu_drive_opts,
     &qemu_chardev_opts,
@@ -442,6 +458,7 @@ static QemuOptsList *vm_config_groups[32] = {
 #ifdef CONFIG_SIMPLE_TRACE
     &qemu_trace_opts,
 #endif
+    &qemu_option_rom_opts,
     NULL,
 };
 
diff --git a/sysemu.h b/sysemu.h
index fe9a582..48f8eee 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -139,7 +139,11 @@ extern uint64_t node_mem[MAX_NODES];
 extern uint64_t node_cpumask[MAX_NODES];
 
 #define MAX_OPTION_ROMS 16
-extern const char *option_rom[MAX_OPTION_ROMS];
+typedef struct QEMUOptionRom {
+    const char *name;
+    int32_t bootindex;
+} QEMUOptionRom;
+extern QEMUOptionRom option_rom[MAX_OPTION_ROMS];
 extern int nb_option_roms;
 
 #define MAX_PROM_ENVS 128
diff --git a/vl.c b/vl.c
index dadc161..844d6a5 100644
--- a/vl.c
+++ b/vl.c
@@ -218,7 +218,7 @@ int cursor_hide = 1;
 int graphic_rotate = 0;
 uint8_t irq0override = 1;
 const char *watchdog;
-const char *option_rom[MAX_OPTION_ROMS];
+QEMUOptionRom option_rom[MAX_OPTION_ROMS];
 int nb_option_roms;
 int semihosting_enabled = 0;
 int old_param = 0;
@@ -2520,7 +2520,14 @@ int main(int argc, char **argv, char **envp)
 		    fprintf(stderr, "Too many option ROMs\n");
 		    exit(1);
 		}
-		option_rom[nb_option_roms] = optarg;
+                opts = qemu_opts_parse(qemu_find_opts("option-rom"), optarg, 1);
+                option_rom[nb_option_roms].name = qemu_opt_get(opts, "romfile");
+                option_rom[nb_option_roms].bootindex =
+                    qemu_opt_get_number(opts, "bootindex", -1);
+                if (!option_rom[nb_option_roms].name) {
+                    fprintf(stderr, "Option ROM file is not specified\n");
+                    exit(1);
+                }
 		nb_option_roms++;
 		break;
             case QEMU_OPTION_semihosting:
commit de1f34cb6351c028ebcc61fea9fa78008ca1a529
Author: Gleb Natapov <gleb at redhat.com>
Date:   Wed Dec 8 13:35:06 2010 +0200

    Change fw_cfg_add_file() to get full file path as a parameter.
    
    Change fw_cfg_add_file() to get full file path as a parameter instead
    of building one internally. Two reasons for that. First caller may need
    to know how file is named. Second this moves policy of file naming out
    from fw_cfg. Platform may want to use more then two levels of
    directories for instance.
    
    Signed-off-by: Gleb Natapov <gleb at redhat.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c
index 48b92d6..957466d 100644
--- a/hw/fw_cfg.c
+++ b/hw/fw_cfg.c
@@ -277,10 +277,9 @@ int fw_cfg_add_callback(FWCfgState *s, uint16_t key, FWCfgCallback callback,
     return 1;
 }
 
-int fw_cfg_add_file(FWCfgState *s,  const char *dir, const char *filename,
-                    uint8_t *data, uint32_t len)
+int fw_cfg_add_file(FWCfgState *s,  const char *filename, uint8_t *data,
+                    uint32_t len)
 {
-    const char *basename;
     int i, index;
 
     if (!s->files) {
@@ -297,15 +296,8 @@ int fw_cfg_add_file(FWCfgState *s,  const char *dir, const char *filename,
 
     fw_cfg_add_bytes(s, FW_CFG_FILE_FIRST + index, data, len);
 
-    basename = strrchr(filename, '/');
-    if (basename) {
-        basename++;
-    } else {
-        basename = filename;
-    }
-
-    snprintf(s->files->f[index].name, sizeof(s->files->f[index].name),
-             "%s/%s", dir, basename);
+    pstrcpy(s->files->f[index].name, sizeof(s->files->f[index].name),
+            filename);
     for (i = 0; i < index; i++) {
         if (strcmp(s->files->f[index].name, s->files->f[i].name) == 0) {
             FW_CFG_DPRINTF("%s: skip duplicate: %s\n", __FUNCTION__,
diff --git a/hw/fw_cfg.h b/hw/fw_cfg.h
index 4d13a4f..856bf91 100644
--- a/hw/fw_cfg.h
+++ b/hw/fw_cfg.h
@@ -60,8 +60,8 @@ int fw_cfg_add_i32(FWCfgState *s, uint16_t key, uint32_t value);
 int fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value);
 int fw_cfg_add_callback(FWCfgState *s, uint16_t key, FWCfgCallback callback,
                         void *callback_opaque, uint8_t *data, size_t len);
-int fw_cfg_add_file(FWCfgState *s, const char *dir, const char *filename,
-                    uint8_t *data, uint32_t len);
+int fw_cfg_add_file(FWCfgState *s, const char *filename, uint8_t *data,
+                    uint32_t len);
 FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
                         target_phys_addr_t crl_addr, target_phys_addr_t data_addr);
 
diff --git a/hw/loader.c b/hw/loader.c
index 49ac1fa..1e98326 100644
--- a/hw/loader.c
+++ b/hw/loader.c
@@ -592,8 +592,20 @@ int rom_add_file(const char *file, const char *fw_dir,
     }
     close(fd);
     rom_insert(rom);
-    if (rom->fw_file && fw_cfg)
-        fw_cfg_add_file(fw_cfg, rom->fw_dir, rom->fw_file, rom->data, rom->romsize);
+    if (rom->fw_file && fw_cfg) {
+        const char *basename;
+        char fw_file_name[56];
+
+        basename = strrchr(rom->fw_file, '/');
+        if (basename) {
+            basename++;
+        } else {
+            basename = rom->fw_file;
+        }
+        snprintf(fw_file_name, sizeof(fw_file_name), "%s/%s", rom->fw_dir,
+                 basename);
+        fw_cfg_add_file(fw_cfg, fw_file_name, rom->data, rom->romsize);
+    }
     return 0;
 
 err:
commit 1ca4d09ae0bcc2fdd6aeef0fdc11f82394f7e757
Author: Gleb Natapov <gleb at redhat.com>
Date:   Wed Dec 8 13:35:05 2010 +0200

    Add bootindex parameter to net/block/fd device
    
    If bootindex is specified on command line a string that describes device
    in firmware readable way is added into sorted list. Later this list will
    be passed into firmware to control boot order.
    
    Signed-off-by: Gleb Natapov <gleb at redhat.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/block_int.h b/block_int.h
index 3c3adb5..0a0e47d 100644
--- a/block_int.h
+++ b/block_int.h
@@ -227,6 +227,7 @@ typedef struct BlockConf {
     uint16_t logical_block_size;
     uint16_t min_io_size;
     uint32_t opt_io_size;
+    int32_t bootindex;
 } BlockConf;
 
 static inline unsigned int get_physical_block_exp(BlockConf *conf)
@@ -249,6 +250,7 @@ static inline unsigned int get_physical_block_exp(BlockConf *conf)
     DEFINE_PROP_UINT16("physical_block_size", _state,                   \
                        _conf.physical_block_size, 512),                 \
     DEFINE_PROP_UINT16("min_io_size", _state, _conf.min_io_size, 0),  \
-    DEFINE_PROP_UINT32("opt_io_size", _state, _conf.opt_io_size, 0)
+    DEFINE_PROP_UINT32("opt_io_size", _state, _conf.opt_io_size, 0),    \
+    DEFINE_PROP_INT32("bootindex", _state, _conf.bootindex, -1)         \
 
 #endif /* BLOCK_INT_H */
diff --git a/hw/e1000.c b/hw/e1000.c
index a697abd..af101bd 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -30,6 +30,7 @@
 #include "net.h"
 #include "net/checksum.h"
 #include "loader.h"
+#include "sysemu.h"
 
 #include "e1000_hw.h"
 
@@ -1147,6 +1148,9 @@ static int pci_e1000_init(PCIDevice *pci_dev)
                           d->dev.qdev.info->name, d->dev.qdev.id, d);
 
     qemu_format_nic_info_str(&d->nic->nc, macaddr);
+
+    add_boot_device_path(d->conf.bootindex, &pci_dev->qdev, "/ethernet-phy at 0");
+
     return 0;
 }
 
diff --git a/hw/eepro100.c b/hw/eepro100.c
index b31ad3e..edf48f6 100644
--- a/hw/eepro100.c
+++ b/hw/eepro100.c
@@ -46,6 +46,7 @@
 #include "pci.h"
 #include "net.h"
 #include "eeprom93xx.h"
+#include "sysemu.h"
 
 #define KiB 1024
 
@@ -1908,6 +1909,8 @@ static int e100_nic_init(PCIDevice *pci_dev)
     s->vmstate->name = s->nic->nc.model;
     vmstate_register(&pci_dev->qdev, -1, s->vmstate, s);
 
+    add_boot_device_path(s->conf.bootindex, &pci_dev->qdev, "/ethernet-phy at 0");
+
     return 0;
 }
 
diff --git a/hw/fdc.c b/hw/fdc.c
index 9d92e93..4bbcc47 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -35,6 +35,7 @@
 #include "sysbus.h"
 #include "qdev-addr.h"
 #include "blockdev.h"
+#include "sysemu.h"
 
 /********************************************************/
 /* debug Floppy devices */
@@ -523,6 +524,8 @@ typedef struct FDCtrlSysBus {
 typedef struct FDCtrlISABus {
     ISADevice busdev;
     struct FDCtrl state;
+    int32_t bootindexA;
+    int32_t bootindexB;
 } FDCtrlISABus;
 
 static uint32_t fdctrl_read (void *opaque, uint32_t reg)
@@ -1992,6 +1995,9 @@ static int isabus_fdc_init1(ISADevice *dev)
     qdev_set_legacy_instance_id(&dev->qdev, iobase, 2);
     ret = fdctrl_init_common(fdctrl);
 
+    add_boot_device_path(isa->bootindexA, &dev->qdev, "/floppy at 0");
+    add_boot_device_path(isa->bootindexB, &dev->qdev, "/floppy at 1");
+
     return ret;
 }
 
@@ -2053,6 +2059,8 @@ static ISADeviceInfo isa_fdc_info = {
     .qdev.props = (Property[]) {
         DEFINE_PROP_DRIVE("driveA", FDCtrlISABus, state.drives[0].bs),
         DEFINE_PROP_DRIVE("driveB", FDCtrlISABus, state.drives[1].bs),
+        DEFINE_PROP_INT32("bootindexA", FDCtrlISABus, bootindexA, -1),
+        DEFINE_PROP_INT32("bootindexB", FDCtrlISABus, bootindexB, -1),
         DEFINE_PROP_END_OF_LIST(),
     },
 };
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index 01a181b..2bb5c27 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -21,6 +21,7 @@
 #include "qemu-error.h"
 #include <hw/ide/internal.h>
 #include "blockdev.h"
+#include "sysemu.h"
 
 /* --------------------------------- */
 
@@ -143,6 +144,10 @@ static int ide_drive_initfn(IDEDevice *dev)
     if (!dev->serial) {
         dev->serial = qemu_strdup(s->drive_serial_str);
     }
+
+    add_boot_device_path(dev->conf.bootindex, &dev->qdev,
+                         dev->unit ? "/disk at 1" : "/disk at 0");
+
     return 0;
 }
 
diff --git a/hw/ne2000.c b/hw/ne2000.c
index 126e7cf..a030106 100644
--- a/hw/ne2000.c
+++ b/hw/ne2000.c
@@ -26,6 +26,7 @@
 #include "net.h"
 #include "ne2000.h"
 #include "loader.h"
+#include "sysemu.h"
 
 /* debug NE2000 card */
 //#define DEBUG_NE2000
@@ -746,6 +747,8 @@ static int pci_ne2000_init(PCIDevice *pci_dev)
         }
     }
 
+    add_boot_device_path(s->c.bootindex, &pci_dev->qdev, "/ethernet-phy at 0");
+
     return 0;
 }
 
diff --git a/hw/pcnet.c b/hw/pcnet.c
index 37010b8..db52dc5 100644
--- a/hw/pcnet.c
+++ b/hw/pcnet.c
@@ -39,6 +39,7 @@
 #include "net.h"
 #include "qemu-timer.h"
 #include "qemu_socket.h"
+#include "sysemu.h"
 
 #include "pcnet.h"
 
@@ -1740,5 +1741,8 @@ int pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info)
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
     s->nic = qemu_new_nic(info, &s->conf, dev->info->name, dev->id, s);
     qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
+
+    add_boot_device_path(s->conf.bootindex, dev, "/ethernet-phy at 0");
+
     return 0;
 }
diff --git a/hw/qdev.c b/hw/qdev.c
index b65b63e..10e28df 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -889,3 +889,35 @@ int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
     }
     return qdev_unplug(dev);
 }
+
+static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
+{
+    int l = 0;
+
+    if (dev && dev->parent_bus) {
+        char *d;
+        l = qdev_get_fw_dev_path_helper(dev->parent_bus->parent, p, size);
+        if (dev->parent_bus->info->get_fw_dev_path) {
+            d = dev->parent_bus->info->get_fw_dev_path(dev);
+            l += snprintf(p + l, size - l, "%s", d);
+            qemu_free(d);
+        } else {
+            l += snprintf(p + l, size - l, "%s", dev->info->name);
+        }
+    }
+    l += snprintf(p + l , size - l, "/");
+
+    return l;
+}
+
+char* qdev_get_fw_dev_path(DeviceState *dev)
+{
+    char path[128];
+    int l;
+
+    l = qdev_get_fw_dev_path_helper(dev, path, 128);
+
+    path[l-1] = '\0';
+
+    return strdup(path);
+}
diff --git a/hw/qdev.h b/hw/qdev.h
index f72fbde..aaaf55a 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -319,6 +319,7 @@ static inline const char *qdev_fw_name(DeviceState *dev)
     return dev->info->fw_name ? : dev->info->alias ? : dev->info->name;
 }
 
+char *qdev_get_fw_dev_path(DeviceState *dev);
 /* This is a nasty hack to allow passing a NULL bus to qdev_create.  */
 extern struct BusInfo system_bus_info;
 
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 4a73f6f..a8aed89 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -52,6 +52,7 @@
 #include "qemu-timer.h"
 #include "net.h"
 #include "loader.h"
+#include "sysemu.h"
 
 /* debug RTL8139 card */
 //#define DEBUG_RTL8139 1
@@ -3376,6 +3377,9 @@ static int pci_rtl8139_init(PCIDevice *dev)
     s->TimerExpire = 0;
     s->timer = qemu_new_timer(vm_clock, rtl8139_timer, s);
     rtl8139_set_next_tctr_time(s, qemu_get_clock(vm_clock));
+
+    add_boot_device_path(s->conf.bootindex, &dev->qdev, "/ethernet-phy at 0");
+
     return 0;
 }
 
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 851046f..87f9e86 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -1225,6 +1225,7 @@ static int scsi_disk_initfn(SCSIDevice *dev)
     s->qdev.type = TYPE_DISK;
     qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
     bdrv_set_removable(s->bs, is_cd);
+    add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, ",0");
     return 0;
 }
 
diff --git a/hw/usb-net.c b/hw/usb-net.c
index f6bed21..8492455 100644
--- a/hw/usb-net.c
+++ b/hw/usb-net.c
@@ -27,6 +27,7 @@
 #include "usb.h"
 #include "net.h"
 #include "qemu-queue.h"
+#include "sysemu.h"
 
 /*#define TRAFFIC_DEBUG*/
 /* Thanks to NetChip Technologies for donating this product ID.
@@ -1463,6 +1464,7 @@ static int usb_net_initfn(USBDevice *dev)
              s->conf.macaddr.a[4],
              s->conf.macaddr.a[5]);
 
+    add_boot_device_path(s->conf.bootindex, &dev->qdev, "/ethernet at 0");
     return 0;
 }
 
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index e5f9b27..f62ccd1 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -548,6 +548,8 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf)
     bdrv_set_removable(s->bs, 0);
     s->bs->buffer_alignment = conf->logical_block_size;
 
+    add_boot_device_path(conf->bootindex, dev, "/disk at 0,0");
+
     return &s->vdev;
 }
 
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index 1d61f19..3472f6b 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -1017,6 +1017,8 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
                     virtio_net_save, virtio_net_load, n);
     n->vmstate = qemu_add_vm_change_state_handler(virtio_net_vmstate_change, n);
 
+    add_boot_device_path(conf->bootindex, dev, "/ethernet-phy at 0");
+
     return &n->vdev;
 }
 
diff --git a/net.h b/net.h
index 44c31a9..6ceca50 100644
--- a/net.h
+++ b/net.h
@@ -17,12 +17,14 @@ typedef struct NICConf {
     MACAddr macaddr;
     VLANState *vlan;
     VLANClientState *peer;
+    int32_t bootindex;
 } NICConf;
 
 #define DEFINE_NIC_PROPERTIES(_state, _conf)                            \
     DEFINE_PROP_MACADDR("mac",   _state, _conf.macaddr),                \
     DEFINE_PROP_VLAN("vlan",     _state, _conf.vlan),                   \
-    DEFINE_PROP_NETDEV("netdev", _state, _conf.peer)
+    DEFINE_PROP_NETDEV("netdev", _state, _conf.peer),                   \
+    DEFINE_PROP_INT32("bootindex", _state, _conf.bootindex, -1)
 
 /* VLANs support */
 
diff --git a/sysemu.h b/sysemu.h
index b81a70e..fe9a582 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -188,4 +188,6 @@ void rtc_change_mon_event(struct tm *tm);
 
 void register_devices(void);
 
+void add_boot_device_path(int32_t bootindex, DeviceState *dev,
+                          const char *suffix);
 #endif
diff --git a/vl.c b/vl.c
index 2cd263e..dadc161 100644
--- a/vl.c
+++ b/vl.c
@@ -229,6 +229,17 @@ unsigned int nb_prom_envs = 0;
 const char *prom_envs[MAX_PROM_ENVS];
 int boot_menu;
 
+typedef struct FWBootEntry FWBootEntry;
+
+struct FWBootEntry {
+    QTAILQ_ENTRY(FWBootEntry) link;
+    int32_t bootindex;
+    DeviceState *dev;
+    char *suffix;
+};
+
+QTAILQ_HEAD(, FWBootEntry) fw_boot_order = QTAILQ_HEAD_INITIALIZER(fw_boot_order);
+
 int nb_numa_nodes;
 uint64_t node_mem[MAX_NODES];
 uint64_t node_cpumask[MAX_NODES];
@@ -693,6 +704,35 @@ static void restore_boot_devices(void *opaque)
     qemu_free(standard_boot_devices);
 }
 
+void add_boot_device_path(int32_t bootindex, DeviceState *dev,
+                          const char *suffix)
+{
+    FWBootEntry *node, *i;
+
+    if (bootindex < 0) {
+        return;
+    }
+
+    assert(dev != NULL || suffix != NULL);
+
+    node = qemu_mallocz(sizeof(FWBootEntry));
+    node->bootindex = bootindex;
+    node->suffix = strdup(suffix);
+    node->dev = dev;
+
+    QTAILQ_FOREACH(i, &fw_boot_order, link) {
+        if (i->bootindex == bootindex) {
+            fprintf(stderr, "Two devices with same boot index %d\n", bootindex);
+            exit(1);
+        } else if (i->bootindex < bootindex) {
+            continue;
+        }
+        QTAILQ_INSERT_BEFORE(i, node, link);
+        return;
+    }
+    QTAILQ_INSERT_TAIL(&fw_boot_order, node, link);
+}
+
 static void numa_add(const char *optarg)
 {
     char option[128];
commit db07c0f84ba2bedea4b8201ccb62602fd5e64c28
Author: Gleb Natapov <gleb at redhat.com>
Date:   Wed Dec 8 13:35:04 2010 +0200

    Add get_fw_dev_path callback to scsi bus.
    
    Signed-off-by: Gleb Natapov <gleb at redhat.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 93f0e9a..7febb86 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -5,9 +5,12 @@
 #include "qdev.h"
 #include "blockdev.h"
 
+static char *scsibus_get_fw_dev_path(DeviceState *dev);
+
 static struct BusInfo scsi_bus_info = {
     .name  = "SCSI",
     .size  = sizeof(SCSIBus),
+    .get_fw_dev_path = scsibus_get_fw_dev_path,
     .props = (Property[]) {
         DEFINE_PROP_UINT32("scsi-id", SCSIDevice, id, -1),
         DEFINE_PROP_END_OF_LIST(),
@@ -518,3 +521,23 @@ void scsi_req_complete(SCSIRequest *req)
                        req->tag,
                        req->status);
 }
+
+static char *scsibus_get_fw_dev_path(DeviceState *dev)
+{
+    SCSIDevice *d = (SCSIDevice*)dev;
+    SCSIBus *bus = scsi_bus_from_device(d);
+    char path[100];
+    int i;
+
+    for (i = 0; i < bus->ndev; i++) {
+        if (bus->devs[i] == d) {
+            break;
+        }
+    }
+
+    assert(i != bus->ndev);
+
+    snprintf(path, sizeof(path), "%s@%x", qdev_fw_name(dev), i);
+
+    return strdup(path);
+}
commit cdedd0061306bf204c5751584f69f1bcc9834f14
Author: Gleb Natapov <gleb at redhat.com>
Date:   Wed Dec 8 13:35:03 2010 +0200

    Add get_fw_dev_path callback for usb bus.
    
    Signed-off-by: Gleb Natapov <gleb at redhat.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/usb-bus.c b/hw/usb-bus.c
index 256b881..8b4583c 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -5,11 +5,13 @@
 #include "monitor.h"
 
 static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);
+static char *usbbus_get_fw_dev_path(DeviceState *dev);
 
 static struct BusInfo usb_bus_info = {
     .name      = "USB",
     .size      = sizeof(USBBus),
     .print_dev = usb_bus_dev_print,
+    .get_fw_dev_path = usbbus_get_fw_dev_path,
 };
 static int next_usb_bus = 0;
 static QTAILQ_HEAD(, USBBus) busses = QTAILQ_HEAD_INITIALIZER(busses);
@@ -307,3 +309,43 @@ USBDevice *usbdevice_create(const char *cmdline)
     }
     return usb->usbdevice_init(params);
 }
+
+static int usbbus_get_fw_dev_path_helper(USBDevice *d, USBBus *bus, char *p,
+                                         int len)
+{
+    int l = 0;
+    USBPort *port;
+
+    QTAILQ_FOREACH(port, &bus->used, next) {
+        if (port->dev == d) {
+            if (port->pdev) {
+                l = usbbus_get_fw_dev_path_helper(port->pdev, bus, p, len);
+            }
+            l += snprintf(p + l, len - l, "%s@%x/", qdev_fw_name(&d->qdev),
+                          port->index);
+            break;
+        }
+    }
+
+    return l;
+}
+
+static char *usbbus_get_fw_dev_path(DeviceState *dev)
+{
+    USBDevice *d = (USBDevice*)dev;
+    USBBus *bus = usb_bus_from_device(d);
+    char path[100];
+    int l;
+
+    assert(d->attached != 0);
+
+    l = usbbus_get_fw_dev_path_helper(d, bus, path, sizeof(path));
+
+    if (l == 0) {
+        abort();
+    }
+
+    path[l-1] = '\0';
+
+    return strdup(path);
+}
commit ab28ccc0c67f52d8966b8172108cb8a6f76e6d2a
Author: Gleb Natapov <gleb at redhat.com>
Date:   Wed Dec 8 13:35:02 2010 +0200

    Record which USBDevice USBPort belongs too.
    
    Ports on root hub will have NULL here. This is needed to reconstruct
    path from device to its root hub to build device path.
    
    Signed-off-by: Gleb Natapov <gleb at redhat.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/usb-bus.c b/hw/usb-bus.c
index b692503..256b881 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -110,11 +110,12 @@ USBDevice *usb_create_simple(USBBus *bus, const char *name)
 }
 
 void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
-                       usb_attachfn attach)
+                       USBDevice *pdev, usb_attachfn attach)
 {
     port->opaque = opaque;
     port->index = index;
     port->attach = attach;
+    port->pdev = pdev;
     QTAILQ_INSERT_TAIL(&bus->free, port, next);
     bus->nfree++;
 }
diff --git a/hw/usb-hub.c b/hw/usb-hub.c
index 8e3a96b..8a3f829 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -535,7 +535,7 @@ static int usb_hub_initfn(USBDevice *dev)
     for (i = 0; i < s->nb_ports; i++) {
         port = &s->ports[i];
         usb_register_port(usb_bus_from_device(dev),
-                          &port->port, s, i, usb_hub_attach);
+                          &port->port, s, i, &s->dev, usb_hub_attach);
         port->wPortStatus = PORT_STAT_POWER;
         port->wPortChange = 0;
     }
diff --git a/hw/usb-musb.c b/hw/usb-musb.c
index 7f15842..9efe7a6 100644
--- a/hw/usb-musb.c
+++ b/hw/usb-musb.c
@@ -343,7 +343,7 @@ struct MUSBState {
     }
 
     usb_bus_new(&s->bus, NULL /* FIXME */);
-    usb_register_port(&s->bus, &s->port, s, 0, musb_attach);
+    usb_register_port(&s->bus, &s->port, s, 0, NULL, musb_attach);
 
     return s;
 }
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index 8eb4a1e..240e840 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -1699,7 +1699,7 @@ static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
     usb_bus_new(&ohci->bus, dev);
     ohci->num_ports = num_ports;
     for (i = 0; i < num_ports; i++) {
-        usb_register_port(&ohci->bus, &ohci->rhport[i].port, ohci, i, ohci_attach);
+        usb_register_port(&ohci->bus, &ohci->rhport[i].port, ohci, i, NULL, ohci_attach);
     }
 
     ohci->async_td = 0;
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index 1d83400..b9b822f 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -1115,7 +1115,7 @@ static int usb_uhci_common_initfn(UHCIState *s)
 
     usb_bus_new(&s->bus, &s->dev.qdev);
     for(i = 0; i < NB_PORTS; i++) {
-        usb_register_port(&s->bus, &s->ports[i].port, s, i, uhci_attach);
+        usb_register_port(&s->bus, &s->ports[i].port, s, i, NULL, uhci_attach);
     }
     s->frame_timer = qemu_new_timer(vm_clock, uhci_frame_timer, s);
     s->expire_time = qemu_get_clock(vm_clock) +
diff --git a/hw/usb.h b/hw/usb.h
index 00d2802..0b32d77 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -203,6 +203,7 @@ struct USBPort {
     USBDevice *dev;
     usb_attachfn attach;
     void *opaque;
+    USBDevice *pdev;
     int index; /* internal port index, may be used with the opaque */
     QTAILQ_ENTRY(USBPort) next;
 };
@@ -312,7 +313,7 @@ USBDevice *usb_create(USBBus *bus, const char *name);
 USBDevice *usb_create_simple(USBBus *bus, const char *name);
 USBDevice *usbdevice_create(const char *cmdline);
 void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
-                       usb_attachfn attach);
+                       USBDevice *pdev, usb_attachfn attach);
 void usb_unregister_port(USBBus *bus, USBPort *port);
 int usb_device_attach(USBDevice *dev);
 int usb_device_detach(USBDevice *dev);
commit 5e0259e7facb6aaac326c3beef79e4d2414c38d4
Author: Gleb Natapov <gleb at redhat.com>
Date:   Wed Dec 8 13:35:01 2010 +0200

    Add get_fw_dev_path callback for pci bus.
    
    Signed-off-by: Gleb Natapov <gleb at redhat.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/pci.c b/hw/pci.c
index 0c15b13..e7ea907 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -43,6 +43,7 @@
 
 static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent);
 static char *pcibus_get_dev_path(DeviceState *dev);
+static char *pcibus_get_fw_dev_path(DeviceState *dev);
 static int pcibus_reset(BusState *qbus);
 
 struct BusInfo pci_bus_info = {
@@ -50,6 +51,7 @@ struct BusInfo pci_bus_info = {
     .size       = sizeof(PCIBus),
     .print_dev  = pcibus_dev_print,
     .get_dev_path = pcibus_get_dev_path,
+    .get_fw_dev_path = pcibus_get_fw_dev_path,
     .reset      = pcibus_reset,
     .props      = (Property[]) {
         DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1),
@@ -1117,45 +1119,63 @@ void pci_msi_notify(PCIDevice *dev, unsigned int vector)
 typedef struct {
     uint16_t class;
     const char *desc;
+    const char *fw_name;
+    uint16_t fw_ign_bits;
 } pci_class_desc;
 
 static const pci_class_desc pci_class_descriptions[] =
 {
-    { 0x0100, "SCSI controller"},
-    { 0x0101, "IDE controller"},
-    { 0x0102, "Floppy controller"},
-    { 0x0103, "IPI controller"},
-    { 0x0104, "RAID controller"},
+    { 0x0001, "VGA controller", "display"},
+    { 0x0100, "SCSI controller", "scsi"},
+    { 0x0101, "IDE controller", "ide"},
+    { 0x0102, "Floppy controller", "fdc"},
+    { 0x0103, "IPI controller", "ipi"},
+    { 0x0104, "RAID controller", "raid"},
     { 0x0106, "SATA controller"},
     { 0x0107, "SAS controller"},
     { 0x0180, "Storage controller"},
-    { 0x0200, "Ethernet controller"},
-    { 0x0201, "Token Ring controller"},
-    { 0x0202, "FDDI controller"},
-    { 0x0203, "ATM controller"},
+    { 0x0200, "Ethernet controller", "ethernet"},
+    { 0x0201, "Token Ring controller", "token-ring"},
+    { 0x0202, "FDDI controller", "fddi"},
+    { 0x0203, "ATM controller", "atm"},
     { 0x0280, "Network controller"},
-    { 0x0300, "VGA controller"},
+    { 0x0300, "VGA controller", "display", 0x00ff},
     { 0x0301, "XGA controller"},
     { 0x0302, "3D controller"},
     { 0x0380, "Display controller"},
-    { 0x0400, "Video controller"},
-    { 0x0401, "Audio controller"},
+    { 0x0400, "Video controller", "video"},
+    { 0x0401, "Audio controller", "sound"},
     { 0x0402, "Phone"},
     { 0x0480, "Multimedia controller"},
-    { 0x0500, "RAM controller"},
-    { 0x0501, "Flash controller"},
+    { 0x0500, "RAM controller", "memory"},
+    { 0x0501, "Flash controller", "flash"},
     { 0x0580, "Memory controller"},
-    { 0x0600, "Host bridge"},
-    { 0x0601, "ISA bridge"},
-    { 0x0602, "EISA bridge"},
-    { 0x0603, "MC bridge"},
-    { 0x0604, "PCI bridge"},
-    { 0x0605, "PCMCIA bridge"},
-    { 0x0606, "NUBUS bridge"},
-    { 0x0607, "CARDBUS bridge"},
+    { 0x0600, "Host bridge", "host"},
+    { 0x0601, "ISA bridge", "isa"},
+    { 0x0602, "EISA bridge", "eisa"},
+    { 0x0603, "MC bridge", "mca"},
+    { 0x0604, "PCI bridge", "pci"},
+    { 0x0605, "PCMCIA bridge", "pcmcia"},
+    { 0x0606, "NUBUS bridge", "nubus"},
+    { 0x0607, "CARDBUS bridge", "cardbus"},
     { 0x0608, "RACEWAY bridge"},
     { 0x0680, "Bridge"},
-    { 0x0c03, "USB controller"},
+    { 0x0700, "Serial port", "serial"},
+    { 0x0701, "Parallel port", "parallel"},
+    { 0x0800, "Interrupt controller", "interrupt-controller"},
+    { 0x0801, "DMA controller", "dma-controller"},
+    { 0x0802, "Timer", "timer"},
+    { 0x0803, "RTC", "rtc"},
+    { 0x0900, "Keyboard", "keyboard"},
+    { 0x0901, "Pen", "pen"},
+    { 0x0902, "Mouse", "mouse"},
+    { 0x0A00, "Dock station", "dock", 0x00ff},
+    { 0x0B00, "i386 cpu", "cpu", 0x00ff},
+    { 0x0c00, "Fireware contorller", "fireware"},
+    { 0x0c01, "Access bus controller", "access-bus"},
+    { 0x0c02, "SSA controller", "ssa"},
+    { 0x0c03, "USB controller", "usb"},
+    { 0x0c04, "Fibre channel controller", "fibre-channel"},
     { 0, NULL}
 };
 
@@ -1960,6 +1980,48 @@ static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent)
     }
 }
 
+static char *pci_dev_fw_name(DeviceState *dev, char *buf, int len)
+{
+    PCIDevice *d = (PCIDevice *)dev;
+    const char *name = NULL;
+    const pci_class_desc *desc =  pci_class_descriptions;
+    int class = pci_get_word(d->config + PCI_CLASS_DEVICE);
+
+    while (desc->desc &&
+          (class & ~desc->fw_ign_bits) !=
+          (desc->class & ~desc->fw_ign_bits)) {
+        desc++;
+    }
+
+    if (desc->desc) {
+        name = desc->fw_name;
+    }
+
+    if (name) {
+        pstrcpy(buf, len, name);
+    } else {
+        snprintf(buf, len, "pci%04x,%04x",
+                 pci_get_word(d->config + PCI_VENDOR_ID),
+                 pci_get_word(d->config + PCI_DEVICE_ID));
+    }
+
+    return buf;
+}
+
+static char *pcibus_get_fw_dev_path(DeviceState *dev)
+{
+    PCIDevice *d = (PCIDevice *)dev;
+    char path[50], name[33];
+    int off;
+
+    off = snprintf(path, sizeof(path), "%s@%x",
+                   pci_dev_fw_name(dev, name, sizeof name),
+                   PCI_SLOT(d->devfn));
+    if (PCI_FUNC(d->devfn))
+        snprintf(path + off, sizeof(path) + off, ",%x", PCI_FUNC(d->devfn));
+    return strdup(path);
+}
+
 static char *pcibus_get_dev_path(DeviceState *dev)
 {
     PCIDevice *d = (PCIDevice *)dev;
commit c646f74ffdc2c514bc12e0c241faf08fab10d181
Author: Gleb Natapov <gleb at redhat.com>
Date:   Wed Dec 8 13:35:00 2010 +0200

    Add get_fw_dev_path callback for system bus.
    
    Prints out mmio or pio used to access child device.
    
    Signed-off-by: Gleb Natapov <gleb at redhat.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/pci_host.c b/hw/pci_host.c
index eebff7a..7c40155 100644
--- a/hw/pci_host.c
+++ b/hw/pci_host.c
@@ -140,6 +140,7 @@ void pci_host_conf_register_ioport(pio_addr_t ioport, PCIHostState *s)
 {
     pci_host_init(s);
     register_ioport_simple(&s->conf_handler, ioport, 4, 4);
+    sysbus_init_ioports(&s->busdev, ioport, 4);
 }
 
 int pci_host_data_register_mmio(PCIHostState *s, int endian)
@@ -154,4 +155,5 @@ void pci_host_data_register_ioport(pio_addr_t ioport, PCIHostState *s)
     register_ioport_simple(&s->data_handler, ioport, 4, 1);
     register_ioport_simple(&s->data_handler, ioport, 4, 2);
     register_ioport_simple(&s->data_handler, ioport, 4, 4);
+    sysbus_init_ioports(&s->busdev, ioport, 4);
 }
diff --git a/hw/sysbus.c b/hw/sysbus.c
index d817721..1583bd8 100644
--- a/hw/sysbus.c
+++ b/hw/sysbus.c
@@ -22,11 +22,13 @@
 #include "monitor.h"
 
 static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent);
+static char *sysbus_get_fw_dev_path(DeviceState *dev);
 
 struct BusInfo system_bus_info = {
     .name       = "System",
     .size       = sizeof(BusState),
     .print_dev  = sysbus_dev_print,
+    .get_fw_dev_path = sysbus_get_fw_dev_path,
 };
 
 void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq)
@@ -106,6 +108,16 @@ void sysbus_init_mmio_cb(SysBusDevice *dev, target_phys_addr_t size,
     dev->mmio[n].cb = cb;
 }
 
+void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size)
+{
+    pio_addr_t i;
+
+    for (i = 0; i < size; i++) {
+        assert(dev->num_pio < QDEV_MAX_PIO);
+        dev->pio[dev->num_pio++] = ioport++;
+    }
+}
+
 static int sysbus_device_init(DeviceState *dev, DeviceInfo *base)
 {
     SysBusDeviceInfo *info = container_of(base, SysBusDeviceInfo, qdev);
@@ -171,3 +183,21 @@ static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent)
                        indent, "", s->mmio[i].addr, s->mmio[i].size);
     }
 }
+
+static char *sysbus_get_fw_dev_path(DeviceState *dev)
+{
+    SysBusDevice *s = sysbus_from_qdev(dev);
+    char path[40];
+    int off;
+
+    off = snprintf(path, sizeof(path), "%s", qdev_fw_name(dev));
+
+    if (s->num_mmio) {
+        snprintf(path + off, sizeof(path) - off, "@"TARGET_FMT_plx,
+                 s->mmio[0].addr);
+    } else if (s->num_pio) {
+        snprintf(path + off, sizeof(path) - off, "@i%04x", s->pio[0]);
+    }
+
+    return strdup(path);
+}
diff --git a/hw/sysbus.h b/hw/sysbus.h
index 5980901..e9eb618 100644
--- a/hw/sysbus.h
+++ b/hw/sysbus.h
@@ -6,6 +6,7 @@
 #include "qdev.h"
 
 #define QDEV_MAX_MMIO 32
+#define QDEV_MAX_PIO 32
 #define QDEV_MAX_IRQ 256
 
 typedef struct SysBusDevice SysBusDevice;
@@ -23,6 +24,8 @@ struct SysBusDevice {
         mmio_mapfunc cb;
         ram_addr_t iofunc;
     } mmio[QDEV_MAX_MMIO];
+    int num_pio;
+    pio_addr_t pio[QDEV_MAX_PIO];
 };
 
 typedef int (*sysbus_initfn)(SysBusDevice *dev);
@@ -45,6 +48,7 @@ void sysbus_init_mmio_cb(SysBusDevice *dev, target_phys_addr_t size,
                             mmio_mapfunc cb);
 void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p);
 void sysbus_pass_irq(SysBusDevice *dev, SysBusDevice *target);
+void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size);
 
 
 void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq);
commit dc1a46b60941e137b3194936540790b720952055
Author: Gleb Natapov <gleb at redhat.com>
Date:   Wed Dec 8 13:34:59 2010 +0200

    Add get_fw_dev_path callback to IDE bus.
    
    Signed-off-by: Gleb Natapov <gleb at redhat.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index 88ff657..01a181b 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -24,9 +24,12 @@
 
 /* --------------------------------- */
 
+static char *idebus_get_fw_dev_path(DeviceState *dev);
+
 static struct BusInfo ide_bus_info = {
     .name  = "IDE",
     .size  = sizeof(IDEBus),
+    .get_fw_dev_path = idebus_get_fw_dev_path,
 };
 
 void ide_bus_new(IDEBus *idebus, DeviceState *dev, int bus_id)
@@ -35,6 +38,16 @@ void ide_bus_new(IDEBus *idebus, DeviceState *dev, int bus_id)
     idebus->bus_id = bus_id;
 }
 
+static char *idebus_get_fw_dev_path(DeviceState *dev)
+{
+    char path[30];
+
+    snprintf(path, sizeof(path), "%s@%d", qdev_fw_name(dev),
+             ((IDEBus*)dev->parent_bus)->bus_id);
+
+    return strdup(path);
+}
+
 static int ide_qdev_init(DeviceState *qdev, DeviceInfo *base)
 {
     IDEDevice *dev = DO_UPCAST(IDEDevice, qdev, qdev);
commit 3835510f10ac74553ff19df3eb254809f0b593c0
Author: Gleb Natapov <gleb at redhat.com>
Date:   Wed Dec 8 13:34:58 2010 +0200

    Store IDE bus id in IDEBus structure for easy access.
    
    Signed-off-by: Gleb Natapov <gleb at redhat.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c
index dfe6091..ea5d2dc 100644
--- a/hw/ide/cmd646.c
+++ b/hw/ide/cmd646.c
@@ -253,8 +253,8 @@ static int pci_cmd646_ide_initfn(PCIDevice *dev)
     pci_conf[PCI_INTERRUPT_PIN] = 0x01; // interrupt on pin 1
 
     irq = qemu_allocate_irqs(cmd646_set_irq, d, 2);
-    ide_bus_new(&d->bus[0], &d->dev.qdev);
-    ide_bus_new(&d->bus[1], &d->dev.qdev);
+    ide_bus_new(&d->bus[0], &d->dev.qdev, 0);
+    ide_bus_new(&d->bus[1], &d->dev.qdev, 1);
     ide_init2(&d->bus[0], irq[0]);
     ide_init2(&d->bus[1], irq[1]);
 
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index 85f4a16..71af66f 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -449,6 +449,7 @@ struct IDEBus {
     IDEDevice *slave;
     BMDMAState *bmdma;
     IDEState ifs[2];
+    int bus_id;
     uint8_t unit;
     uint8_t cmd;
     qemu_irq irq;
@@ -567,7 +568,7 @@ void ide_init2_with_non_qdev_drives(IDEBus *bus, DriveInfo *hd0,
 void ide_init_ioport(IDEBus *bus, int iobase, int iobase2);
 
 /* hw/ide/qdev.c */
-void ide_bus_new(IDEBus *idebus, DeviceState *dev);
+void ide_bus_new(IDEBus *idebus, DeviceState *dev, int bus_id);
 IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive);
 
 #endif /* HW_IDE_INTERNAL_H */
diff --git a/hw/ide/isa.c b/hw/ide/isa.c
index 4206afd..8c59c5a 100644
--- a/hw/ide/isa.c
+++ b/hw/ide/isa.c
@@ -67,7 +67,7 @@ static int isa_ide_initfn(ISADevice *dev)
 {
     ISAIDEState *s = DO_UPCAST(ISAIDEState, dev, dev);
 
-    ide_bus_new(&s->bus, &s->dev.qdev);
+    ide_bus_new(&s->bus, &s->dev.qdev, 0);
     ide_init_ioport(&s->bus, s->iobase, s->iobase2);
     isa_init_irq(dev, &s->irq, s->isairq);
     isa_init_ioport_range(dev, s->iobase, 8);
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index e02b89a..1c0cb0c 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -125,8 +125,8 @@ static int pci_piix_ide_initfn(PCIIDEState *d)
 
     vmstate_register(&d->dev.qdev, 0, &vmstate_ide_pci, d);
 
-    ide_bus_new(&d->bus[0], &d->dev.qdev);
-    ide_bus_new(&d->bus[1], &d->dev.qdev);
+    ide_bus_new(&d->bus[0], &d->dev.qdev, 0);
+    ide_bus_new(&d->bus[1], &d->dev.qdev, 1);
     ide_init_ioport(&d->bus[0], 0x1f0, 0x3f6);
     ide_init_ioport(&d->bus[1], 0x170, 0x376);
 
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index 6d27b60..88ff657 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -29,9 +29,10 @@ static struct BusInfo ide_bus_info = {
     .size  = sizeof(IDEBus),
 };
 
-void ide_bus_new(IDEBus *idebus, DeviceState *dev)
+void ide_bus_new(IDEBus *idebus, DeviceState *dev, int bus_id)
 {
     qbus_create_inplace(&idebus->qbus, &ide_bus_info, dev, NULL);
+    idebus->bus_id = bus_id;
 }
 
 static int ide_qdev_init(DeviceState *qdev, DeviceInfo *base)
diff --git a/hw/ide/via.c b/hw/ide/via.c
index 66be0c4..78857e8 100644
--- a/hw/ide/via.c
+++ b/hw/ide/via.c
@@ -154,8 +154,8 @@ static int vt82c686b_ide_initfn(PCIDevice *dev)
 
     vmstate_register(&dev->qdev, 0, &vmstate_ide_pci, d);
 
-    ide_bus_new(&d->bus[0], &d->dev.qdev);
-    ide_bus_new(&d->bus[1], &d->dev.qdev);
+    ide_bus_new(&d->bus[0], &d->dev.qdev, 0);
+    ide_bus_new(&d->bus[1], &d->dev.qdev, 1);
     ide_init2(&d->bus[0], isa_reserve_irq(14));
     ide_init2(&d->bus[1], isa_reserve_irq(15));
     ide_init_ioport(&d->bus[0], 0x1f0, 0x3f6);
commit 6a26e1197db1684798c4255955c04e31270eccb8
Author: Gleb Natapov <gleb at redhat.com>
Date:   Wed Dec 8 13:34:57 2010 +0200

    Add get_fw_dev_path callback to ISA bus in qdev.
    
    Use device ioports to create unique device path.
    
    Signed-off-by: Gleb Natapov <gleb at redhat.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/isa-bus.c b/hw/isa-bus.c
index 5486efa..0cb1afb 100644
--- a/hw/isa-bus.c
+++ b/hw/isa-bus.c
@@ -31,11 +31,13 @@ static ISABus *isabus;
 target_phys_addr_t isa_mem_base = 0;
 
 static void isabus_dev_print(Monitor *mon, DeviceState *dev, int indent);
+static char *isabus_get_fw_dev_path(DeviceState *dev);
 
 static struct BusInfo isa_bus_info = {
     .name      = "ISA",
     .size      = sizeof(ISABus),
     .print_dev = isabus_dev_print,
+    .get_fw_dev_path = isabus_get_fw_dev_path,
 };
 
 ISABus *isa_bus_new(DeviceState *dev)
@@ -185,4 +187,18 @@ static void isabus_register_devices(void)
     sysbus_register_withprop(&isabus_bridge_info);
 }
 
+static char *isabus_get_fw_dev_path(DeviceState *dev)
+{
+    ISADevice *d = (ISADevice*)dev;
+    char path[40];
+    int off;
+
+    off = snprintf(path, sizeof(path), "%s", qdev_fw_name(dev));
+    if (d->nioports) {
+        snprintf(path + off, sizeof(path) - off, "@%04x", d->ioports[0]);
+    }
+
+    return strdup(path);
+}
+
 device_init(isabus_register_devices)
commit dee41d58ef7b874fd8a07e9e0ae4ef6e7fe624fc
Author: Gleb Natapov <gleb at redhat.com>
Date:   Wed Dec 8 13:34:56 2010 +0200

    Keep track of ISA ports ISA device is using in qdev.
    
    Store all io ports used by device in ISADevice structure.
    
    Signed-off-by: Gleb Natapov <gleb at redhat.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/cs4231a.c b/hw/cs4231a.c
index 4d5ce5c..598f032 100644
--- a/hw/cs4231a.c
+++ b/hw/cs4231a.c
@@ -645,6 +645,7 @@ static int cs4231a_initfn (ISADevice *dev)
     isa_init_irq (dev, &s->pic, s->irq);
 
     for (i = 0; i < 4; i++) {
+        isa_init_ioport(dev, i);
         register_ioport_write (s->port + i, 1, 1, cs_write, s);
         register_ioport_read (s->port + i, 1, 1, cs_read, s);
     }
diff --git a/hw/fdc.c b/hw/fdc.c
index 589bf06..9d92e93 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -1983,6 +1983,9 @@ static int isabus_fdc_init1(ISADevice *dev)
                           &fdctrl_write_port, fdctrl);
     register_ioport_write(iobase + 0x07, 1, 1,
                           &fdctrl_write_port, fdctrl);
+    isa_init_ioport_range(dev, iobase, 6);
+    isa_init_ioport(dev, iobase + 7);
+
     isa_init_irq(&isa->busdev, &fdctrl->irq, isairq);
     fdctrl->dma_chann = dma_chann;
 
diff --git a/hw/gus.c b/hw/gus.c
index e9016d8..ff9e7c7 100644
--- a/hw/gus.c
+++ b/hw/gus.c
@@ -264,20 +264,24 @@ static int gus_initfn (ISADevice *dev)
 
     register_ioport_write (s->port, 1, 1, gus_writeb, s);
     register_ioport_write (s->port, 1, 2, gus_writew, s);
+    isa_init_ioport_range(dev, s->port, 2);
 
     register_ioport_read ((s->port + 0x100) & 0xf00, 1, 1, gus_readb, s);
     register_ioport_read ((s->port + 0x100) & 0xf00, 1, 2, gus_readw, s);
+    isa_init_ioport_range(dev, (s->port + 0x100) & 0xf00, 2);
 
     register_ioport_write (s->port + 6, 10, 1, gus_writeb, s);
     register_ioport_write (s->port + 6, 10, 2, gus_writew, s);
     register_ioport_read (s->port + 6, 10, 1, gus_readb, s);
     register_ioport_read (s->port + 6, 10, 2, gus_readw, s);
+    isa_init_ioport_range(dev, s->port + 6, 10);
 
 
     register_ioport_write (s->port + 0x100, 8, 1, gus_writeb, s);
     register_ioport_write (s->port + 0x100, 8, 2, gus_writew, s);
     register_ioport_read (s->port + 0x100, 8, 1, gus_readb, s);
     register_ioport_read (s->port + 0x100, 8, 2, gus_readw, s);
+    isa_init_ioport_range(dev, s->port + 0x100, 8);
 
     DMA_register_channel (s->emu.gusdma, GUS_read_DMA, s);
     s->emu.himemaddr = s->himem;
diff --git a/hw/ide/isa.c b/hw/ide/isa.c
index 9856435..4206afd 100644
--- a/hw/ide/isa.c
+++ b/hw/ide/isa.c
@@ -70,6 +70,8 @@ static int isa_ide_initfn(ISADevice *dev)
     ide_bus_new(&s->bus, &s->dev.qdev);
     ide_init_ioport(&s->bus, s->iobase, s->iobase2);
     isa_init_irq(dev, &s->irq, s->isairq);
+    isa_init_ioport_range(dev, s->iobase, 8);
+    isa_init_ioport(dev, s->iobase2);
     ide_init2(&s->bus, s->irq);
     vmstate_register(&dev->qdev, 0, &vmstate_ide_isa, s);
     return 0;
diff --git a/hw/isa-bus.c b/hw/isa-bus.c
index f9c7ec0..5486efa 100644
--- a/hw/isa-bus.c
+++ b/hw/isa-bus.c
@@ -89,6 +89,31 @@ void isa_init_irq(ISADevice *dev, qemu_irq *p, int isairq)
     dev->nirqs++;
 }
 
+static void isa_init_ioport_one(ISADevice *dev, uint16_t ioport)
+{
+    assert(dev->nioports < ARRAY_SIZE(dev->ioports));
+    dev->ioports[dev->nioports++] = ioport;
+}
+
+static int isa_cmp_ports(const void *p1, const void *p2)
+{
+    return *(uint16_t*)p1 - *(uint16_t*)p2;
+}
+
+void isa_init_ioport_range(ISADevice *dev, uint16_t start, uint16_t length)
+{
+    int i;
+    for (i = start; i < start + length; i++) {
+        isa_init_ioport_one(dev, i);
+    }
+    qsort(dev->ioports, dev->nioports, sizeof(dev->ioports[0]), isa_cmp_ports);
+}
+
+void isa_init_ioport(ISADevice *dev, uint16_t ioport)
+{
+    isa_init_ioport_range(dev, ioport, 1);
+}
+
 static int isa_qdev_init(DeviceState *qdev, DeviceInfo *base)
 {
     ISADevice *dev = DO_UPCAST(ISADevice, qdev, qdev);
diff --git a/hw/isa.h b/hw/isa.h
index e6848e4..19aa94c 100644
--- a/hw/isa.h
+++ b/hw/isa.h
@@ -14,6 +14,8 @@ struct ISADevice {
     DeviceState qdev;
     uint32_t isairq[2];
     int nirqs;
+    uint16_t ioports[32];
+    int nioports;
 };
 
 typedef int (*isa_qdev_initfn)(ISADevice *dev);
@@ -26,6 +28,8 @@ ISABus *isa_bus_new(DeviceState *dev);
 void isa_bus_irqs(qemu_irq *irqs);
 qemu_irq isa_reserve_irq(int isairq);
 void isa_init_irq(ISADevice *dev, qemu_irq *p, int isairq);
+void isa_init_ioport(ISADevice *dev, uint16_t ioport);
+void isa_init_ioport_range(ISADevice *dev, uint16_t start, uint16_t length);
 void isa_qdev_register(ISADeviceInfo *info);
 ISADevice *isa_create(const char *name);
 ISADevice *isa_create_simple(const char *name);
diff --git a/hw/m48t59.c b/hw/m48t59.c
index 3c26b54..6991e2e 100644
--- a/hw/m48t59.c
+++ b/hw/m48t59.c
@@ -680,6 +680,7 @@ M48t59State *m48t59_init_isa(uint32_t io_base, uint16_t size, int type)
     if (io_base != 0) {
         register_ioport_read(io_base, 0x04, 1, NVRAM_readb, s);
         register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, s);
+        isa_init_ioport_range(dev, io_base, 4);
     }
 
     return s;
diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index 2b91fa8..6466aff 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -605,6 +605,7 @@ static int rtc_initfn(ISADevice *dev)
 
     register_ioport_write(base, 2, 1, cmos_ioport_write, s);
     register_ioport_read(base, 2, 1, cmos_ioport_read, s);
+    isa_init_ioport_range(dev, base, 2);
 
     qdev_set_legacy_instance_id(&dev->qdev, base, 2);
     qemu_register_reset(rtc_reset, s);
diff --git a/hw/ne2000-isa.c b/hw/ne2000-isa.c
index 03a5a1f..3ff0d89 100644
--- a/hw/ne2000-isa.c
+++ b/hw/ne2000-isa.c
@@ -68,14 +68,17 @@ static int isa_ne2000_initfn(ISADevice *dev)
 
     register_ioport_write(isa->iobase, 16, 1, ne2000_ioport_write, s);
     register_ioport_read(isa->iobase, 16, 1, ne2000_ioport_read, s);
+    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);
 
     isa_init_irq(dev, &s->irq, isa->isairq);
 
diff --git a/hw/parallel.c b/hw/parallel.c
index 00005c4..ce311aa 100644
--- a/hw/parallel.c
+++ b/hw/parallel.c
@@ -481,16 +481,21 @@ static int parallel_isa_initfn(ISADevice *dev)
     if (s->hw_driver) {
         register_ioport_write(base, 8, 1, parallel_ioport_write_hw, s);
         register_ioport_read(base, 8, 1, parallel_ioport_read_hw, s);
+        isa_init_ioport_range(dev, base, 8);
+
         register_ioport_write(base+4, 1, 2, parallel_ioport_eppdata_write_hw2, s);
         register_ioport_read(base+4, 1, 2, parallel_ioport_eppdata_read_hw2, s);
         register_ioport_write(base+4, 1, 4, parallel_ioport_eppdata_write_hw4, s);
         register_ioport_read(base+4, 1, 4, parallel_ioport_eppdata_read_hw4, s);
+        isa_init_ioport(dev, base+4);
         register_ioport_write(base+0x400, 8, 1, parallel_ioport_ecp_write, s);
         register_ioport_read(base+0x400, 8, 1, parallel_ioport_ecp_read, s);
+        isa_init_ioport_range(dev, base+0x400, 8);
     }
     else {
         register_ioport_write(base, 8, 1, parallel_ioport_write_sw, s);
         register_ioport_read(base, 8, 1, parallel_ioport_read_sw, s);
+        isa_init_ioport_range(dev, base, 8);
     }
     return 0;
 }
diff --git a/hw/pckbd.c b/hw/pckbd.c
index 7f0e6bb..863b485 100644
--- a/hw/pckbd.c
+++ b/hw/pckbd.c
@@ -485,10 +485,13 @@ static int i8042_initfn(ISADevice *dev)
 
     register_ioport_read(0x60, 1, 1, kbd_read_data, s);
     register_ioport_write(0x60, 1, 1, kbd_write_data, s);
+    isa_init_ioport(dev, 0x60);
     register_ioport_read(0x64, 1, 1, kbd_read_status, s);
     register_ioport_write(0x64, 1, 1, kbd_write_command, s);
+    isa_init_ioport(dev, 0x64);
     register_ioport_read(0x92, 1, 1, ioport92_read, s);
     register_ioport_write(0x92, 1, 1, ioport92_write, s);
+    isa_init_ioport(dev, 0x92);
 
     s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
     s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
diff --git a/hw/sb16.c b/hw/sb16.c
index 78590a7..c9d37ad 100644
--- a/hw/sb16.c
+++ b/hw/sb16.c
@@ -1368,16 +1368,20 @@ static int sb16_initfn (ISADevice *dev)
 
     for (i = 0; i < ARRAY_SIZE (dsp_write_ports); i++) {
         register_ioport_write (s->port + dsp_write_ports[i], 1, 1, dsp_write, s);
+        isa_init_ioport(dev, s->port + dsp_write_ports[i]);
     }
 
     for (i = 0; i < ARRAY_SIZE (dsp_read_ports); i++) {
         register_ioport_read (s->port + dsp_read_ports[i], 1, 1, dsp_read, s);
+        isa_init_ioport(dev, s->port + dsp_read_ports[i]);
     }
 
     register_ioport_write (s->port + 0x4, 1, 1, mixer_write_indexb, s);
     register_ioport_write (s->port + 0x4, 1, 2, mixer_write_indexw, s);
+    isa_init_ioport(dev, s->port + 0x4);
     register_ioport_read (s->port + 0x5, 1, 1, mixer_read, s);
     register_ioport_write (s->port + 0x5, 1, 1, mixer_write_datab, s);
+    isa_init_ioport(dev, s->port + 0x5);
 
     DMA_register_channel (s->hdma, SB_read_DMA, s);
     DMA_register_channel (s->dma, SB_read_DMA, s);
diff --git a/hw/serial.c b/hw/serial.c
index d21cbe9..2c4af61 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -778,6 +778,7 @@ static int serial_isa_initfn(ISADevice *dev)
 
     register_ioport_write(isa->iobase, 8, 1, serial_ioport_write, s);
     register_ioport_read(isa->iobase, 8, 1, serial_ioport_read, s);
+    isa_init_ioport_range(dev, isa->iobase, 8);
     return 0;
 }
 
commit 21150814d9f0d40b77f8ec54e716505b85b87e6b
Author: Gleb Natapov <gleb at redhat.com>
Date:   Wed Dec 8 13:34:55 2010 +0200

    Introduce new BusInfo callback get_fw_dev_path.
    
    New get_fw_dev_path callback will be used for build device path usable
    by firmware in contrast to qdev qemu internal device path.
    
    Signed-off-by: Gleb Natapov <gleb at redhat.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/qdev.h b/hw/qdev.h
index bc71110..f72fbde 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -49,6 +49,12 @@ struct DeviceState {
 
 typedef void (*bus_dev_printfn)(Monitor *mon, DeviceState *dev, int indent);
 typedef char *(*bus_get_dev_path)(DeviceState *dev);
+/*
+ * This callback is used to create Open Firmware device path in accordance with
+ * OF spec http://forthworks.com/standards/of1275.pdf. Indicidual bus bindings
+ * can be found here http://playground.sun.com/1275/bindings/.
+ */
+typedef char *(*bus_get_fw_dev_path)(DeviceState *dev);
 typedef int (qbus_resetfn)(BusState *bus);
 
 struct BusInfo {
@@ -56,6 +62,7 @@ struct BusInfo {
     size_t size;
     bus_dev_printfn print_dev;
     bus_get_dev_path get_dev_path;
+    bus_get_fw_dev_path get_fw_dev_path;
     qbus_resetfn *reset;
     Property *props;
 };
commit 779206de677533616ec3558bae89ea06fb91fc84
Author: Gleb Natapov <gleb at redhat.com>
Date:   Wed Dec 8 13:34:54 2010 +0200

    Introduce fw_name field to DeviceInfo structure.
    
    Add "fw_name" to DeviceInfo to use in device path building. In
    contrast to "name" "fw_name" should refer to functionality device
    provides instead of particular device model like "name" does.
    
    Signed-off-by: Gleb Natapov <gleb at redhat.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/fdc.c b/hw/fdc.c
index bea5af2..589bf06 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -2042,6 +2042,7 @@ static const VMStateDescription vmstate_isa_fdc ={
 static ISADeviceInfo isa_fdc_info = {
     .init = isabus_fdc_init1,
     .qdev.name  = "isa-fdc",
+    .qdev.fw_name  = "fdc",
     .qdev.size  = sizeof(FDCtrlISABus),
     .qdev.no_user = 1,
     .qdev.vmsd  = &vmstate_isa_fdc,
diff --git a/hw/ide/isa.c b/hw/ide/isa.c
index 6b57e0d..9856435 100644
--- a/hw/ide/isa.c
+++ b/hw/ide/isa.c
@@ -98,6 +98,7 @@ ISADevice *isa_ide_init(int iobase, int iobase2, int isairq,
 
 static ISADeviceInfo isa_ide_info = {
     .qdev.name  = "isa-ide",
+    .qdev.fw_name  = "ide",
     .qdev.size  = sizeof(ISAIDEState),
     .init       = isa_ide_initfn,
     .qdev.reset = isa_ide_reset,
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index 0808760..6d27b60 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -134,6 +134,7 @@ static int ide_drive_initfn(IDEDevice *dev)
 
 static IDEDeviceInfo ide_drive_info = {
     .qdev.name  = "ide-drive",
+    .qdev.fw_name  = "drive",
     .qdev.size  = sizeof(IDEDrive),
     .init       = ide_drive_initfn,
     .qdev.props = (Property[]) {
diff --git a/hw/isa-bus.c b/hw/isa-bus.c
index 3a6c961..f9c7ec0 100644
--- a/hw/isa-bus.c
+++ b/hw/isa-bus.c
@@ -150,6 +150,7 @@ static int isabus_bridge_init(SysBusDevice *dev)
 static SysBusDeviceInfo isabus_bridge_info = {
     .init = isabus_bridge_init,
     .qdev.name  = "isabus-bridge",
+    .qdev.fw_name  = "isa",
     .qdev.size  = sizeof(SysBusDevice),
     .qdev.no_user = 1,
 };
diff --git a/hw/lance.c b/hw/lance.c
index 8c51858..ddb1cbb 100644
--- a/hw/lance.c
+++ b/hw/lance.c
@@ -142,6 +142,7 @@ static void lance_reset(DeviceState *dev)
 static SysBusDeviceInfo lance_info = {
     .init       = lance_init,
     .qdev.name  = "lance",
+    .qdev.fw_name  = "ethernet",
     .qdev.size  = sizeof(SysBusPCNetState),
     .qdev.reset = lance_reset,
     .qdev.vmsd  = &vmstate_lance,
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index b5589b9..38f9d9e 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -365,6 +365,7 @@ static PCIDeviceInfo i440fx_info[] = {
 static SysBusDeviceInfo i440fx_pcihost_info = {
     .init         = i440fx_pcihost_initfn,
     .qdev.name    = "i440FX-pcihost",
+    .qdev.fw_name = "pci",
     .qdev.size    = sizeof(I440FXState),
     .qdev.no_user = 1,
 };
diff --git a/hw/qdev.h b/hw/qdev.h
index 3fac364..bc71110 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -141,6 +141,7 @@ typedef void (*qdev_resetfn)(DeviceState *dev);
 
 struct DeviceInfo {
     const char *name;
+    const char *fw_name;
     const char *alias;
     const char *desc;
     size_t size;
@@ -306,6 +307,11 @@ void qdev_prop_set_defaults(DeviceState *dev, Property *props);
 void qdev_prop_register_global_list(GlobalProperty *props);
 void qdev_prop_set_globals(DeviceState *dev);
 
+static inline const char *qdev_fw_name(DeviceState *dev)
+{
+    return dev->info->fw_name ? : dev->info->alias ? : dev->info->name;
+}
+
 /* This is a nasty hack to allow passing a NULL bus to qdev_create.  */
 extern struct BusInfo system_bus_info;
 
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 6e49404..851046f 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -1230,6 +1230,7 @@ static int scsi_disk_initfn(SCSIDevice *dev)
 
 static SCSIDeviceInfo scsi_disk_info = {
     .qdev.name    = "scsi-disk",
+    .qdev.fw_name = "disk",
     .qdev.desc    = "virtual scsi disk or cdrom",
     .qdev.size    = sizeof(SCSIDiskState),
     .qdev.reset   = scsi_disk_reset,
diff --git a/hw/usb-hub.c b/hw/usb-hub.c
index 2a1edfc..8e3a96b 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -545,6 +545,7 @@ static int usb_hub_initfn(USBDevice *dev)
 static struct USBDeviceInfo hub_info = {
     .product_desc   = "QEMU USB Hub",
     .qdev.name      = "usb-hub",
+    .qdev.fw_name    = "hub",
     .qdev.size      = sizeof(USBHubState),
     .init           = usb_hub_initfn,
     .handle_packet  = usb_hub_handle_packet,
diff --git a/hw/usb-net.c b/hw/usb-net.c
index 58c672f..f6bed21 100644
--- a/hw/usb-net.c
+++ b/hw/usb-net.c
@@ -1496,6 +1496,7 @@ static USBDevice *usb_net_init(const char *cmdline)
 static struct USBDeviceInfo net_info = {
     .product_desc   = "QEMU USB Network Interface",
     .qdev.name      = "usb-net",
+    .qdev.fw_name    = "network",
     .qdev.size      = sizeof(USBNetState),
     .init           = usb_net_initfn,
     .handle_packet  = usb_generic_handle_packet,
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index c65765a..6186142 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -699,6 +699,7 @@ static int virtio_9p_init_pci(PCIDevice *pci_dev)
 static PCIDeviceInfo virtio_info[] = {
     {
         .qdev.name = "virtio-blk-pci",
+        .qdev.alias = "virtio-blk",
         .qdev.size = sizeof(VirtIOPCIProxy),
         .init      = virtio_blk_init_pci,
         .exit      = virtio_blk_exit_pci,
commit 1b3cba6e91ab55a158e49bc5398fd76e67c695a8
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sat Dec 11 18:56:27 2010 +0000

    monitor: implement x86 info mem for PAE and long modes
    
    'info mem' didn't show correct information for PAE mode and
    x86_64 long mode.
    
    Fix by implementing the output for missing modes.
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/monitor.c b/monitor.c
index a4ab163..0896254 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2027,14 +2027,16 @@ static void tlb_info(Monitor *mon)
     }
 }
 
-static void mem_print(Monitor *mon, uint32_t *pstart, int *plast_prot,
-                      uint32_t end, int prot)
+static void mem_print(Monitor *mon, target_phys_addr_t *pstart,
+                      int *plast_prot,
+                      target_phys_addr_t end, int prot)
 {
     int prot1;
     prot1 = *plast_prot;
     if (prot != prot1) {
         if (*pstart != -1) {
-            monitor_printf(mon, "%08x-%08x %08x %c%c%c\n",
+            monitor_printf(mon, TARGET_FMT_plx "-" TARGET_FMT_plx " "
+                           TARGET_FMT_plx " %c%c%c\n",
                            *pstart, end, end - *pstart,
                            prot1 & PG_USER_MASK ? 'u' : '-',
                            'r',
@@ -2048,18 +2050,12 @@ static void mem_print(Monitor *mon, uint32_t *pstart, int *plast_prot,
     }
 }
 
-static void mem_info(Monitor *mon)
+static void mem_info_32(Monitor *mon, CPUState *env)
 {
-    CPUState *env;
     int l1, l2, prot, last_prot;
-    uint32_t pgd, pde, pte, start, end;
-
-    env = mon_get_cpu();
+    uint32_t pgd, pde, pte;
+    target_phys_addr_t start, end;
 
-    if (!(env->cr[0] & CR0_PG_MASK)) {
-        monitor_printf(mon, "PG disabled\n");
-        return;
-    }
     pgd = env->cr[3] & ~0xfff;
     last_prot = 0;
     start = -1;
@@ -2091,6 +2087,162 @@ static void mem_info(Monitor *mon)
         }
     }
 }
+
+static void mem_info_pae32(Monitor *mon, CPUState *env)
+{
+    int l1, l2, l3, prot, last_prot;
+    uint64_t pdpe, pde, pte;
+    uint64_t pdp_addr, pd_addr, pt_addr;
+    target_phys_addr_t start, end;
+
+    pdp_addr = env->cr[3] & ~0x1f;
+    last_prot = 0;
+    start = -1;
+    for (l1 = 0; l1 < 4; l1++) {
+        cpu_physical_memory_read(pdp_addr + l1 * 8, (uint8_t *)&pdpe, 8);
+        pdpe = le64_to_cpu(pdpe);
+        end = l1 << 30;
+        if (pdpe & PG_PRESENT_MASK) {
+            pd_addr = pdpe & 0x3fffffffff000ULL;
+            for (l2 = 0; l2 < 512; l2++) {
+                cpu_physical_memory_read(pd_addr + l2 * 8,
+                                         (uint8_t *)&pde, 8);
+                pde = le64_to_cpu(pde);
+                end = (l1 << 30) + (l2 << 21);
+                if (pde & PG_PRESENT_MASK) {
+                    if (pde & PG_PSE_MASK) {
+                        prot = pde & (PG_USER_MASK | PG_RW_MASK |
+                                      PG_PRESENT_MASK);
+                        mem_print(mon, &start, &last_prot, end, prot);
+                    } else {
+                        pt_addr = pde & 0x3fffffffff000ULL;
+                        for (l3 = 0; l3 < 512; l3++) {
+                            cpu_physical_memory_read(pt_addr + l3 * 8,
+                                                     (uint8_t *)&pte, 8);
+                            pte = le64_to_cpu(pte);
+                            end = (l1 << 30) + (l2 << 21) + (l3 << 12);
+                            if (pte & PG_PRESENT_MASK) {
+                                prot = pte & (PG_USER_MASK | PG_RW_MASK |
+                                              PG_PRESENT_MASK);
+                            } else {
+                                prot = 0;
+                            }
+                            mem_print(mon, &start, &last_prot, end, prot);
+                        }
+                    }
+                } else {
+                    prot = 0;
+                    mem_print(mon, &start, &last_prot, end, prot);
+                }
+            }
+        } else {
+            prot = 0;
+            mem_print(mon, &start, &last_prot, end, prot);
+        }
+    }
+}
+
+
+#ifdef TARGET_X86_64
+static void mem_info_64(Monitor *mon, CPUState *env)
+{
+    int prot, last_prot;
+    uint64_t l1, l2, l3, l4;
+    uint64_t pml4e, pdpe, pde, pte;
+    uint64_t pml4_addr, pdp_addr, pd_addr, pt_addr, start, end;
+
+    pml4_addr = env->cr[3] & 0x3fffffffff000ULL;
+    last_prot = 0;
+    start = -1;
+    for (l1 = 0; l1 < 512; l1++) {
+        cpu_physical_memory_read(pml4_addr + l1 * 8, (uint8_t *)&pml4e, 8);
+        pml4e = le64_to_cpu(pml4e);
+        end = l1 << 39;
+        if (pml4e & PG_PRESENT_MASK) {
+            pdp_addr = pml4e & 0x3fffffffff000ULL;
+            for (l2 = 0; l2 < 512; l2++) {
+                cpu_physical_memory_read(pdp_addr + l2 * 8, (uint8_t *)&pdpe,
+                                         8);
+                pdpe = le64_to_cpu(pdpe);
+                end = (l1 << 39) + (l2 << 30);
+                if (pdpe & PG_PRESENT_MASK) {
+                    if (pdpe & PG_PSE_MASK) {
+                        prot = pde & (PG_USER_MASK | PG_RW_MASK |
+                                      PG_PRESENT_MASK);
+                        mem_print(mon, &start, &last_prot, end, prot);
+                    } else {
+                        pd_addr = pdpe & 0x3fffffffff000ULL;
+                        for (l3 = 0; l3 < 512; l3++) {
+                            cpu_physical_memory_read(pd_addr + l3 * 8,
+                                                     (uint8_t *)&pde, 8);
+                            pde = le64_to_cpu(pde);
+                            end = (l1 << 39) + (l2 << 30) + (l3 << 21);
+                            if (pde & PG_PRESENT_MASK) {
+                                if (pde & PG_PSE_MASK) {
+                                    prot = pde & (PG_USER_MASK | PG_RW_MASK |
+                                                  PG_PRESENT_MASK);
+                                    mem_print(mon, &start, &last_prot, end, prot);
+                                } else {
+                                    pt_addr = pde & 0x3fffffffff000ULL;
+                                    for (l4 = 0; l4 < 512; l4++) {
+                                        cpu_physical_memory_read(pt_addr
+                                                                 + l4 * 8,
+                                                                 (uint8_t *)&pte,
+                                                                 8);
+                                        pte = le64_to_cpu(pte);
+                                        end = (l1 << 39) + (l2 << 30) +
+                                            (l3 << 21) + (l4 << 12);
+                                        if (pte & PG_PRESENT_MASK) {
+                                            prot = pte & (PG_USER_MASK | PG_RW_MASK |
+                                                          PG_PRESENT_MASK);
+                                        } else {
+                                            prot = 0;
+                                        }
+                                        mem_print(mon, &start, &last_prot, end, prot);
+                                    }
+                                }
+                            } else {
+                                prot = 0;
+                                mem_print(mon, &start, &last_prot, end, prot);
+                            }
+                        }
+                    }
+                } else {
+                    prot = 0;
+                    mem_print(mon, &start, &last_prot, end, prot);
+                }
+            }
+        } else {
+            prot = 0;
+            mem_print(mon, &start, &last_prot, end, prot);
+        }
+    }
+}
+#endif
+
+static void mem_info(Monitor *mon)
+{
+    CPUState *env;
+
+    env = mon_get_cpu();
+
+    if (!(env->cr[0] & CR0_PG_MASK)) {
+        monitor_printf(mon, "PG disabled\n");
+        return;
+    }
+    if (env->cr[4] & CR4_PAE_MASK) {
+#ifdef TARGET_X86_64
+        if (env->hflags & HF_LMA_MASK) {
+            mem_info_64(mon, env);
+        } else
+#endif
+        {
+            mem_info_pae32(mon, env);
+        }
+    } else {
+        mem_info_32(mon, env);
+    }
+}
 #endif
 
 #if defined(TARGET_SH4)
commit d65aaf3773e4be7ae97df9d867cbe9b36e2fb8a1
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sat Dec 11 18:56:24 2010 +0000

    monitor: implement x86 info tlb for PAE and long modes
    
    'info tlb' didn't show correct information for PAE mode and
    x86_64 long mode.
    
    Implement the missing modes. Also print NX bit for PAE and long modes.
    Fix off-by-one error in 32 bit mode mask.
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/monitor.c b/monitor.c
index ec31eac..a4ab163 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1848,11 +1848,20 @@ static int do_system_powerdown(Monitor *mon, const QDict *qdict,
 }
 
 #if defined(TARGET_I386)
-static void print_pte(Monitor *mon, uint32_t addr, uint32_t pte, uint32_t mask)
+static void print_pte(Monitor *mon, target_phys_addr_t addr,
+                      target_phys_addr_t pte,
+                      target_phys_addr_t mask)
 {
-    monitor_printf(mon, "%08x: %08x %c%c%c%c%c%c%c%c\n",
+#ifdef TARGET_X86_64
+    if (addr & (1ULL << 47)) {
+        addr |= -1LL << 48;
+    }
+#endif
+    monitor_printf(mon, TARGET_FMT_plx ": " TARGET_FMT_plx
+                   " %c%c%c%c%c%c%c%c%c\n",
                    addr,
                    pte & mask,
+                   pte & PG_NX_MASK ? 'X' : '-',
                    pte & PG_GLOBAL_MASK ? 'G' : '-',
                    pte & PG_PSE_MASK ? 'P' : '-',
                    pte & PG_DIRTY_MASK ? 'D' : '-',
@@ -1863,25 +1872,19 @@ static void print_pte(Monitor *mon, uint32_t addr, uint32_t pte, uint32_t mask)
                    pte & PG_RW_MASK ? 'W' : '-');
 }
 
-static void tlb_info(Monitor *mon)
+static void tlb_info_32(Monitor *mon, CPUState *env)
 {
-    CPUState *env;
     int l1, l2;
     uint32_t pgd, pde, pte;
 
-    env = mon_get_cpu();
-
-    if (!(env->cr[0] & CR0_PG_MASK)) {
-        monitor_printf(mon, "PG disabled\n");
-        return;
-    }
     pgd = env->cr[3] & ~0xfff;
     for(l1 = 0; l1 < 1024; l1++) {
         cpu_physical_memory_read(pgd + l1 * 4, (uint8_t *)&pde, 4);
         pde = le32_to_cpu(pde);
         if (pde & PG_PRESENT_MASK) {
             if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
-                print_pte(mon, (l1 << 22), pde, ~((1 << 20) - 1));
+                /* 4M pages */
+                print_pte(mon, (l1 << 22), pde, ~((1 << 21) - 1));
             } else {
                 for(l2 = 0; l2 < 1024; l2++) {
                     cpu_physical_memory_read((pde & ~0xfff) + l2 * 4,
@@ -1898,6 +1901,132 @@ static void tlb_info(Monitor *mon)
     }
 }
 
+static void tlb_info_pae32(Monitor *mon, CPUState *env)
+{
+    int l1, l2, l3;
+    uint64_t pdpe, pde, pte;
+    uint64_t pdp_addr, pd_addr, pt_addr;
+
+    pdp_addr = env->cr[3] & ~0x1f;
+    for (l1 = 0; l1 < 4; l1++) {
+        cpu_physical_memory_read(pdp_addr + l1 * 8, (uint8_t *)&pdpe, 8);
+        pdpe = le64_to_cpu(pdpe);
+        if (pdpe & PG_PRESENT_MASK) {
+            pd_addr = pdpe & 0x3fffffffff000ULL;
+            for (l2 = 0; l2 < 512; l2++) {
+                cpu_physical_memory_read(pd_addr + l2 * 8,
+                                         (uint8_t *)&pde, 8);
+                pde = le64_to_cpu(pde);
+                if (pde & PG_PRESENT_MASK) {
+                    if (pde & PG_PSE_MASK) {
+                        /* 2M pages with PAE, CR4.PSE is ignored */
+                        print_pte(mon, (l1 << 30 ) + (l2 << 21), pde,
+                                  ~((target_phys_addr_t)(1 << 20) - 1));
+                    } else {
+                        pt_addr = pde & 0x3fffffffff000ULL;
+                        for (l3 = 0; l3 < 512; l3++) {
+                            cpu_physical_memory_read(pt_addr + l3 * 8,
+                                                     (uint8_t *)&pte, 8);
+                            pte = le64_to_cpu(pte);
+                            if (pte & PG_PRESENT_MASK) {
+                                print_pte(mon, (l1 << 30 ) + (l2 << 21)
+                                          + (l3 << 12),
+                                          pte & ~PG_PSE_MASK,
+                                          ~(target_phys_addr_t)0xfff);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+#ifdef TARGET_X86_64
+static void tlb_info_64(Monitor *mon, CPUState *env)
+{
+    uint64_t l1, l2, l3, l4;
+    uint64_t pml4e, pdpe, pde, pte;
+    uint64_t pml4_addr, pdp_addr, pd_addr, pt_addr;
+
+    pml4_addr = env->cr[3] & 0x3fffffffff000ULL;
+    for (l1 = 0; l1 < 512; l1++) {
+        cpu_physical_memory_read(pml4_addr + l1 * 8, (uint8_t *)&pml4e, 8);
+        pml4e = le64_to_cpu(pml4e);
+        if (pml4e & PG_PRESENT_MASK) {
+            pdp_addr = pml4e & 0x3fffffffff000ULL;
+            for (l2 = 0; l2 < 512; l2++) {
+                cpu_physical_memory_read(pdp_addr + l2 * 8, (uint8_t *)&pdpe,
+                                         8);
+                pdpe = le64_to_cpu(pdpe);
+                if (pdpe & PG_PRESENT_MASK) {
+                    if (pdpe & PG_PSE_MASK) {
+                        /* 1G pages, CR4.PSE is ignored */
+                        print_pte(mon, (l1 << 39) + (l2 << 30), pdpe,
+                                  0x3ffffc0000000ULL);
+                    } else {
+                        pd_addr = pdpe & 0x3fffffffff000ULL;
+                        for (l3 = 0; l3 < 512; l3++) {
+                            cpu_physical_memory_read(pd_addr + l3 * 8,
+                                                     (uint8_t *)&pde, 8);
+                            pde = le64_to_cpu(pde);
+                            if (pde & PG_PRESENT_MASK) {
+                                if (pde & PG_PSE_MASK) {
+                                    /* 2M pages, CR4.PSE is ignored */
+                                    print_pte(mon, (l1 << 39) + (l2 << 30) +
+                                              (l3 << 21), pde,
+                                              0x3ffffffe00000ULL);
+                                } else {
+                                    pt_addr = pde & 0x3fffffffff000ULL;
+                                    for (l4 = 0; l4 < 512; l4++) {
+                                        cpu_physical_memory_read(pt_addr
+                                                                 + l4 * 8,
+                                                                 (uint8_t *)&pte,
+                                                                 8);
+                                        pte = le64_to_cpu(pte);
+                                        if (pte & PG_PRESENT_MASK) {
+                                            print_pte(mon, (l1 << 39) +
+                                                      (l2 << 30) +
+                                                      (l3 << 21) + (l4 << 12),
+                                                      pte & ~PG_PSE_MASK,
+                                                      0x3fffffffff000ULL);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+#endif
+
+static void tlb_info(Monitor *mon)
+{
+    CPUState *env;
+
+    env = mon_get_cpu();
+
+    if (!(env->cr[0] & CR0_PG_MASK)) {
+        monitor_printf(mon, "PG disabled\n");
+        return;
+    }
+    if (env->cr[4] & CR4_PAE_MASK) {
+#ifdef TARGET_X86_64
+        if (env->hflags & HF_LMA_MASK) {
+            tlb_info_64(mon, env);
+        } else
+#endif
+        {
+            tlb_info_pae32(mon, env);
+        }
+    } else {
+        tlb_info_32(mon, env);
+    }
+}
+
 static void mem_print(Monitor *mon, uint32_t *pstart, int *plast_prot,
                       uint32_t end, int prot)
 {
commit fa82e9c300df6f7b8bd44a26ac752c4ea5da02c1
Author: Bernhard Kohl <bernhard.kohl at nsn.com>
Date:   Wed Dec 8 15:59:55 2010 +0100

    wdt_i6300esb: register a reset function
    
    The device shall set its default hardware state after each reset.
    This includes that the timer is stopped which is especially important
    if the guest does a reboot independantly of a watchdog bite. I moved
    the initialization of the state variables completely from the init
    to the reset function which is called right after init during the
    first boot and afterwards during each reboot.
    
    Signed-off-by: Bernhard Kohl <bernhard.kohl at nsn.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/wdt_i6300esb.c b/hw/wdt_i6300esb.c
index 09f2f58..8443b41 100644
--- a/hw/wdt_i6300esb.c
+++ b/hw/wdt_i6300esb.c
@@ -140,14 +140,26 @@ static void i6300esb_disable_timer(I6300State *d)
     qemu_del_timer(d->timer);
 }
 
-static void i6300esb_reset(I6300State *d)
+static void i6300esb_reset(DeviceState *dev)
 {
-    /* XXX We should probably reset other parts of the state here,
-     * but we should also reset our state on general machine reset
-     * too.  For now just disable the timer so it doesn't fire
-     * again after the reboot.
-     */
+    PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, dev);
+    I6300State *d = DO_UPCAST(I6300State, dev, pdev);
+
+    i6300esb_debug("I6300State = %p\n", d);
+
     i6300esb_disable_timer(d);
+
+    d->reboot_enabled = 1;
+    d->clock_scale = CLOCK_SCALE_1KHZ;
+    d->int_type = INT_TYPE_IRQ;
+    d->free_run = 0;
+    d->locked = 0;
+    d->enabled = 0;
+    d->timer1_preload = 0xfffff;
+    d->timer2_preload = 0xfffff;
+    d->stage = 1;
+    d->unlock_state = 0;
+    d->previous_reboot_flag = 0;
 }
 
 /* This function is called when the watchdog expires.  Note that
@@ -181,7 +193,6 @@ static void i6300esb_timer_expired(void *vp)
         if (d->reboot_enabled) {
             d->previous_reboot_flag = 1;
             watchdog_perform_action(); /* This reboots, exits, etc */
-            i6300esb_reset(d);
         }
 
         /* In "free running mode" we start stage 1 again. */
@@ -395,18 +406,9 @@ static int i6300esb_init(PCIDevice *dev)
     I6300State *d = DO_UPCAST(I6300State, dev, dev);
     uint8_t *pci_conf;
 
-    d->reboot_enabled = 1;
-    d->clock_scale = CLOCK_SCALE_1KHZ;
-    d->int_type = INT_TYPE_IRQ;
-    d->free_run = 0;
-    d->locked = 0;
-    d->enabled = 0;
+    i6300esb_debug("I6300State = %p\n", d);
+
     d->timer = qemu_new_timer(vm_clock, i6300esb_timer_expired, d);
-    d->timer1_preload = 0xfffff;
-    d->timer2_preload = 0xfffff;
-    d->stage = 1;
-    d->unlock_state = 0;
-    d->previous_reboot_flag = 0;
 
     pci_conf = d->dev.config;
     pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
@@ -428,6 +430,7 @@ static PCIDeviceInfo i6300esb_info = {
     .qdev.name    = "i6300esb",
     .qdev.size    = sizeof(I6300State),
     .qdev.vmsd    = &vmstate_i6300esb,
+    .qdev.reset   = i6300esb_reset,
     .config_read  = i6300esb_config_read,
     .config_write = i6300esb_config_write,
     .init         = i6300esb_init,
commit 74782223de16e30940630b2bdb488e650ece6cd4
Author: Tristan Gingold <gingold at adacore.com>
Date:   Fri Dec 3 12:05:03 2010 +0100

    isa-bus.c: use hw_error instead of fprintf
    
    Minor clean-up in isa-bus.c.  Using hw_error is more consistent.
    There is a difference however: hw_error dumps the cpu state.
    
    Signed-off-by: Tristan Gingold <gingold at adacore.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/isa-bus.c b/hw/isa-bus.c
index 4e306de..3a6c961 100644
--- a/hw/isa-bus.c
+++ b/hw/isa-bus.c
@@ -68,12 +68,10 @@ void isa_bus_irqs(qemu_irq *irqs)
 qemu_irq isa_reserve_irq(int isairq)
 {
     if (isairq < 0 || isairq > 15) {
-        fprintf(stderr, "isa irq %d invalid\n", isairq);
-        exit(1);
+        hw_error("isa irq %d invalid", isairq);
     }
     if (isabus->assigned & (1 << isairq)) {
-        fprintf(stderr, "isa irq %d already assigned\n", isairq);
-        exit(1);
+        hw_error("isa irq %d already assigned", isairq);
     }
     isabus->assigned |= (1 << isairq);
     return isabus->irqs[isairq];
@@ -83,8 +81,7 @@ void isa_init_irq(ISADevice *dev, qemu_irq *p, int isairq)
 {
     assert(dev->nirqs < ARRAY_SIZE(dev->isairq));
     if (isabus->assigned & (1 << isairq)) {
-        fprintf(stderr, "isa irq %d already assigned\n", isairq);
-        exit(1);
+        hw_error("isa irq %d already assigned", isairq);
     }
     isabus->assigned |= (1 << isairq);
     dev->isairq[dev->nirqs] = isairq;
@@ -115,7 +112,7 @@ ISADevice *isa_create(const char *name)
     DeviceState *dev;
 
     if (!isabus) {
-        hw_error("Tried to create isa device %s with no isa bus present.\n",
+        hw_error("Tried to create isa device %s with no isa bus present.",
                  name);
     }
     dev = qdev_create(&isabus->qbus, name);
commit 34557491911f8977b5863628b1b6f5a9c95f9c29
Author: Alexander Graf <agraf at suse.de>
Date:   Wed Dec 8 12:05:50 2010 +0100

    usb_ohci: Always use little endian
    
    This patch replaces explicit bswaps with endianness hints to the
    mmio layer.
    
    Because we don't depend on the target endianness anymore, we can also
    move the driver over to Makefile.objs.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/Makefile.objs b/Makefile.objs
index 2b93598..cebb945 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -188,6 +188,7 @@ hw-obj-$(CONFIG_I8254) += i8254.o
 hw-obj-$(CONFIG_PCSPK) += pcspk.o
 hw-obj-$(CONFIG_PCKBD) += pckbd.o
 hw-obj-$(CONFIG_USB_UHCI) += usb-uhci.o
+hw-obj-$(CONFIG_USB_OHCI) += usb-ohci.o
 hw-obj-$(CONFIG_FDC) += fdc.o
 hw-obj-$(CONFIG_ACPI) += acpi.o acpi_piix4.o
 hw-obj-$(CONFIG_APM) += pm_smbus.o apm.o
diff --git a/Makefile.target b/Makefile.target
index 8bef8e3..d08f5dd 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -206,9 +206,6 @@ QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
 # xen backend driver support
 obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
 
-# USB layer
-obj-$(CONFIG_USB_OHCI) += usb-ohci.o
-
 # Inter-VM PCI shared memory
 obj-$(CONFIG_KVM) += ivshmem.o
 
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index ba1ebbc..8eb4a1e 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -1530,9 +1530,6 @@ static uint32_t ohci_mem_read(void *ptr, target_phys_addr_t addr)
         }
     }
 
-#ifdef TARGET_WORDS_BIGENDIAN
-    retval = bswap32(retval);
-#endif
     return retval;
 }
 
@@ -1542,10 +1539,6 @@ static void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val)
 
     addr &= 0xff;
 
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap32(val);
-#endif
-
     /* Only aligned reads are allowed on OHCI */
     if (addr & 3) {
         fprintf(stderr, "usb-ohci: Mis-aligned write\n");
@@ -1698,7 +1691,7 @@ static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
     }
 
     ohci->mem = cpu_register_io_memory(ohci_readfn, ohci_writefn, ohci,
-                                       DEVICE_NATIVE_ENDIAN);
+                                       DEVICE_LITTLE_ENDIAN);
     ohci->localmem_base = localmem_base;
 
     ohci->name = dev->info->name;
commit 968d683c042d80821a00a76608ae770a7401cac0
Author: Alexander Graf <agraf at suse.de>
Date:   Wed Dec 8 12:05:49 2010 +0100

    isa_mmio: Always use little endian
    
    This patch converts the ISA MMIO bridge code to always use little endian mmio.
    All bswap code that existed was only there to convert from native cpu
    endianness to little endian ISA devices.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/bonito.c b/hw/bonito.c
index fd90527..65a4a63 100644
--- a/hw/bonito.c
+++ b/hw/bonito.c
@@ -743,12 +743,12 @@ static int bonito_initfn(PCIDevice *dev)
     s->bonito_pciio_start = BONITO_PCIIO_BASE;
     s->bonito_pciio_length = BONITO_PCIIO_SIZE;
     isa_mem_base = s->bonito_pciio_start;
-    isa_mmio_init(s->bonito_pciio_start, s->bonito_pciio_length, 0);
+    isa_mmio_init(s->bonito_pciio_start, s->bonito_pciio_length);
 
     /* add pci local io mapping */
     s->bonito_localio_start = BONITO_DEV_BASE;
     s->bonito_localio_length = BONITO_DEV_SIZE;
-    isa_mmio_init(s->bonito_localio_start, s->bonito_localio_length, 0);
+    isa_mmio_init(s->bonito_localio_start, s->bonito_localio_length);
 
     /* set the default value of north bridge pci config */
     pci_set_word(dev->config + PCI_COMMAND, 0x0000);
diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c
index 51e4db0..14c6ad3 100644
--- a/hw/gt64xxx.c
+++ b/hw/gt64xxx.c
@@ -297,11 +297,7 @@ static void gt64120_pci_mapping(GT64120State *s)
       s->PCI0IO_start = s->regs[GT_PCI0IOLD] << 21;
       s->PCI0IO_length = ((s->regs[GT_PCI0IOHD] + 1) - (s->regs[GT_PCI0IOLD] & 0x7f)) << 21;
       isa_mem_base = s->PCI0IO_start;
-#ifdef TARGET_WORDS_BIGENDIAN
-      isa_mmio_init(s->PCI0IO_start, s->PCI0IO_length, 1);
-#else
-      isa_mmio_init(s->PCI0IO_start, s->PCI0IO_length, 0);
-#endif
+      isa_mmio_init(s->PCI0IO_start, s->PCI0IO_length);
     }
 }
 
diff --git a/hw/isa.h b/hw/isa.h
index aaf0272..e6848e4 100644
--- a/hw/isa.h
+++ b/hw/isa.h
@@ -32,7 +32,7 @@ ISADevice *isa_create_simple(const char *name);
 
 extern target_phys_addr_t isa_mem_base;
 
-void isa_mmio_init(target_phys_addr_t base, target_phys_addr_t size, int be);
+void isa_mmio_init(target_phys_addr_t base, target_phys_addr_t size);
 
 /* dma.c */
 int DMA_get_channel_mode (int nchan);
diff --git a/hw/isa_mmio.c b/hw/isa_mmio.c
index 46458f4..ca957fb 100644
--- a/hw/isa_mmio.c
+++ b/hw/isa_mmio.c
@@ -31,27 +31,13 @@ static void isa_mmio_writeb (void *opaque, target_phys_addr_t addr,
     cpu_outb(addr & IOPORTS_MASK, val);
 }
 
-static void isa_mmio_writew_be(void *opaque, target_phys_addr_t addr,
+static void isa_mmio_writew(void *opaque, target_phys_addr_t addr,
                                uint32_t val)
 {
-    val = bswap16(val);
     cpu_outw(addr & IOPORTS_MASK, val);
 }
 
-static void isa_mmio_writew_le(void *opaque, target_phys_addr_t addr,
-                               uint32_t val)
-{
-    cpu_outw(addr & IOPORTS_MASK, val);
-}
-
-static void isa_mmio_writel_be(void *opaque, target_phys_addr_t addr,
-                               uint32_t val)
-{
-    val = bswap32(val);
-    cpu_outl(addr & IOPORTS_MASK, val);
-}
-
-static void isa_mmio_writel_le(void *opaque, target_phys_addr_t addr,
+static void isa_mmio_writel(void *opaque, target_phys_addr_t addr,
                                uint32_t val)
 {
     cpu_outl(addr & IOPORTS_MASK, val);
@@ -59,86 +45,38 @@ static void isa_mmio_writel_le(void *opaque, target_phys_addr_t addr,
 
 static uint32_t isa_mmio_readb (void *opaque, target_phys_addr_t addr)
 {
-    uint32_t val;
-
-    val = cpu_inb(addr & IOPORTS_MASK);
-    return val;
+    return cpu_inb(addr & IOPORTS_MASK);
 }
 
-static uint32_t isa_mmio_readw_be(void *opaque, target_phys_addr_t addr)
+static uint32_t isa_mmio_readw(void *opaque, target_phys_addr_t addr)
 {
-    uint32_t val;
-
-    val = cpu_inw(addr & IOPORTS_MASK);
-    val = bswap16(val);
-    return val;
+    return cpu_inw(addr & IOPORTS_MASK);
 }
 
-static uint32_t isa_mmio_readw_le(void *opaque, target_phys_addr_t addr)
+static uint32_t isa_mmio_readl(void *opaque, target_phys_addr_t addr)
 {
-    uint32_t val;
-
-    val = cpu_inw(addr & IOPORTS_MASK);
-    return val;
+    return cpu_inl(addr & IOPORTS_MASK);
 }
 
-static uint32_t isa_mmio_readl_be(void *opaque, target_phys_addr_t addr)
-{
-    uint32_t val;
-
-    val = cpu_inl(addr & IOPORTS_MASK);
-    val = bswap32(val);
-    return val;
-}
-
-static uint32_t isa_mmio_readl_le(void *opaque, target_phys_addr_t addr)
-{
-    uint32_t val;
-
-    val = cpu_inl(addr & IOPORTS_MASK);
-    return val;
-}
-
-static CPUWriteMemoryFunc * const isa_mmio_write_be[] = {
-    &isa_mmio_writeb,
-    &isa_mmio_writew_be,
-    &isa_mmio_writel_be,
-};
-
-static CPUReadMemoryFunc * const isa_mmio_read_be[] = {
-    &isa_mmio_readb,
-    &isa_mmio_readw_be,
-    &isa_mmio_readl_be,
-};
-
-static CPUWriteMemoryFunc * const isa_mmio_write_le[] = {
+static CPUWriteMemoryFunc * const isa_mmio_write[] = {
     &isa_mmio_writeb,
-    &isa_mmio_writew_le,
-    &isa_mmio_writel_le,
+    &isa_mmio_writew,
+    &isa_mmio_writel,
 };
 
-static CPUReadMemoryFunc * const isa_mmio_read_le[] = {
+static CPUReadMemoryFunc * const isa_mmio_read[] = {
     &isa_mmio_readb,
-    &isa_mmio_readw_le,
-    &isa_mmio_readl_le,
+    &isa_mmio_readw,
+    &isa_mmio_readl,
 };
 
-static int isa_mmio_iomemtype = 0;
-
-void isa_mmio_init(target_phys_addr_t base, target_phys_addr_t size, int be)
+void isa_mmio_init(target_phys_addr_t base, target_phys_addr_t size)
 {
-    if (!isa_mmio_iomemtype) {
-        if (be) {
-            isa_mmio_iomemtype = cpu_register_io_memory(isa_mmio_read_be,
-                                                        isa_mmio_write_be,
-                                                        NULL,
-                                                        DEVICE_NATIVE_ENDIAN);
-        } else {
-            isa_mmio_iomemtype = cpu_register_io_memory(isa_mmio_read_le,
-                                                        isa_mmio_write_le,
-                                                        NULL,
-                                                        DEVICE_NATIVE_ENDIAN);
-        }
-    }
+    int isa_mmio_iomemtype;
+
+    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);
 }
diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c
index 1264743..a7caa3f 100644
--- a/hw/mips_jazz.c
+++ b/hw/mips_jazz.c
@@ -205,12 +205,7 @@ void mips_jazz_init (ram_addr_t ram_size,
     pcspk_init(pit);
 
     /* ISA IO space at 0x90000000 */
-#ifdef TARGET_WORDS_BIGENDIAN
-    isa_mmio_init(0x90000000, 0x01000000, 1);
-#else
-    isa_mmio_init(0x90000000, 0x01000000, 0);
-#endif
-
+    isa_mmio_init(0x90000000, 0x01000000);
     isa_mem_base = 0x11000000;
 
     /* Video card */
diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c
index 111c759..380a7eb 100644
--- a/hw/mips_mipssim.c
+++ b/hw/mips_mipssim.c
@@ -186,11 +186,7 @@ mips_mipssim_init (ram_addr_t ram_size,
     cpu_mips_clock_init(env);
 
     /* Register 64 KB of ISA IO space at 0x1fd00000. */
-#ifdef TARGET_WORDS_BIGENDIAN
-    isa_mmio_init(0x1fd00000, 0x00010000, 1);
-#else
-    isa_mmio_init(0x1fd00000, 0x00010000, 0);
-#endif
+    isa_mmio_init(0x1fd00000, 0x00010000);
 
     /* A single 16450 sits at offset 0x3f8. It is attached to
        MIPS CPU INT2, which is interrupt 4. */
diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c
index afe52f3..fb34dcf 100644
--- a/hw/mips_r4k.c
+++ b/hw/mips_r4k.c
@@ -271,11 +271,7 @@ void mips_r4k_init (ram_addr_t ram_size,
     rtc_init(2000, NULL);
 
     /* Register 64 KB of ISA IO space at 0x14000000 */
-#ifdef TARGET_WORDS_BIGENDIAN
-    isa_mmio_init(0x14000000, 0x00010000, 1);
-#else
-    isa_mmio_init(0x14000000, 0x00010000, 0);
-#endif
+    isa_mmio_init(0x14000000, 0x00010000);
     isa_mem_base = 0x10000000;
 
     pit = pit_init(0x40, i8259[0]);
diff --git a/hw/ppc440.c b/hw/ppc440.c
index d12cf71..1ed001a 100644
--- a/hw/ppc440.c
+++ b/hw/ppc440.c
@@ -85,7 +85,7 @@ CPUState *ppc440ep_init(ram_addr_t *ram_size, PCIBus **pcip,
     if (!*pcip)
         printf("couldn't create PCI controller!\n");
 
-    isa_mmio_init(PPC440EP_PCI_IO, PPC440EP_PCI_IOLEN, 1);
+    isa_mmio_init(PPC440EP_PCI_IO, PPC440EP_PCI_IOLEN);
 
     if (serial_hds[0] != NULL) {
         serial_mm_init(0xef600300, 0, pic[0], PPC_SERIAL_MM_BAUDBASE,
diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c
index 49b046b..b9245f0 100644
--- a/hw/ppc_newworld.c
+++ b/hw/ppc_newworld.c
@@ -257,7 +257,7 @@ static void ppc_core99_init (ram_addr_t ram_size,
     isa_mem_base = 0x80000000;
 
     /* Register 8 MB of ISA IO space */
-    isa_mmio_init(0xf2000000, 0x00800000, 1);
+    isa_mmio_init(0xf2000000, 0x00800000);
 
     /* UniN init */
     unin_memory = cpu_register_io_memory(unin_read, unin_write, NULL,
diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c
index 5efc93d..8a4e088 100644
--- a/hw/ppc_oldworld.c
+++ b/hw/ppc_oldworld.c
@@ -202,7 +202,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
     isa_mem_base = 0x80000000;
 
     /* Register 2 MB of ISA IO space */
-    isa_mmio_init(0xfe000000, 0x00200000, 1);
+    isa_mmio_init(0xfe000000, 0x00200000);
 
     /* XXX: we register only 1 output pin for heathrow PIC */
     heathrow_irqs = qemu_mallocz(smp_cpus * sizeof(qemu_irq *));
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 59d20d3..b7670ae 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -220,7 +220,7 @@ static void mpc8544ds_init(ram_addr_t ram_size,
     if (!pci_bus)
         printf("couldn't create PCI controller!\n");
 
-    isa_mmio_init(MPC8544_PCI_IO, MPC8544_PCI_IOLEN, 1);
+    isa_mmio_init(MPC8544_PCI_IO, MPC8544_PCI_IOLEN);
 
     if (pci_bus) {
         /* Register network interfaces. */
diff --git a/hw/sh_pci.c b/hw/sh_pci.c
index 6042d9c..072078b 100644
--- a/hw/sh_pci.c
+++ b/hw/sh_pci.c
@@ -54,7 +54,7 @@ static void sh_pci_reg_write (void *p, target_phys_addr_t addr, uint32_t val)
             cpu_register_physical_memory(pcic->iobr & 0xfffc0000, 0x40000,
                                          IO_MEM_UNASSIGNED);
             pcic->iobr = val & 0xfffc0001;
-            isa_mmio_init(pcic->iobr & 0xfffc0000, 0x40000, 0);
+            isa_mmio_init(pcic->iobr & 0xfffc0000, 0x40000);
         }
         break;
     case 0x220:
@@ -109,7 +109,7 @@ PCIBus *sh_pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
     cpu_register_physical_memory(0xfe200000, 0x224, reg);
 
     p->iobr = 0xfe240000;
-    isa_mmio_init(p->iobr, 0x40000, 0);
+    isa_mmio_init(p->iobr, 0x40000);
 
     pci_config_set_vendor_id(p->dev->config, PCI_VENDOR_ID_HITACHI);
     pci_config_set_device_id(p->dev->config, PCI_DEVICE_ID_HITACHI_SH7751R);
diff --git a/hw/sun4u.c b/hw/sun4u.c
index 5292ac6..90b1ce2 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -525,10 +525,10 @@ static void ebus_mmio_mapfunc(PCIDevice *pci_dev, int region_num,
                  region_num, addr);
     switch (region_num) {
     case 0:
-        isa_mmio_init(addr, 0x1000000, 1);
+        isa_mmio_init(addr, 0x1000000);
         break;
     case 1:
-        isa_mmio_init(addr, 0x800000, 1);
+        isa_mmio_init(addr, 0x800000);
         break;
     }
 }
diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c
index cc8f9f8..2fed8a0 100644
--- a/hw/versatile_pci.c
+++ b/hw/versatile_pci.c
@@ -96,11 +96,7 @@ static void pci_vpb_map(SysBusDevice *dev, target_phys_addr_t base)
 
     if (s->realview) {
         /* IO memory area.  */
-#ifdef TARGET_WORDS_BIGENDIAN
-        isa_mmio_init(base + 0x03000000, 0x00100000, 1);
-#else
-        isa_mmio_init(base + 0x03000000, 0x00100000, 0);
-#endif
+        isa_mmio_init(base + 0x03000000, 0x00100000);
     }
 }
 
commit b093c1a3277d4ce531a1a36f85dd542c60db3809
Author: Alexander Graf <agraf at suse.de>
Date:   Wed Dec 8 12:05:48 2010 +0100

    heathrow_pic: Declare as little endian
    
    This patch replaces explicit bswaps with endianness hints to the
    mmio layer.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/heathrow_pic.c b/hw/heathrow_pic.c
index 390b63c..b19b754 100644
--- a/hw/heathrow_pic.c
+++ b/hw/heathrow_pic.c
@@ -68,7 +68,6 @@ static void pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
     HeathrowPIC *pic;
     unsigned int n;
 
-    value = bswap32(value);
     n = ((addr & 0xfff) - 0x10) >> 4;
     PIC_DPRINTF("writel: " TARGET_FMT_plx " %u: %08x\n", addr, n, value);
     if (n >= 2)
@@ -118,7 +117,6 @@ static uint32_t pic_readl (void *opaque, target_phys_addr_t addr)
         }
     }
     PIC_DPRINTF("readl: " TARGET_FMT_plx " %u: %08x\n", addr, n, value);
-    value = bswap32(value);
     return value;
 }
 
@@ -223,7 +221,7 @@ qemu_irq *heathrow_pic_init(int *pmem_index,
     /* only 1 CPU */
     s->irqs = irqs[0];
     *pmem_index = cpu_register_io_memory(pic_read, pic_write, s,
-                                         DEVICE_NATIVE_ENDIAN);
+                                         DEVICE_LITTLE_ENDIAN);
 
     register_savevm(NULL, "heathrow_pic", -1, 1, heathrow_pic_save,
                     heathrow_pic_load, s);
commit 5cf7a3ca5bfec0c62bd7ebdecd11320c47dc9be6
Author: Alexander Graf <agraf at suse.de>
Date:   Wed Dec 8 12:05:47 2010 +0100

    rtl8139: Declare as little endian
    
    This patch replaces explicit bswaps with endianness hints to the
    mmio layer.
    
    Because we don't depend on the target endianness anymore, we can also
    move the driver over to Makefile.objs.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/Makefile.objs b/Makefile.objs
index 29b1ede..2b93598 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -225,6 +225,7 @@ hw-obj-$(CONFIG_EEPRO100_PCI) += eepro100.o
 hw-obj-$(CONFIG_PCNET_PCI) += pcnet-pci.o
 hw-obj-$(CONFIG_PCNET_COMMON) += pcnet.o
 hw-obj-$(CONFIG_E1000_PCI) += e1000.o
+hw-obj-$(CONFIG_RTL8139_PCI) += rtl8139.o
 
 hw-obj-$(CONFIG_SMC91C111) += smc91c111.o
 hw-obj-$(CONFIG_LAN9118) += lan9118.o
diff --git a/Makefile.target b/Makefile.target
index 39d8df9..8bef8e3 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -209,9 +209,6 @@ obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
 # USB layer
 obj-$(CONFIG_USB_OHCI) += usb-ohci.o
 
-# PCI network cards
-obj-$(CONFIG_RTL8139_PCI) += rtl8139.o
-
 # Inter-VM PCI shared memory
 obj-$(CONFIG_KVM) += ivshmem.o
 
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 30a3960..4a73f6f 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -3125,17 +3125,11 @@ static void rtl8139_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t
 
 static void rtl8139_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap16(val);
-#endif
     rtl8139_io_writew(opaque, addr & 0xFF, val);
 }
 
 static void rtl8139_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap32(val);
-#endif
     rtl8139_io_writel(opaque, addr & 0xFF, val);
 }
 
@@ -3147,18 +3141,12 @@ static uint32_t rtl8139_mmio_readb(void *opaque, target_phys_addr_t addr)
 static uint32_t rtl8139_mmio_readw(void *opaque, target_phys_addr_t addr)
 {
     uint32_t val = rtl8139_io_readw(opaque, addr & 0xFF);
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap16(val);
-#endif
     return val;
 }
 
 static uint32_t rtl8139_mmio_readl(void *opaque, target_phys_addr_t addr)
 {
     uint32_t val = rtl8139_io_readl(opaque, addr & 0xFF);
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap32(val);
-#endif
     return val;
 }
 
@@ -3367,7 +3355,7 @@ static int pci_rtl8139_init(PCIDevice *dev)
     /* 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_NATIVE_ENDIAN);
+                               DEVICE_LITTLE_ENDIAN);
 
     pci_register_bar(&s->dev, 0, 0x100,
                            PCI_BASE_ADDRESS_SPACE_IO,  rtl8139_ioport_map);
commit 82600641c1bb09611ea5e82be7589c86027787a0
Author: Alexander Graf <agraf at suse.de>
Date:   Wed Dec 8 12:05:46 2010 +0100

    openpic: Replace explicit byte swap with endian hints
    
    This patch replaces explicit bswaps with endianness hints to the
    mmio layer.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/openpic.c b/hw/openpic.c
index 9e2500a..6d2cf99 100644
--- a/hw/openpic.c
+++ b/hw/openpic.c
@@ -242,19 +242,10 @@ typedef struct openpic_t {
     int max_irq;
     int irq_ipi0;
     int irq_tim0;
-    int need_swap;
     void (*reset) (void *);
     void (*irq_raise) (struct openpic_t *, int, IRQ_src_t *);
 } openpic_t;
 
-static inline uint32_t openpic_swap32(openpic_t *opp, uint32_t val)
-{
-    if (opp->need_swap)
-        return bswap32(val);
-
-    return val;
-}
-
 static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ)
 {
     set_bit(q->queue, n_IRQ);
@@ -599,7 +590,6 @@ static void openpic_gbl_write (void *opaque, target_phys_addr_t addr, uint32_t v
     DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
     if (addr & 0xF)
         return;
-    val = openpic_swap32(opp, val);
     addr &= 0xFF;
     switch (addr) {
     case 0x00: /* FREP */
@@ -693,7 +683,6 @@ static uint32_t openpic_gbl_read (void *opaque, target_phys_addr_t addr)
         break;
     }
     DPRINTF("%s: => %08x\n", __func__, retval);
-    retval = openpic_swap32(opp, retval);
 
     return retval;
 }
@@ -706,7 +695,6 @@ static void openpic_timer_write (void *opaque, uint32_t addr, uint32_t val)
     DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
     if (addr & 0xF)
         return;
-    val = openpic_swap32(opp, val);
     addr -= 0x1100;
     addr &= 0xFFFF;
     idx = (addr & 0xFFF0) >> 6;
@@ -759,7 +747,6 @@ static uint32_t openpic_timer_read (void *opaque, uint32_t addr)
         break;
     }
     DPRINTF("%s: => %08x\n", __func__, retval);
-    retval = openpic_swap32(opp, retval);
 
     return retval;
 }
@@ -772,7 +759,6 @@ static void openpic_src_write (void *opaque, uint32_t addr, uint32_t val)
     DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
     if (addr & 0xF)
         return;
-    val = openpic_swap32(opp, val);
     addr = addr & 0xFFF0;
     idx = addr >> 5;
     if (addr & 0x10) {
@@ -804,7 +790,6 @@ static uint32_t openpic_src_read (void *opaque, uint32_t addr)
         retval = read_IRQreg(opp, idx, IRQ_IPVP);
     }
     DPRINTF("%s: => %08x\n", __func__, retval);
-    retval = openpic_swap32(opp, retval);
 
     return retval;
 }
@@ -819,7 +804,6 @@ static void openpic_cpu_write (void *opaque, target_phys_addr_t addr, uint32_t v
     DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
     if (addr & 0xF)
         return;
-    val = openpic_swap32(opp, val);
     addr &= 0x1FFF0;
     idx = addr / 0x1000;
     dst = &opp->dst[idx];
@@ -937,7 +921,6 @@ static uint32_t openpic_cpu_read (void *opaque, target_phys_addr_t addr)
         break;
     }
     DPRINTF("%s: => %08x\n", __func__, retval);
-    retval = openpic_swap32(opp, retval);
 
     return retval;
 }
@@ -1204,7 +1187,7 @@ qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
         opp = qemu_mallocz(sizeof(openpic_t));
     }
     opp->mem_index = cpu_register_io_memory(openpic_read, openpic_write, opp,
-                                            DEVICE_NATIVE_ENDIAN);
+                                            DEVICE_LITTLE_ENDIAN);
 
     //    isu_base &= 0xFFFC0000;
     opp->nb_cpus = nb_cpus;
@@ -1232,7 +1215,6 @@ qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
     for (i = 0; i < nb_cpus; i++)
         opp->dst[i].irqs = irqs[i];
     opp->irq_out = irq_out;
-    opp->need_swap = 1;
 
     register_savevm(&opp->pci_dev.qdev, "openpic", 0, 2,
                     openpic_save, openpic_load, opp);
@@ -1673,7 +1655,7 @@ qemu_irq *mpic_init (target_phys_addr_t base, int nb_cpus,
         int mem_index;
 
         mem_index = cpu_register_io_memory(list[i].read, list[i].write, mpp,
-                                           DEVICE_NATIVE_ENDIAN);
+                                           DEVICE_BIG_ENDIAN);
         if (mem_index < 0) {
             goto free;
         }
@@ -1689,7 +1671,6 @@ qemu_irq *mpic_init (target_phys_addr_t base, int nb_cpus,
     for (i = 0; i < nb_cpus; i++)
         mpp->dst[i].irqs = irqs[i];
     mpp->irq_out = irq_out;
-    mpp->need_swap = 0;    /* MPIC has the same endian as target */
 
     mpp->irq_raise = mpic_irq_raise;
     mpp->reset = mpic_reset;
commit 0d2a73b3abe4d8380579bfeed39530a4b6c597ad
Author: Alexander Graf <agraf at suse.de>
Date:   Wed Dec 8 12:05:45 2010 +0100

    ppc4xx_pci: Declare as little endian
    
    This patch replaces explicit bswaps with endianness hints to the
    mmio layer.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c
index f2ecece..f62f1f9 100644
--- a/hw/ppc4xx_pci.c
+++ b/hw/ppc4xx_pci.c
@@ -24,7 +24,6 @@
 #include "ppc4xx.h"
 #include "pci.h"
 #include "pci_host.h"
-#include "bswap.h"
 
 #undef DEBUG
 #ifdef DEBUG
@@ -102,10 +101,6 @@ static void pci4xx_cfgaddr_writel(void *opaque, target_phys_addr_t addr,
 {
     PPC4xxPCIState *ppc4xx_pci = opaque;
 
-#ifdef TARGET_WORDS_BIGENDIAN
-    value = bswap32(value);
-#endif
-
     ppc4xx_pci->pci_state.config_reg = value & ~0x3;
 }
 
@@ -120,10 +115,6 @@ static void ppc4xx_pci_reg_write4(void *opaque, target_phys_addr_t offset,
 {
     struct PPC4xxPCIState *pci = opaque;
 
-#ifdef TARGET_WORDS_BIGENDIAN
-    value = bswap32(value);
-#endif
-
     /* We ignore all target attempts at PCI configuration, effectively
      * assuming a bidirectional 1:1 mapping of PLB and PCI space. */
 
@@ -251,10 +242,6 @@ static uint32_t ppc4xx_pci_reg_read4(void *opaque, target_phys_addr_t offset)
         value = 0;
     }
 
-#ifdef TARGET_WORDS_BIGENDIAN
-    value = bswap32(value);
-#endif
-
     return value;
 }
 
@@ -373,7 +360,7 @@ PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4],
     /* CFGADDR */
     index = cpu_register_io_memory(pci4xx_cfgaddr_read,
                                    pci4xx_cfgaddr_write, controller,
-                                   DEVICE_NATIVE_ENDIAN);
+                                   DEVICE_LITTLE_ENDIAN);
     if (index < 0)
         goto free;
     cpu_register_physical_memory(config_space + PCIC0_CFGADDR, 4, index);
@@ -386,7 +373,7 @@ PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4],
 
     /* Internal registers */
     index = cpu_register_io_memory(pci_reg_read, pci_reg_write, controller,
-                                   DEVICE_NATIVE_ENDIAN);
+                                   DEVICE_LITTLE_ENDIAN);
     if (index < 0)
         goto free;
     cpu_register_physical_memory(registers, PCI_REG_SIZE, index);
commit 387c3e96bf34222f265d005b6b7aaef0b01ae6e9
Author: Alexander Graf <agraf at suse.de>
Date:   Wed Dec 8 12:05:44 2010 +0100

    versatile_pci: Declare as little endian
    
    This patch replaces explicit bswaps with endianness hints to the
    mmio layer.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c
index 3baad96..cc8f9f8 100644
--- a/hw/versatile_pci.c
+++ b/hw/versatile_pci.c
@@ -32,18 +32,12 @@ static void pci_vpb_config_writeb (void *opaque, target_phys_addr_t addr,
 static void pci_vpb_config_writew (void *opaque, target_phys_addr_t addr,
                                    uint32_t val)
 {
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap16(val);
-#endif
     pci_data_write(opaque, vpb_pci_config_addr (addr), val, 2);
 }
 
 static void pci_vpb_config_writel (void *opaque, target_phys_addr_t addr,
                                    uint32_t val)
 {
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap32(val);
-#endif
     pci_data_write(opaque, vpb_pci_config_addr (addr), val, 4);
 }
 
@@ -58,9 +52,6 @@ static uint32_t pci_vpb_config_readw (void *opaque, target_phys_addr_t addr)
 {
     uint32_t val;
     val = pci_data_read(opaque, vpb_pci_config_addr (addr), 2);
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap16(val);
-#endif
     return val;
 }
 
@@ -68,9 +59,6 @@ static uint32_t pci_vpb_config_readl (void *opaque, target_phys_addr_t addr)
 {
     uint32_t val;
     val = pci_data_read(opaque, vpb_pci_config_addr (addr), 4);
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap32(val);
-#endif
     return val;
 }
 
@@ -133,7 +121,7 @@ static int pci_vpb_init(SysBusDevice *dev)
 
     s->mem_config = cpu_register_io_memory(pci_vpb_config_read,
                                            pci_vpb_config_write, bus,
-                                           DEVICE_NATIVE_ENDIAN);
+                                           DEVICE_LITTLE_ENDIAN);
     sysbus_init_mmio_cb(dev, 0x04000000, pci_vpb_map);
 
     pci_create_simple(bus, -1, "versatile_pci_host");
commit 8cb7da56188bbf6b083df5d6f1a7f5db6ec17dda
Author: Alexander Graf <agraf at suse.de>
Date:   Wed Dec 8 12:05:43 2010 +0100

    prep: Declare as little endian
    
    This patch replaces explicit bswaps with endianness hints to the
    mmio layer.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 80f5db6..1492266 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -145,20 +145,12 @@ static uint32_t PPC_intack_readb (void *opaque, target_phys_addr_t addr)
 
 static uint32_t PPC_intack_readw (void *opaque, target_phys_addr_t addr)
 {
-#ifdef TARGET_WORDS_BIGENDIAN
-    return bswap16(_PPC_intack_read(addr));
-#else
     return _PPC_intack_read(addr);
-#endif
 }
 
 static uint32_t PPC_intack_readl (void *opaque, target_phys_addr_t addr)
 {
-#ifdef TARGET_WORDS_BIGENDIAN
-    return bswap32(_PPC_intack_read(addr));
-#else
     return _PPC_intack_read(addr);
-#endif
 }
 
 static CPUWriteMemoryFunc * const PPC_intack_write[] = {
@@ -210,9 +202,6 @@ static void PPC_XCSR_writeb (void *opaque,
 static void PPC_XCSR_writew (void *opaque,
                              target_phys_addr_t addr, uint32_t value)
 {
-#ifdef TARGET_WORDS_BIGENDIAN
-    value = bswap16(value);
-#endif
     printf("%s: 0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", __func__, addr,
            value);
 }
@@ -220,9 +209,6 @@ static void PPC_XCSR_writew (void *opaque,
 static void PPC_XCSR_writel (void *opaque,
                              target_phys_addr_t addr, uint32_t value)
 {
-#ifdef TARGET_WORDS_BIGENDIAN
-    value = bswap32(value);
-#endif
     printf("%s: 0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", __func__, addr,
            value);
 }
@@ -243,9 +229,6 @@ static uint32_t PPC_XCSR_readw (void *opaque, target_phys_addr_t addr)
 
     printf("%s: 0x" TARGET_FMT_plx " <= %08" PRIx32 "\n", __func__, addr,
            retval);
-#ifdef TARGET_WORDS_BIGENDIAN
-    retval = bswap16(retval);
-#endif
 
     return retval;
 }
@@ -256,9 +239,6 @@ static uint32_t PPC_XCSR_readl (void *opaque, target_phys_addr_t addr)
 
     printf("%s: 0x" TARGET_FMT_plx " <= %08" PRIx32 "\n", __func__, addr,
            retval);
-#ifdef TARGET_WORDS_BIGENDIAN
-    retval = bswap32(retval);
-#endif
 
     return retval;
 }
@@ -484,9 +464,6 @@ static void PPC_prep_io_writew (void *opaque, target_phys_addr_t addr,
     sysctrl_t *sysctrl = opaque;
 
     addr = prep_IO_address(sysctrl, addr);
-#ifdef TARGET_WORDS_BIGENDIAN
-    value = bswap16(value);
-#endif
     PPC_IO_DPRINTF("0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", addr, value);
     cpu_outw(addr, value);
 }
@@ -498,9 +475,6 @@ static uint32_t PPC_prep_io_readw (void *opaque, target_phys_addr_t addr)
 
     addr = prep_IO_address(sysctrl, addr);
     ret = cpu_inw(addr);
-#ifdef TARGET_WORDS_BIGENDIAN
-    ret = bswap16(ret);
-#endif
     PPC_IO_DPRINTF("0x" TARGET_FMT_plx " <= 0x%08" PRIx32 "\n", addr, ret);
 
     return ret;
@@ -512,9 +486,6 @@ static void PPC_prep_io_writel (void *opaque, target_phys_addr_t addr,
     sysctrl_t *sysctrl = opaque;
 
     addr = prep_IO_address(sysctrl, addr);
-#ifdef TARGET_WORDS_BIGENDIAN
-    value = bswap32(value);
-#endif
     PPC_IO_DPRINTF("0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", addr, value);
     cpu_outl(addr, value);
 }
@@ -526,9 +497,6 @@ static uint32_t PPC_prep_io_readl (void *opaque, target_phys_addr_t addr)
 
     addr = prep_IO_address(sysctrl, addr);
     ret = cpu_inl(addr);
-#ifdef TARGET_WORDS_BIGENDIAN
-    ret = bswap32(ret);
-#endif
     PPC_IO_DPRINTF("0x" TARGET_FMT_plx " <= 0x%08" PRIx32 "\n", addr, ret);
 
     return ret;
@@ -691,7 +659,7 @@ static void ppc_prep_init (ram_addr_t ram_size,
     /* Register 8 MB of ISA IO space (needed for non-contiguous map) */
     PPC_io_memory = cpu_register_io_memory(PPC_prep_io_read,
                                            PPC_prep_io_write, sysctrl,
-                                           DEVICE_NATIVE_ENDIAN);
+                                           DEVICE_LITTLE_ENDIAN);
     cpu_register_physical_memory(0x80000000, 0x00800000, PPC_io_memory);
 
     /* init basic PC hardware */
@@ -757,12 +725,12 @@ static void ppc_prep_init (ram_addr_t ram_size,
     /* PCI intack location */
     PPC_io_memory = cpu_register_io_memory(PPC_intack_read,
                                            PPC_intack_write, NULL,
-                                           DEVICE_NATIVE_ENDIAN);
+                                           DEVICE_LITTLE_ENDIAN);
     cpu_register_physical_memory(0xBFFFFFF0, 0x4, PPC_io_memory);
     /* PowerPC control and status register group */
 #if 0
     PPC_io_memory = cpu_register_io_memory(PPC_XCSR_read, PPC_XCSR_write,
-                                           NULL, DEVICE_NATIVE_ENDIAN);
+                                           NULL, DEVICE_LITTLE_ENDIAN);
     cpu_register_physical_memory(0xFEFF0000, 0x1000, PPC_io_memory);
 #endif
 
commit 32600a309f34ab173bbb79de73e85b7879d235bf
Author: Alexander Graf <agraf at suse.de>
Date:   Wed Dec 8 12:05:42 2010 +0100

    e1000: Make little endian
    
    The e1000 has compatibility code to handle big endianness which makes it
    mandatory to be recompiled on different targets.
    
    With the generic mmio endianness solution, there's no need for that anymore.
    We just declare all mmio to be little endian and call it a day.
    
    Because we don't depend on the target endianness anymore, we can also
    move the driver over to Makefile.objs.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/Makefile.objs b/Makefile.objs
index 04625eb..29b1ede 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -224,6 +224,7 @@ hw-obj-$(CONFIG_NE2000_PCI) += ne2000.o
 hw-obj-$(CONFIG_EEPRO100_PCI) += eepro100.o
 hw-obj-$(CONFIG_PCNET_PCI) += pcnet-pci.o
 hw-obj-$(CONFIG_PCNET_COMMON) += pcnet.o
+hw-obj-$(CONFIG_E1000_PCI) += e1000.o
 
 hw-obj-$(CONFIG_SMC91C111) += smc91c111.o
 hw-obj-$(CONFIG_LAN9118) += lan9118.o
diff --git a/Makefile.target b/Makefile.target
index 5784844..39d8df9 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -211,7 +211,6 @@ obj-$(CONFIG_USB_OHCI) += usb-ohci.o
 
 # PCI network cards
 obj-$(CONFIG_RTL8139_PCI) += rtl8139.o
-obj-$(CONFIG_E1000_PCI) += e1000.o
 
 # Inter-VM PCI shared memory
 obj-$(CONFIG_KVM) += ivshmem.o
diff --git a/hw/e1000.c b/hw/e1000.c
index bf3f2d3..a697abd 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -857,9 +857,6 @@ e1000_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
     E1000State *s = opaque;
     unsigned int index = (addr & 0x1ffff) >> 2;
 
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap32(val);
-#endif
     if (index < NWRITEOPS && macreg_writeops[index]) {
         macreg_writeops[index](s, index, val);
     } else if (index < NREADOPS && macreg_readops[index]) {
@@ -894,11 +891,7 @@ e1000_mmio_readl(void *opaque, target_phys_addr_t addr)
 
     if (index < NREADOPS && macreg_readops[index])
     {
-        uint32_t val = macreg_readops[index](s, index);
-#ifdef TARGET_WORDS_BIGENDIAN
-        val = bswap32(val);
-#endif
-        return val;
+        return macreg_readops[index](s, index);
     }
     DBGOUT(UNKNOWN, "MMIO unknown read addr=0x%08x\n", index<<2);
     return 0;
@@ -1131,7 +1124,7 @@ static int pci_e1000_init(PCIDevice *pci_dev)
     pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0
 
     d->mmio_index = cpu_register_io_memory(e1000_mmio_read,
-            e1000_mmio_write, d, DEVICE_NATIVE_ENDIAN);
+            e1000_mmio_write, d, DEVICE_LITTLE_ENDIAN);
 
     pci_register_bar(&d->dev, 0, PNPMMIO_SIZE,
                            PCI_BASE_ADDRESS_SPACE_MEMORY, e1000_mmio_map);
commit f23cea4d04287c2e7c1bb614c84c3b0086bcb7d3
Author: Alexander Graf <agraf at suse.de>
Date:   Wed Dec 8 12:05:41 2010 +0100

    uninorth: Get rid of bswap
    
    There's no need to bswap once we correctly set the mmio to be little endian.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/unin_pci.c b/hw/unin_pci.c
index f2e440e..5f15058 100644
--- a/hw/unin_pci.c
+++ b/hw/unin_pci.c
@@ -121,7 +121,6 @@ static void unin_data_write(ReadWriteHandler *handler,
                             pcibus_t addr, uint32_t val, int len)
 {
     UNINState *s = container_of(handler, UNINState, data_handler);
-    val = qemu_bswap_len(val, len);
     UNIN_DPRINTF("write addr %" FMT_PCIBUS " len %d val %x\n", addr, len, val);
     pci_data_write(s->host_state.bus,
                    unin_get_config_reg(s->host_state.config_reg, addr),
@@ -138,7 +137,6 @@ static uint32_t unin_data_read(ReadWriteHandler *handler,
                         unin_get_config_reg(s->host_state.config_reg, addr),
                         len);
     UNIN_DPRINTF("read addr %" FMT_PCIBUS " len %d val %x\n", addr, len, val);
-    val = qemu_bswap_len(val, len);
     return val;
 }
 
@@ -156,7 +154,7 @@ static int pci_unin_main_init_device(SysBusDevice *dev)
     s->data_handler.read = unin_data_read;
     s->data_handler.write = unin_data_write;
     pci_mem_data = cpu_register_io_memory_simple(&s->data_handler,
-                                                 DEVICE_NATIVE_ENDIAN);
+                                                 DEVICE_LITTLE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, pci_mem_config);
     sysbus_init_mmio(dev, 0x1000, pci_mem_data);
 
@@ -179,7 +177,7 @@ static int pci_u3_agp_init_device(SysBusDevice *dev)
     s->data_handler.read = unin_data_read;
     s->data_handler.write = unin_data_write;
     pci_mem_data = cpu_register_io_memory_simple(&s->data_handler,
-                                                 DEVICE_NATIVE_ENDIAN);
+                                                 DEVICE_LITTLE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, pci_mem_config);
     sysbus_init_mmio(dev, 0x1000, pci_mem_data);
 
commit 6ebf5905f4a664a873cf7f49094960f08cb3a2d5
Author: Alexander Graf <agraf at suse.de>
Date:   Wed Dec 8 12:05:40 2010 +0100

    pci-host: Delegate bswap to mmio layer
    
    The only reason we have bswap versions of the pci host code is that
    most pci host devices are little endian. The ppc e500 is the only
    odd one here, being big endian.
    
    So let's directly pass the endianness down to the mmio layer and not
    worry about it on the pci host layer.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/dec_pci.c b/hw/dec_pci.c
index aa07ab7..bf88f2a 100644
--- a/hw/dec_pci.c
+++ b/hw/dec_pci.c
@@ -96,8 +96,10 @@ static int pci_dec_21154_init_device(SysBusDevice *dev)
 
     s = FROM_SYSBUS(DECState, dev);
 
-    pci_mem_config = pci_host_conf_register_mmio(&s->host_state, 1);
-    pci_mem_data = pci_host_data_register_mmio(&s->host_state, 1);
+    pci_mem_config = pci_host_conf_register_mmio(&s->host_state,
+                                                 DEVICE_LITTLE_ENDIAN);
+    pci_mem_data = pci_host_data_register_mmio(&s->host_state,
+                                               DEVICE_LITTLE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, pci_mem_config);
     sysbus_init_mmio(dev, 0x1000, pci_mem_data);
     return 0;
diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c
index 91c755f..bd3d6b0 100644
--- a/hw/grackle_pci.c
+++ b/hw/grackle_pci.c
@@ -108,8 +108,10 @@ static int pci_grackle_init_device(SysBusDevice *dev)
 
     s = FROM_SYSBUS(GrackleState, dev);
 
-    pci_mem_config = pci_host_conf_register_mmio(&s->host_state, 1);
-    pci_mem_data = pci_host_data_register_mmio(&s->host_state, 1);
+    pci_mem_config = pci_host_conf_register_mmio(&s->host_state,
+                                                 DEVICE_LITTLE_ENDIAN);
+    pci_mem_data = pci_host_data_register_mmio(&s->host_state,
+                                               DEVICE_LITTLE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, pci_mem_config);
     sysbus_init_mmio(dev, 0x1000, pci_mem_data);
 
diff --git a/hw/pci_host.c b/hw/pci_host.c
index a6e39c9..eebff7a 100644
--- a/hw/pci_host.c
+++ b/hw/pci_host.c
@@ -78,64 +78,39 @@ uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len)
     return val;
 }
 
-static void pci_host_config_write_swap(ReadWriteHandler *handler,
-                                       pcibus_t addr, uint32_t val, int len)
+static void pci_host_config_write(ReadWriteHandler *handler,
+                                  pcibus_t addr, uint32_t val, int len)
 {
     PCIHostState *s = container_of(handler, PCIHostState, conf_handler);
 
     PCI_DPRINTF("%s addr %" FMT_PCIBUS " %d val %"PRIx32"\n",
                 __func__, addr, len, val);
-    val = qemu_bswap_len(val, len);
     s->config_reg = val;
 }
 
-static uint32_t pci_host_config_read_swap(ReadWriteHandler *handler,
-                                          pcibus_t addr, int len)
+static uint32_t pci_host_config_read(ReadWriteHandler *handler,
+                                     pcibus_t addr, int len)
 {
     PCIHostState *s = container_of(handler, PCIHostState, conf_handler);
     uint32_t val = s->config_reg;
 
-    val = qemu_bswap_len(val, len);
     PCI_DPRINTF("%s addr %" FMT_PCIBUS " len %d val %"PRIx32"\n",
                 __func__, addr, len, val);
     return val;
 }
 
-static void pci_host_config_write_noswap(ReadWriteHandler *handler,
-                                         pcibus_t addr, uint32_t val, int len)
-{
-    PCIHostState *s = container_of(handler, PCIHostState, conf_noswap_handler);
-
-    PCI_DPRINTF("%s addr %" FMT_PCIBUS " %d val %"PRIx32"\n",
-                __func__, addr, len, val);
-    s->config_reg = val;
-}
-
-static uint32_t pci_host_config_read_noswap(ReadWriteHandler *handler,
-                                            pcibus_t addr, int len)
-{
-    PCIHostState *s = container_of(handler, PCIHostState, conf_noswap_handler);
-    uint32_t val = s->config_reg;
-
-    PCI_DPRINTF("%s addr %" FMT_PCIBUS " len %d val %"PRIx32"\n",
-                __func__, addr, len, val);
-    return val;
-}
-
-static void pci_host_data_write_swap(ReadWriteHandler *handler,
-                                     pcibus_t addr, uint32_t val, int len)
+static void pci_host_data_write(ReadWriteHandler *handler,
+                                pcibus_t addr, uint32_t val, int len)
 {
     PCIHostState *s = container_of(handler, PCIHostState, data_handler);
-
-    val = qemu_bswap_len(val, len);
     PCI_DPRINTF("write addr %" FMT_PCIBUS " len %d val %x\n",
                 addr, len, val);
     if (s->config_reg & (1u << 31))
         pci_data_write(s->bus, s->config_reg | (addr & 3), val, len);
 }
 
-static uint32_t pci_host_data_read_swap(ReadWriteHandler *handler,
-                                        pcibus_t addr, int len)
+static uint32_t pci_host_data_read(ReadWriteHandler *handler,
+                                   pcibus_t addr, int len)
 {
     PCIHostState *s = container_of(handler, PCIHostState, data_handler);
     uint32_t val;
@@ -144,79 +119,39 @@ static uint32_t pci_host_data_read_swap(ReadWriteHandler *handler,
     val = pci_data_read(s->bus, s->config_reg | (addr & 3), len);
     PCI_DPRINTF("read addr %" FMT_PCIBUS " len %d val %x\n",
                 addr, len, val);
-    val = qemu_bswap_len(val, len);
-    return val;
-}
-
-static void pci_host_data_write_noswap(ReadWriteHandler *handler,
-                                       pcibus_t addr, uint32_t val, int len)
-{
-    PCIHostState *s = container_of(handler, PCIHostState, data_noswap_handler);
-    PCI_DPRINTF("write addr %" FMT_PCIBUS " len %d val %x\n",
-                addr, len, val);
-    if (s->config_reg & (1u << 31))
-        pci_data_write(s->bus, s->config_reg | (addr & 3), val, len);
-}
-
-static uint32_t pci_host_data_read_noswap(ReadWriteHandler *handler,
-                                          pcibus_t addr, int len)
-{
-    PCIHostState *s = container_of(handler, PCIHostState, data_noswap_handler);
-    uint32_t val;
-    if (!(s->config_reg & (1 << 31)))
-        return 0xffffffff;
-    val = pci_data_read(s->bus, s->config_reg | (addr & 3), len);
-    PCI_DPRINTF("read addr %" FMT_PCIBUS " len %d val %x\n",
-                addr, len, val);
     return val;
 }
 
 static void pci_host_init(PCIHostState *s)
 {
-    s->conf_handler.write = pci_host_config_write_swap;
-    s->conf_handler.read = pci_host_config_read_swap;
-    s->conf_noswap_handler.write = pci_host_config_write_noswap;
-    s->conf_noswap_handler.read = pci_host_config_read_noswap;
-    s->data_handler.write = pci_host_data_write_swap;
-    s->data_handler.read = pci_host_data_read_swap;
-    s->data_noswap_handler.write = pci_host_data_write_noswap;
-    s->data_noswap_handler.read = pci_host_data_read_noswap;
+    s->conf_handler.write = pci_host_config_write;
+    s->conf_handler.read = pci_host_config_read;
+    s->data_handler.write = pci_host_data_write;
+    s->data_handler.read = pci_host_data_read;
 }
 
-int pci_host_conf_register_mmio(PCIHostState *s, int swap)
+int pci_host_conf_register_mmio(PCIHostState *s, int endian)
 {
     pci_host_init(s);
-    if (swap) {
-        return cpu_register_io_memory_simple(&s->conf_handler,
-                                             DEVICE_NATIVE_ENDIAN);
-    } else {
-        return cpu_register_io_memory_simple(&s->conf_noswap_handler,
-                                             DEVICE_NATIVE_ENDIAN);
-    }
+    return cpu_register_io_memory_simple(&s->conf_handler, endian);
 }
 
 void pci_host_conf_register_ioport(pio_addr_t ioport, PCIHostState *s)
 {
     pci_host_init(s);
-    register_ioport_simple(&s->conf_noswap_handler, ioport, 4, 4);
+    register_ioport_simple(&s->conf_handler, ioport, 4, 4);
 }
 
-int pci_host_data_register_mmio(PCIHostState *s, int swap)
+int pci_host_data_register_mmio(PCIHostState *s, int endian)
 {
     pci_host_init(s);
-    if (swap) {
-        return cpu_register_io_memory_simple(&s->data_handler,
-                                             DEVICE_NATIVE_ENDIAN);
-    } else {
-        return cpu_register_io_memory_simple(&s->data_noswap_handler,
-                                             DEVICE_NATIVE_ENDIAN);
-    }
+    return cpu_register_io_memory_simple(&s->data_handler, endian);
 }
 
 void pci_host_data_register_ioport(pio_addr_t ioport, PCIHostState *s)
 {
     pci_host_init(s);
-    register_ioport_simple(&s->data_noswap_handler, ioport, 4, 1);
-    register_ioport_simple(&s->data_noswap_handler, ioport, 4, 2);
-    register_ioport_simple(&s->data_noswap_handler, ioport, 4, 4);
+    register_ioport_simple(&s->data_handler, ioport, 4, 1);
+    register_ioport_simple(&s->data_handler, ioport, 4, 2);
+    register_ioport_simple(&s->data_handler, ioport, 4, 4);
 }
diff --git a/hw/pci_host.h b/hw/pci_host.h
index bd8ede8..0a58595 100644
--- a/hw/pci_host.h
+++ b/hw/pci_host.h
@@ -33,9 +33,7 @@
 
 struct PCIHostState {
     SysBusDevice busdev;
-    ReadWriteHandler conf_noswap_handler;
     ReadWriteHandler conf_handler;
-    ReadWriteHandler data_noswap_handler;
     ReadWriteHandler data_handler;
     uint32_t config_reg;
     PCIBus *bus;
@@ -45,8 +43,8 @@ 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);
 
 /* for mmio */
-int pci_host_conf_register_mmio(PCIHostState *s, int swap);
-int pci_host_data_register_mmio(PCIHostState *s, int swap);
+int pci_host_conf_register_mmio(PCIHostState *s, int endian);
+int pci_host_data_register_mmio(PCIHostState *s, int endian);
 
 /* for ioio */
 void pci_host_conf_register_ioport(pio_addr_t ioport, PCIHostState *s);
diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c
index 71302ba..11edd03 100644
--- a/hw/ppce500_pci.c
+++ b/hw/ppce500_pci.c
@@ -292,13 +292,15 @@ PCIBus *ppce500_pci_init(qemu_irq pci_irqs[4], target_phys_addr_t registers)
     controller->pci_dev = d;
 
     /* CFGADDR */
-    index = pci_host_conf_register_mmio(&controller->pci_state, 0);
+    index = pci_host_conf_register_mmio(&controller->pci_state,
+                                        DEVICE_BIG_ENDIAN);
     if (index < 0)
         goto free;
     cpu_register_physical_memory(registers + PCIE500_CFGADDR, 4, index);
 
     /* CFGDATA */
-    index = pci_host_data_register_mmio(&controller->pci_state, 0);
+    index = pci_host_data_register_mmio(&controller->pci_state,
+                                        DEVICE_BIG_ENDIAN);
     if (index < 0)
         goto free;
     cpu_register_physical_memory(registers + PCIE500_CFGDATA, 4, index);
diff --git a/hw/unin_pci.c b/hw/unin_pci.c
index 53791dd..f2e440e 100644
--- a/hw/unin_pci.c
+++ b/hw/unin_pci.c
@@ -151,7 +151,8 @@ static int pci_unin_main_init_device(SysBusDevice *dev)
     /* Uninorth main bus */
     s = FROM_SYSBUS(UNINState, dev);
 
-    pci_mem_config = pci_host_conf_register_mmio(&s->host_state, 1);
+    pci_mem_config = pci_host_conf_register_mmio(&s->host_state,
+                                                 DEVICE_LITTLE_ENDIAN);
     s->data_handler.read = unin_data_read;
     s->data_handler.write = unin_data_write;
     pci_mem_data = cpu_register_io_memory_simple(&s->data_handler,
@@ -173,7 +174,8 @@ static int pci_u3_agp_init_device(SysBusDevice *dev)
     /* Uninorth U3 AGP bus */
     s = FROM_SYSBUS(UNINState, dev);
 
-    pci_mem_config = pci_host_conf_register_mmio(&s->host_state, 1);
+    pci_mem_config = pci_host_conf_register_mmio(&s->host_state,
+                                                 DEVICE_LITTLE_ENDIAN);
     s->data_handler.read = unin_data_read;
     s->data_handler.write = unin_data_write;
     pci_mem_data = cpu_register_io_memory_simple(&s->data_handler,
@@ -196,8 +198,10 @@ static int pci_unin_agp_init_device(SysBusDevice *dev)
     /* Uninorth AGP bus */
     s = FROM_SYSBUS(UNINState, dev);
 
-    pci_mem_config = pci_host_conf_register_mmio(&s->host_state, 0);
-    pci_mem_data = pci_host_data_register_mmio(&s->host_state, 1);
+    pci_mem_config = pci_host_conf_register_mmio(&s->host_state,
+                                                 DEVICE_LITTLE_ENDIAN);
+    pci_mem_data = pci_host_data_register_mmio(&s->host_state,
+                                               DEVICE_LITTLE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, pci_mem_config);
     sysbus_init_mmio(dev, 0x1000, pci_mem_data);
     return 0;
@@ -211,8 +215,10 @@ static int pci_unin_internal_init_device(SysBusDevice *dev)
     /* Uninorth internal bus */
     s = FROM_SYSBUS(UNINState, dev);
 
-    pci_mem_config = pci_host_conf_register_mmio(&s->host_state, 0);
-    pci_mem_data = pci_host_data_register_mmio(&s->host_state, 1);
+    pci_mem_config = pci_host_conf_register_mmio(&s->host_state,
+                                                 DEVICE_LITTLE_ENDIAN);
+    pci_mem_data = pci_host_data_register_mmio(&s->host_state,
+                                               DEVICE_LITTLE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, pci_mem_config);
     sysbus_init_mmio(dev, 0x1000, pci_mem_data);
     return 0;
commit 0f4f039b9895e2e52d591a123017cb53fe636f9d
Author: Alexander Graf <agraf at suse.de>
Date:   Wed Dec 8 12:05:39 2010 +0100

    dbdma: Make little endian
    
    The device is only used on big endian systems, but always byte swaps. That's
    a very good indicator that it's actually a little endian device ;-).
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/mac_dbdma.c b/hw/mac_dbdma.c
index f449a59..5680fa9 100644
--- a/hw/mac_dbdma.c
+++ b/hw/mac_dbdma.c
@@ -707,8 +707,6 @@ static void dbdma_writel (void *opaque,
     DBDMA_DPRINTF("channel 0x%x reg 0x%x\n",
                   (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg);
 
-    value = bswap32(value);
-
     /* cmdptr cannot be modified if channel is RUN or ACTIVE */
 
     if (reg == DBDMA_CMDPTR_LO &&
@@ -788,7 +786,6 @@ static uint32_t dbdma_readl (void *opaque, target_phys_addr_t addr)
         break;
     }
 
-    value = bswap32(value);
     return value;
 }
 
@@ -845,7 +842,7 @@ void* DBDMA_init (int *dbdma_mem_index)
     s = qemu_mallocz(sizeof(DBDMA_channel) * DBDMA_CHANNELS);
 
     *dbdma_mem_index = cpu_register_io_memory(dbdma_read, dbdma_write, s,
-                                              DEVICE_NATIVE_ENDIAN);
+                                              DEVICE_LITTLE_ENDIAN);
     register_savevm(NULL, "dbdma", -1, 1, dbdma_save, dbdma_load, s);
     qemu_register_reset(dbdma_reset, s);
 
commit 6bef04365589b1b82be1a1c3aa223f4bddb3dabb
Author: Alexander Graf <agraf at suse.de>
Date:   Wed Dec 8 12:05:38 2010 +0100

    Make simple io mem handler endian aware
    
    As an alternative to the 3 individual handlers, there is also a simplified
    io mem hook function. To be consistent, let's add an endianness parameter
    there too.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/apb_pci.c b/hw/apb_pci.c
index bf00c71..84e9af7 100644
--- a/hw/apb_pci.c
+++ b/hw/apb_pci.c
@@ -418,7 +418,8 @@ static int pci_pbm_init_device(SysBusDevice *dev)
     /* PCI configuration space */
     s->pci_config_handler.read = apb_pci_config_read;
     s->pci_config_handler.write = apb_pci_config_write;
-    pci_config = cpu_register_io_memory_simple(&s->pci_config_handler);
+    pci_config = cpu_register_io_memory_simple(&s->pci_config_handler,
+                                               DEVICE_NATIVE_ENDIAN);
     assert(pci_config >= 0);
     /* at region 1 */
     sysbus_init_mmio(dev, 0x1000000ULL, pci_config);
diff --git a/hw/pci_host.c b/hw/pci_host.c
index bc5b771..a6e39c9 100644
--- a/hw/pci_host.c
+++ b/hw/pci_host.c
@@ -187,9 +187,11 @@ int pci_host_conf_register_mmio(PCIHostState *s, int swap)
 {
     pci_host_init(s);
     if (swap) {
-        return cpu_register_io_memory_simple(&s->conf_handler);
+        return cpu_register_io_memory_simple(&s->conf_handler,
+                                             DEVICE_NATIVE_ENDIAN);
     } else {
-        return cpu_register_io_memory_simple(&s->conf_noswap_handler);
+        return cpu_register_io_memory_simple(&s->conf_noswap_handler,
+                                             DEVICE_NATIVE_ENDIAN);
     }
 }
 
@@ -203,9 +205,11 @@ int pci_host_data_register_mmio(PCIHostState *s, int swap)
 {
     pci_host_init(s);
     if (swap) {
-        return cpu_register_io_memory_simple(&s->data_handler);
+        return cpu_register_io_memory_simple(&s->data_handler,
+                                             DEVICE_NATIVE_ENDIAN);
     } else {
-        return cpu_register_io_memory_simple(&s->data_noswap_handler);
+        return cpu_register_io_memory_simple(&s->data_noswap_handler,
+                                             DEVICE_NATIVE_ENDIAN);
     }
 }
 
diff --git a/hw/unin_pci.c b/hw/unin_pci.c
index 1310211..53791dd 100644
--- a/hw/unin_pci.c
+++ b/hw/unin_pci.c
@@ -154,7 +154,8 @@ static int pci_unin_main_init_device(SysBusDevice *dev)
     pci_mem_config = pci_host_conf_register_mmio(&s->host_state, 1);
     s->data_handler.read = unin_data_read;
     s->data_handler.write = unin_data_write;
-    pci_mem_data = cpu_register_io_memory_simple(&s->data_handler);
+    pci_mem_data = cpu_register_io_memory_simple(&s->data_handler,
+                                                 DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, pci_mem_config);
     sysbus_init_mmio(dev, 0x1000, pci_mem_data);
 
@@ -175,7 +176,8 @@ static int pci_u3_agp_init_device(SysBusDevice *dev)
     pci_mem_config = pci_host_conf_register_mmio(&s->host_state, 1);
     s->data_handler.read = unin_data_read;
     s->data_handler.write = unin_data_write;
-    pci_mem_data = cpu_register_io_memory_simple(&s->data_handler);
+    pci_mem_data = cpu_register_io_memory_simple(&s->data_handler,
+                                                 DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, pci_mem_config);
     sysbus_init_mmio(dev, 0x1000, pci_mem_data);
 
diff --git a/rwhandler.c b/rwhandler.c
index 88dfcc5..bb2238f 100644
--- a/rwhandler.c
+++ b/rwhandler.c
@@ -35,14 +35,14 @@ static CPUReadMemoryFunc * const cpu_io_memory_simple_read[] = {
     &cpu_io_memory_simple_readl,
 };
 
-int cpu_register_io_memory_simple(struct ReadWriteHandler *handler)
+int cpu_register_io_memory_simple(struct ReadWriteHandler *handler, int endian)
 {
     if (!handler->read || !handler->write) {
         return -1;
     }
     return cpu_register_io_memory(cpu_io_memory_simple_read,
                                   cpu_io_memory_simple_write,
-                                  handler, DEVICE_NATIVE_ENDIAN);
+                                  handler, endian);
 }
 
 RWHANDLER_WRITE(ioport_simple_writeb, 1, uint32_t);
diff --git a/rwhandler.h b/rwhandler.h
index bc11849..b2a5790 100644
--- a/rwhandler.h
+++ b/rwhandler.h
@@ -19,7 +19,7 @@ struct ReadWriteHandler {
 
 /* Helpers for when we want to use a single routine with length. */
 /* CPU memory handler: both read and write must be present. */
-int cpu_register_io_memory_simple(ReadWriteHandler *);
+int cpu_register_io_memory_simple(ReadWriteHandler *, int endian);
 /* io port handler: can supply only read or write handlers. */
 int register_ioport_simple(ReadWriteHandler *,
                            pio_addr_t start, int length, int size);
commit 2507c12ab026b2286b0a47035c629f3d568c96f4
Author: Alexander Graf <agraf at suse.de>
Date:   Wed Dec 8 12:05:37 2010 +0100

    Add endianness as io mem parameter
    
    As stated before, devices can be little, big or native endian. The
    target endianness is not of their concern, so we need to push things
    down a level.
    
    This patch adds a parameter to cpu_register_io_memory that allows a
    device to choose its endianness. For now, all devices simply choose
    native endian, because that's the same behavior as before.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/exec.c b/exec.c
index af1e89d..a338495 100644
--- a/exec.c
+++ b/exec.c
@@ -3331,7 +3331,8 @@ static subpage_t *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
     mmio = qemu_mallocz(sizeof(subpage_t));
 
     mmio->base = base;
-    subpage_memory = cpu_register_io_memory(subpage_read, subpage_write, mmio);
+    subpage_memory = cpu_register_io_memory(subpage_read, subpage_write, mmio,
+                                            DEVICE_NATIVE_ENDIAN);
 #if defined(DEBUG_SUBPAGE)
     printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
            mmio, base, TARGET_PAGE_SIZE, subpage_memory);
@@ -3468,7 +3469,6 @@ static int cpu_register_io_memory_fixed(int io_index,
                                         void *opaque, enum device_endian endian)
 {
     int i;
-    int endian = DEVICE_NATIVE_ENDIAN;
 
     if (io_index <= 0) {
         io_index = get_free_io_mem_idx();
@@ -3513,7 +3513,7 @@ int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read,
                            CPUWriteMemoryFunc * const *mem_write,
                            void *opaque, enum device_endian endian)
 {
-    return cpu_register_io_memory_fixed(0, mem_read, mem_write, opaque);
+    return cpu_register_io_memory_fixed(0, mem_read, mem_write, opaque, endian);
 }
 
 void cpu_unregister_io_memory(int io_table_address)
@@ -3535,14 +3535,21 @@ static void io_mem_init(void)
 {
     int i;
 
-    cpu_register_io_memory_fixed(IO_MEM_ROM, error_mem_read, unassigned_mem_write, NULL);
-    cpu_register_io_memory_fixed(IO_MEM_UNASSIGNED, unassigned_mem_read, unassigned_mem_write, NULL);
-    cpu_register_io_memory_fixed(IO_MEM_NOTDIRTY, error_mem_read, notdirty_mem_write, NULL);
+    cpu_register_io_memory_fixed(IO_MEM_ROM, error_mem_read,
+                                 unassigned_mem_write, NULL,
+                                 DEVICE_NATIVE_ENDIAN);
+    cpu_register_io_memory_fixed(IO_MEM_UNASSIGNED, unassigned_mem_read,
+                                 unassigned_mem_write, NULL,
+                                 DEVICE_NATIVE_ENDIAN);
+    cpu_register_io_memory_fixed(IO_MEM_NOTDIRTY, error_mem_read,
+                                 notdirty_mem_write, NULL,
+                                 DEVICE_NATIVE_ENDIAN);
     for (i=0; i<5; i++)
         io_mem_used[i] = 1;
 
     io_mem_watch = cpu_register_io_memory(watch_mem_read,
-                                          watch_mem_write, NULL);
+                                          watch_mem_write, NULL,
+                                          DEVICE_NATIVE_ENDIAN);
 }
 
 #endif /* !defined(CONFIG_USER_ONLY) */
diff --git a/hw/apb_pci.c b/hw/apb_pci.c
index c619112..bf00c71 100644
--- a/hw/apb_pci.c
+++ b/hw/apb_pci.c
@@ -410,7 +410,8 @@ static int pci_pbm_init_device(SysBusDevice *dev)
 
     /* apb_config */
     apb_config = cpu_register_io_memory(apb_config_read,
-                                        apb_config_write, s);
+                                        apb_config_write, s,
+                                        DEVICE_NATIVE_ENDIAN);
     /* at region 0 */
     sysbus_init_mmio(dev, 0x10000ULL, apb_config);
 
@@ -424,7 +425,8 @@ static int pci_pbm_init_device(SysBusDevice *dev)
 
     /* pci_ioport */
     pci_ioport = cpu_register_io_memory(pci_apb_ioread,
-                                        pci_apb_iowrite, s);
+                                        pci_apb_iowrite, s,
+                                        DEVICE_NATIVE_ENDIAN);
     /* at region 2 */
     sysbus_init_mmio(dev, 0x10000ULL, pci_ioport);
 
diff --git a/hw/apic.c b/hw/apic.c
index 5f4a87c..a5a53fb 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -980,7 +980,8 @@ static int apic_init1(SysBusDevice *dev)
         return -1;
     }
     apic_io_memory = cpu_register_io_memory(apic_mem_read,
-                                            apic_mem_write, NULL);
+                                            apic_mem_write, NULL,
+                                            DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, MSI_ADDR_SIZE, apic_io_memory);
 
     s->timer = qemu_new_timer(vm_clock, apic_timer, s);
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
index 8286a28..e6b1953 100644
--- a/hw/arm_gic.c
+++ b/hw/arm_gic.c
@@ -742,7 +742,8 @@ static void gic_init(gic_state *s)
         sysbus_init_irq(&s->busdev, &s->parent_irq[i]);
     }
     s->iomemtype = cpu_register_io_memory(gic_dist_readfn,
-                                          gic_dist_writefn, s);
+                                          gic_dist_writefn, s,
+                                          DEVICE_NATIVE_ENDIAN);
     gic_reset(s);
     register_savevm(NULL, "arm_gic", -1, 1, gic_save, gic_load, s);
 }
diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c
index 0cb2ffc..bd0664f 100644
--- a/hw/arm_sysctl.c
+++ b/hw/arm_sysctl.c
@@ -208,7 +208,8 @@ static int arm_sysctl_init1(SysBusDevice *dev)
     int iomemtype;
 
     iomemtype = cpu_register_io_memory(arm_sysctl_readfn,
-                                       arm_sysctl_writefn, s);
+                                       arm_sysctl_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, iomemtype);
     /* ??? Save/restore.  */
     return 0;
diff --git a/hw/arm_timer.c b/hw/arm_timer.c
index f009e9e..82f05de 100644
--- a/hw/arm_timer.c
+++ b/hw/arm_timer.c
@@ -269,7 +269,7 @@ static int sp804_init(SysBusDevice *dev)
     s->timer[0]->irq = qi[0];
     s->timer[1]->irq = qi[1];
     iomemtype = cpu_register_io_memory(sp804_readfn,
-                                       sp804_writefn, s);
+                                       sp804_writefn, s, DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, iomemtype);
     register_savevm(&dev->qdev, "sp804", -1, 1, sp804_save, sp804_load, s);
     return 0;
@@ -340,7 +340,8 @@ static int icp_pit_init(SysBusDevice *dev)
     sysbus_init_irq(dev, &s->timer[2]->irq);
 
     iomemtype = cpu_register_io_memory(icp_pit_readfn,
-                                       icp_pit_writefn, s);
+                                       icp_pit_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, iomemtype);
     /* This device has no state to save/restore.  The component timers will
        save themselves.  */
diff --git a/hw/armv7m.c b/hw/armv7m.c
index 588ec98..304cd34 100644
--- a/hw/armv7m.c
+++ b/hw/armv7m.c
@@ -130,7 +130,7 @@ static int bitband_init(SysBusDevice *dev)
     int iomemtype;
 
     iomemtype = cpu_register_io_memory(bitband_readfn, bitband_writefn,
-                                       &s->base);
+                                       &s->base, DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x02000000, iomemtype);
     return 0;
 }
diff --git a/hw/axis_dev88.c b/hw/axis_dev88.c
index f16c76a..57b5e2f 100644
--- a/hw/axis_dev88.c
+++ b/hw/axis_dev88.c
@@ -280,11 +280,13 @@ void axisdev88_init (ram_addr_t ram_size,
 
       /* Attach a NAND flash to CS1.  */
     nand_state.nand = nand_init(NAND_MFR_STMICRO, 0x39);
-    nand_regs = cpu_register_io_memory(nand_read, nand_write, &nand_state);
+    nand_regs = cpu_register_io_memory(nand_read, nand_write, &nand_state,
+                                       DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(0x10000000, 0x05000000, nand_regs);
 
     gpio_state.nand = &nand_state;
-    gpio_regs = cpu_register_io_memory(gpio_read, gpio_write, &gpio_state);
+    gpio_regs = cpu_register_io_memory(gpio_read, gpio_write, &gpio_state,
+                                       DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(0x3001a000, 0x5c, gpio_regs);
 
 
diff --git a/hw/bonito.c b/hw/bonito.c
index dcf0311..fd90527 100644
--- a/hw/bonito.c
+++ b/hw/bonito.c
@@ -698,7 +698,8 @@ static int bonito_initfn(PCIDevice *dev)
     pci_config_set_revision(dev->config, 0x01);
 
     /* set the north bridge register mapping */
-    s->bonito_reg_handle = cpu_register_io_memory(bonito_read, bonito_write, s);
+    s->bonito_reg_handle = cpu_register_io_memory(bonito_read, bonito_write, s,
+                                                  DEVICE_NATIVE_ENDIAN);
     s->bonito_reg_start = BONITO_INTERNAL_REG_BASE;
     s->bonito_reg_length = BONITO_INTERNAL_REG_SIZE;
     cpu_register_physical_memory(s->bonito_reg_start, s->bonito_reg_length,
@@ -706,7 +707,8 @@ static int bonito_initfn(PCIDevice *dev)
 
     /* set the north bridge pci configure  mapping */
     s->bonito_pciconf_handle = cpu_register_io_memory(bonito_pciconf_read,
-                                                      bonito_pciconf_write, s);
+                                                      bonito_pciconf_write, s,
+                                                      DEVICE_NATIVE_ENDIAN);
     s->bonito_pciconf_start = BONITO_PCICONFIG_BASE;
     s->bonito_pciconf_length = BONITO_PCICONFIG_SIZE;
     cpu_register_physical_memory(s->bonito_pciconf_start, s->bonito_pciconf_length,
@@ -714,21 +716,24 @@ static int bonito_initfn(PCIDevice *dev)
 
     /* set the south bridge pci configure  mapping */
     s->bonito_spciconf_handle = cpu_register_io_memory(bonito_spciconf_read,
-                                                       bonito_spciconf_write, s);
+                                                       bonito_spciconf_write, s,
+                                                       DEVICE_NATIVE_ENDIAN);
     s->bonito_spciconf_start = BONITO_SPCICONFIG_BASE;
     s->bonito_spciconf_length = BONITO_SPCICONFIG_SIZE;
     cpu_register_physical_memory(s->bonito_spciconf_start, s->bonito_spciconf_length,
                                  s->bonito_spciconf_handle);
 
     s->bonito_ldma_handle = cpu_register_io_memory(bonito_ldma_read,
-                                                   bonito_ldma_write, s);
+                                                   bonito_ldma_write, s,
+                                                   DEVICE_NATIVE_ENDIAN);
     s->bonito_ldma_start = 0xbfe00200;
     s->bonito_ldma_length = 0x100;
     cpu_register_physical_memory(s->bonito_ldma_start, s->bonito_ldma_length,
                                  s->bonito_ldma_handle);
 
     s->bonito_cop_handle = cpu_register_io_memory(bonito_cop_read,
-                                                  bonito_cop_write, s);
+                                                  bonito_cop_write, s,
+                                                  DEVICE_NATIVE_ENDIAN);
     s->bonito_cop_start = 0xbfe00300;
     s->bonito_cop_length = 0x100;
     cpu_register_physical_memory(s->bonito_cop_start, s->bonito_cop_length,
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index 40be55d..4f5040c 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -3076,23 +3076,27 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci)
     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);
+                                                  cirrus_vga_mem_write, s,
+                                                  DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
                                  s->vga.vga_io_memory);
     qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000);
 
     /* I/O handler for LFB */
     s->cirrus_linear_io_addr =
-        cpu_register_io_memory(cirrus_linear_read, cirrus_linear_write, s);
+        cpu_register_io_memory(cirrus_linear_read, cirrus_linear_write, s,
+                               DEVICE_NATIVE_ENDIAN);
 
     /* I/O handler for LFB */
     s->cirrus_linear_bitblt_io_addr =
         cpu_register_io_memory(cirrus_linear_bitblt_read,
-                               cirrus_linear_bitblt_write, s);
+                               cirrus_linear_bitblt_write, s,
+                               DEVICE_NATIVE_ENDIAN);
 
     /* I/O handler for memory-mapped I/O */
     s->cirrus_mmio_io_addr =
-        cpu_register_io_memory(cirrus_mmio_read, cirrus_mmio_write, s);
+        cpu_register_io_memory(cirrus_mmio_read, cirrus_mmio_write, s,
+                               DEVICE_NATIVE_ENDIAN);
 
     s->real_vram_size =
         (s->device_id == CIRRUS_ID_CLGD5446) ? 4096 * 1024 : 2048 * 1024;
diff --git a/hw/cs4231.c b/hw/cs4231.c
index 2977101..a65b697 100644
--- a/hw/cs4231.c
+++ b/hw/cs4231.c
@@ -148,7 +148,8 @@ static int cs4231_init1(SysBusDevice *dev)
     int io;
     CSState *s = FROM_SYSBUS(CSState, dev);
 
-    io = cpu_register_io_memory(cs_mem_read, cs_mem_write, s);
+    io = cpu_register_io_memory(cs_mem_read, cs_mem_write, s,
+                                DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, CS_SIZE, io);
     sysbus_init_irq(dev, &s->irq);
 
diff --git a/hw/cuda.c b/hw/cuda.c
index 3f238b6..e4c178d 100644
--- a/hw/cuda.c
+++ b/hw/cuda.c
@@ -762,7 +762,8 @@ 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(vm_clock, cuda_adb_poll, s);
-    *cuda_mem_index = cpu_register_io_memory(cuda_read, cuda_write, s);
+    *cuda_mem_index = cpu_register_io_memory(cuda_read, cuda_write, s,
+                                             DEVICE_NATIVE_ENDIAN);
     register_savevm(NULL, "cuda", -1, 1, cuda_save, cuda_load, s);
     qemu_register_reset(cuda_reset, s);
 }
diff --git a/hw/dp8393x.c b/hw/dp8393x.c
index e65e4d1..0ef8abe 100644
--- a/hw/dp8393x.c
+++ b/hw/dp8393x.c
@@ -908,6 +908,7 @@ void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift,
     qemu_register_reset(nic_reset, s);
     nic_reset(s);
 
-    s->mmio_index = cpu_register_io_memory(dp8393x_read, dp8393x_write, s);
+    s->mmio_index = cpu_register_io_memory(dp8393x_read, dp8393x_write, s,
+                                           DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x40 << it_shift, s->mmio_index);
 }
diff --git a/hw/ds1225y.c b/hw/ds1225y.c
index 009d127..b1c5232 100644
--- a/hw/ds1225y.c
+++ b/hw/ds1225y.c
@@ -171,10 +171,12 @@ void *ds1225y_init(target_phys_addr_t mem_base, const char *filename)
     }
 
     /* Read/write memory */
-    mem_indexRW = cpu_register_io_memory(nvram_read, nvram_write, s);
+    mem_indexRW = cpu_register_io_memory(nvram_read, nvram_write, s,
+                                         DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(mem_base, s->chip_size, mem_indexRW);
     /* Read/write protected memory */
-    mem_indexRP = cpu_register_io_memory(nvram_read, nvram_write_protected, s);
+    mem_indexRP = cpu_register_io_memory(nvram_read, nvram_write_protected, s,
+                                         DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(mem_base + s->chip_size, s->chip_size, mem_indexRP);
     return s;
 }
diff --git a/hw/e1000.c b/hw/e1000.c
index 57d08cf..bf3f2d3 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -1131,7 +1131,7 @@ static int pci_e1000_init(PCIDevice *pci_dev)
     pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0
 
     d->mmio_index = cpu_register_io_memory(e1000_mmio_read,
-            e1000_mmio_write, d);
+            e1000_mmio_write, d, DEVICE_NATIVE_ENDIAN);
 
     pci_register_bar(&d->dev, 0, PNPMMIO_SIZE,
                            PCI_BASE_ADDRESS_SPACE_MEMORY, e1000_mmio_map);
diff --git a/hw/eccmemctl.c b/hw/eccmemctl.c
index a8042e9..2bda87b 100644
--- a/hw/eccmemctl.c
+++ b/hw/eccmemctl.c
@@ -297,12 +297,14 @@ static int ecc_init1(SysBusDevice *dev)
 
     sysbus_init_irq(dev, &s->irq);
     s->regs[0] = s->version;
-    ecc_io_memory = cpu_register_io_memory(ecc_mem_read, ecc_mem_write, s);
+    ecc_io_memory = cpu_register_io_memory(ecc_mem_read, ecc_mem_write, s,
+                                           DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, ECC_SIZE, ecc_io_memory);
 
     if (s->version == ECC_MCC) { // SS-600MP only
         ecc_io_memory = cpu_register_io_memory(ecc_diag_mem_read,
-                                               ecc_diag_mem_write, s);
+                                               ecc_diag_mem_write, s,
+                                               DEVICE_NATIVE_ENDIAN);
         sysbus_init_mmio(dev, ECC_DIAG_SIZE, ecc_io_memory);
     }
 
diff --git a/hw/eepro100.c b/hw/eepro100.c
index f8a700a..b31ad3e 100644
--- a/hw/eepro100.c
+++ b/hw/eepro100.c
@@ -1878,7 +1878,8 @@ static int e100_nic_init(PCIDevice *pci_dev)
 
     /* Handler for memory-mapped I/O */
     s->mmio_index =
-        cpu_register_io_memory(pci_mmio_read, pci_mmio_write, s);
+        cpu_register_io_memory(pci_mmio_read, pci_mmio_write, s,
+                               DEVICE_NATIVE_ENDIAN);
 
     pci_register_bar(&s->dev, 0, PCI_MEM_SIZE,
                            PCI_BASE_ADDRESS_SPACE_MEMORY |
diff --git a/hw/empty_slot.c b/hw/empty_slot.c
index ac1f6eb..664b8d9 100644
--- a/hw/empty_slot.c
+++ b/hw/empty_slot.c
@@ -73,7 +73,8 @@ static int empty_slot_init1(SysBusDevice *dev)
     ram_addr_t empty_slot_offset;
 
     empty_slot_offset = cpu_register_io_memory(empty_slot_read,
-                                               empty_slot_write, s);
+                                               empty_slot_write, s,
+                                               DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, s->size, empty_slot_offset | IO_MEM_RAM);
     return 0;
 }
diff --git a/hw/escc.c b/hw/escc.c
index 8714239..ba60636 100644
--- a/hw/escc.c
+++ b/hw/escc.c
@@ -914,7 +914,8 @@ 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);
+    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;
 
diff --git a/hw/esp.c b/hw/esp.c
index 910fd31..fa9d2a2 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -722,7 +722,8 @@ static int esp_init1(SysBusDevice *dev)
     sysbus_init_irq(dev, &s->irq);
     assert(s->it_shift != -1);
 
-    esp_io_memory = cpu_register_io_memory(esp_mem_read, esp_mem_write, s);
+    esp_io_memory = cpu_register_io_memory(esp_mem_read, esp_mem_write, s,
+                                           DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, ESP_REGS << s->it_shift, esp_io_memory);
 
     qdev_init_gpio_in(&dev->qdev, esp_gpio_demux, 2);
diff --git a/hw/etraxfs_dma.c b/hw/etraxfs_dma.c
index 15c8ad3..c205ec1 100644
--- a/hw/etraxfs_dma.c
+++ b/hw/etraxfs_dma.c
@@ -750,7 +750,7 @@ void *etraxfs_dmac_init(target_phys_addr_t base, int nr_channels)
 	ctrl->nr_channels = nr_channels;
 	ctrl->channels = qemu_mallocz(sizeof ctrl->channels[0] * nr_channels);
 
-	ctrl->map = cpu_register_io_memory(dma_read, dma_write, ctrl);
+	ctrl->map = cpu_register_io_memory(dma_read, dma_write, ctrl, DEVICE_NATIVE_ENDIAN);
 	cpu_register_physical_memory(base, nr_channels * 0x2000, ctrl->map);
 	return ctrl;
 }
diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c
index ade96f1..6aa4007 100644
--- a/hw/etraxfs_eth.c
+++ b/hw/etraxfs_eth.c
@@ -598,7 +598,8 @@ void *etraxfs_eth_init(NICInfo *nd, target_phys_addr_t base, int phyaddr)
 	tdk_init(&eth->phy);
 	mdio_attach(&eth->mdio_bus, &eth->phy, eth->phyaddr);
 
-	eth->ethregs = cpu_register_io_memory(eth_read, eth_write, eth);
+	eth->ethregs = cpu_register_io_memory(eth_read, eth_write, eth,
+                                              DEVICE_NATIVE_ENDIAN);
 	cpu_register_physical_memory (base, 0x5c, eth->ethregs);
 
 	memcpy(eth->conf.macaddr.a, nd->macaddr, sizeof(nd->macaddr));
diff --git a/hw/etraxfs_pic.c b/hw/etraxfs_pic.c
index b2c4859..4feffda 100644
--- a/hw/etraxfs_pic.c
+++ b/hw/etraxfs_pic.c
@@ -145,7 +145,8 @@ static int etraxfs_pic_init(SysBusDevice *dev)
     sysbus_init_irq(dev, &s->parent_irq);
     sysbus_init_irq(dev, &s->parent_nmi);
 
-    intr_vect_regs = cpu_register_io_memory(pic_read, pic_write, s);
+    intr_vect_regs = cpu_register_io_memory(pic_read, pic_write, s,
+                                            DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, R_MAX * 4, intr_vect_regs);
     return 0;
 }
diff --git a/hw/etraxfs_ser.c b/hw/etraxfs_ser.c
index 336cc54..2787ebd 100644
--- a/hw/etraxfs_ser.c
+++ b/hw/etraxfs_ser.c
@@ -200,7 +200,8 @@ static int etraxfs_ser_init(SysBusDevice *dev)
     s->regs[RS_STAT_DIN] |= (1 << STAT_TR_IDLE);
 
     sysbus_init_irq(dev, &s->irq);
-    ser_regs = cpu_register_io_memory(ser_read, ser_write, s);
+    ser_regs = cpu_register_io_memory(ser_read, ser_write, s,
+                                      DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, R_MAX * 4, ser_regs);
     s->chr = qdev_init_chardev(&dev->qdev);
     if (s->chr)
diff --git a/hw/etraxfs_timer.c b/hw/etraxfs_timer.c
index 87700d4..ba1adbe 100644
--- a/hw/etraxfs_timer.c
+++ b/hw/etraxfs_timer.c
@@ -323,7 +323,8 @@ static int etraxfs_timer_init(SysBusDevice *dev)
     sysbus_init_irq(dev, &t->irq);
     sysbus_init_irq(dev, &t->nmi);
 
-    timer_regs = cpu_register_io_memory(timer_read, timer_write, t);
+    timer_regs = cpu_register_io_memory(timer_read, timer_write, t,
+                                        DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x5c, timer_regs);
 
     qemu_register_reset(etraxfs_timer_reset, t);
diff --git a/hw/fdc.c b/hw/fdc.c
index c159dcb..bea5af2 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -1999,7 +1999,8 @@ static int sysbus_fdc_init1(SysBusDevice *dev)
     int io;
     int ret;
 
-    io = cpu_register_io_memory(fdctrl_mem_read, fdctrl_mem_write, fdctrl);
+    io = cpu_register_io_memory(fdctrl_mem_read, fdctrl_mem_write, fdctrl,
+                                DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x08, io);
     sysbus_init_irq(dev, &fdctrl->irq);
     qdev_init_gpio_in(&dev->qdev, fdctrl_handle_tc, 1);
@@ -2017,7 +2018,8 @@ static int sun4m_fdc_init1(SysBusDevice *dev)
     int io;
 
     io = cpu_register_io_memory(fdctrl_mem_read_strict,
-                                fdctrl_mem_write_strict, fdctrl);
+                                fdctrl_mem_write_strict, fdctrl,
+                                DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x08, io);
     sysbus_init_irq(dev, &fdctrl->irq);
     qdev_init_gpio_in(&dev->qdev, fdctrl_handle_tc, 1);
diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c
index 72866ae..48b92d6 100644
--- a/hw/fw_cfg.c
+++ b/hw/fw_cfg.c
@@ -360,11 +360,13 @@ static int fw_cfg_init1(SysBusDevice *dev)
     int io_ctl_memory, io_data_memory;
 
     io_ctl_memory = cpu_register_io_memory(fw_cfg_ctl_mem_read,
-                                           fw_cfg_ctl_mem_write, s);
+                                           fw_cfg_ctl_mem_write, s,
+                                           DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, FW_CFG_SIZE, io_ctl_memory);
 
     io_data_memory = cpu_register_io_memory(fw_cfg_data_mem_read,
-                                            fw_cfg_data_mem_write, s);
+                                            fw_cfg_data_mem_write, s,
+                                            DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, FW_CFG_SIZE, io_data_memory);
 
     if (s->ctl_iobase) {
diff --git a/hw/g364fb.c b/hw/g364fb.c
index 3c8fb98..a41e988 100644
--- a/hw/g364fb.c
+++ b/hw/g364fb.c
@@ -607,7 +607,8 @@ int g364fb_mm_init(target_phys_addr_t vram_base,
 
     cpu_register_physical_memory(vram_base, s->vram_size, s->vram_offset);
 
-    io_ctrl = cpu_register_io_memory(g364fb_ctrl_read, g364fb_ctrl_write, s);
+    io_ctrl = cpu_register_io_memory(g364fb_ctrl_read, g364fb_ctrl_write, s,
+                                     DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(ctrl_base, 0x200000, io_ctrl);
 
     return 0;
diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c
index cabf7ea..51e4db0 100644
--- a/hw/gt64xxx.c
+++ b/hw/gt64xxx.c
@@ -1116,7 +1116,8 @@ PCIBus *pci_gt64120_init(qemu_irq *pic)
     s->pci->bus = pci_register_bus(NULL, "pci",
                                    pci_gt64120_set_irq, pci_gt64120_map_irq,
                                    pic, PCI_DEVFN(18, 0), 4);
-    s->ISD_handle = cpu_register_io_memory(gt64120_read, gt64120_write, s);
+    s->ISD_handle = cpu_register_io_memory(gt64120_read, gt64120_write, s,
+                                           DEVICE_NATIVE_ENDIAN);
     d = pci_register_device(s->pci->bus, "GT64120 PCI Bus", sizeof(PCIDevice),
                             0, NULL, NULL);
 
diff --git a/hw/heathrow_pic.c b/hw/heathrow_pic.c
index cd86121..390b63c 100644
--- a/hw/heathrow_pic.c
+++ b/hw/heathrow_pic.c
@@ -222,7 +222,8 @@ 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);
+    *pmem_index = cpu_register_io_memory(pic_read, pic_write, s,
+                                         DEVICE_NATIVE_ENDIAN);
 
     register_savevm(NULL, "heathrow_pic", -1, 1, heathrow_pic_save,
                     heathrow_pic_load, s);
diff --git a/hw/hpet.c b/hw/hpet.c
index d5c406c..8fb6811 100644
--- a/hw/hpet.c
+++ b/hw/hpet.c
@@ -720,7 +720,8 @@ static int hpet_init(SysBusDevice *dev)
 
     /* HPET Area */
     iomemtype = cpu_register_io_memory(hpet_ram_read,
-                                       hpet_ram_write, s);
+                                       hpet_ram_write, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x400, iomemtype);
     return 0;
 }
diff --git a/hw/ide/macio.c b/hw/ide/macio.c
index bd1c73e..c1b4caa 100644
--- a/hw/ide/macio.c
+++ b/hw/ide/macio.c
@@ -320,7 +320,8 @@ int pmac_ide_init (DriveInfo **hd_table, qemu_irq irq,
         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);
+                                             pmac_ide_write, d,
+                                             DEVICE_NATIVE_ENDIAN);
     vmstate_register(NULL, 0, &vmstate_pmac, d);
     qemu_register_reset(pmac_ide_reset, d);
 
diff --git a/hw/ide/mmio.c b/hw/ide/mmio.c
index 9f20e8b..82b24b6 100644
--- a/hw/ide/mmio.c
+++ b/hw/ide/mmio.c
@@ -129,8 +129,10 @@ void mmio_ide_init (target_phys_addr_t membase, target_phys_addr_t membase2,
 
     s->shift = shift;
 
-    mem1 = cpu_register_io_memory(mmio_ide_reads, mmio_ide_writes, s);
-    mem2 = cpu_register_io_memory(mmio_ide_status, mmio_ide_cmd, s);
+    mem1 = cpu_register_io_memory(mmio_ide_reads, mmio_ide_writes, s,
+                                  DEVICE_NATIVE_ENDIAN);
+    mem2 = cpu_register_io_memory(mmio_ide_status, mmio_ide_cmd, s,
+                                  DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(membase, 16 << shift, mem1);
     cpu_register_physical_memory(membase2, 2 << shift, mem2);
     vmstate_register(NULL, 0, &vmstate_ide_mmio, s);
diff --git a/hw/integratorcp.c b/hw/integratorcp.c
index 3bf216b..b049940 100644
--- a/hw/integratorcp.c
+++ b/hw/integratorcp.c
@@ -256,7 +256,8 @@ static int integratorcm_init(SysBusDevice *dev)
     s->flash_offset = qemu_ram_alloc(NULL, "integrator.flash", 0x100000);
 
     iomemtype = cpu_register_io_memory(integratorcm_readfn,
-                                       integratorcm_writefn, s);
+                                       integratorcm_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x00800000, iomemtype);
     integratorcm_do_remap(s, 1);
     /* ??? Save/restore.  */
@@ -382,7 +383,8 @@ static int icp_pic_init(SysBusDevice *dev)
     sysbus_init_irq(dev, &s->parent_irq);
     sysbus_init_irq(dev, &s->parent_fiq);
     iomemtype = cpu_register_io_memory(icp_pic_readfn,
-                                       icp_pic_writefn, s);
+                                       icp_pic_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x00800000, iomemtype);
     return 0;
 }
@@ -435,7 +437,8 @@ static void icp_control_init(uint32_t base)
     int iomemtype;
 
     iomemtype = cpu_register_io_memory(icp_control_readfn,
-                                       icp_control_writefn, NULL);
+                                       icp_control_writefn, NULL,
+                                       DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x00800000, iomemtype);
     /* ??? Save/restore.  */
 }
diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index fe31624..b2b6708 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -1156,7 +1156,8 @@ static int intel_hda_init(PCIDevice *pci)
     conf[0x40] = 0x01;
 
     d->mmio_addr = cpu_register_io_memory(intel_hda_mmio_read,
-                                          intel_hda_mmio_write, d);
+                                          intel_hda_mmio_write, d,
+                                          DEVICE_NATIVE_ENDIAN);
     pci_register_bar(&d->pci, 0, 0x4000, PCI_BASE_ADDRESS_SPACE_MEMORY,
                      intel_hda_map);
     if (d->msi) {
diff --git a/hw/ioapic.c b/hw/ioapic.c
index 5ae21e9..2109568 100644
--- a/hw/ioapic.c
+++ b/hw/ioapic.c
@@ -242,7 +242,8 @@ static int ioapic_init1(SysBusDevice *dev)
     int io_memory;
 
     io_memory = cpu_register_io_memory(ioapic_mem_read,
-                                       ioapic_mem_write, s);
+                                       ioapic_mem_write, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, io_memory);
 
     qdev_init_gpio_in(&dev->qdev, ioapic_set_irq, IOAPIC_NUM_PINS);
diff --git a/hw/isa_mmio.c b/hw/isa_mmio.c
index 66bdd2c..46458f4 100644
--- a/hw/isa_mmio.c
+++ b/hw/isa_mmio.c
@@ -131,11 +131,13 @@ void isa_mmio_init(target_phys_addr_t base, target_phys_addr_t size, int be)
         if (be) {
             isa_mmio_iomemtype = cpu_register_io_memory(isa_mmio_read_be,
                                                         isa_mmio_write_be,
-                                                        NULL);
+                                                        NULL,
+                                                        DEVICE_NATIVE_ENDIAN);
         } else {
             isa_mmio_iomemtype = cpu_register_io_memory(isa_mmio_read_le,
                                                         isa_mmio_write_le,
-                                                        NULL);
+                                                        NULL,
+                                                        DEVICE_NATIVE_ENDIAN);
         }
     }
     cpu_register_physical_memory(base, size, isa_mmio_iomemtype);
diff --git a/hw/ivshmem.c b/hw/ivshmem.c
index 06dce70..7b19a81 100644
--- a/hw/ivshmem.c
+++ b/hw/ivshmem.c
@@ -720,7 +720,7 @@ static int pci_ivshmem_init(PCIDevice *dev)
     s->shm_fd = 0;
 
     s->ivshmem_mmio_io_addr = cpu_register_io_memory(ivshmem_mmio_read,
-                                    ivshmem_mmio_write, s);
+                                    ivshmem_mmio_write, s, DEVICE_NATIVE_ENDIAN);
     /* region for registers*/
     pci_register_bar(&s->dev, 0, IVSHMEM_REG_BAR_SIZE,
                            PCI_BASE_ADDRESS_SPACE_MEMORY, ivshmem_mmio_map);
diff --git a/hw/jazz_led.c b/hw/jazz_led.c
index 4cb680c..1dc22cf 100644
--- a/hw/jazz_led.c
+++ b/hw/jazz_led.c
@@ -316,7 +316,8 @@ void jazz_led_init(target_phys_addr_t base)
 
     s->state = REDRAW_SEGMENTS | REDRAW_BACKGROUND;
 
-    io = cpu_register_io_memory(led_read, led_write, s);
+    io = cpu_register_io_memory(led_read, led_write, s,
+                                DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 1, io);
 
     s->ds = graphic_console_init(jazz_led_update_display,
diff --git a/hw/lan9118.c b/hw/lan9118.c
index b996dc4..a988664 100644
--- a/hw/lan9118.c
+++ b/hw/lan9118.c
@@ -1124,7 +1124,8 @@ static int lan9118_init1(SysBusDevice *dev)
     int i;
 
     s->mmio_index = cpu_register_io_memory(lan9118_readfn,
-                                           lan9118_writefn, s);
+                                           lan9118_writefn, s,
+                                           DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x100, s->mmio_index);
     sysbus_init_irq(dev, &s->irq);
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
diff --git a/hw/lance.c b/hw/lance.c
index dc12144..8c51858 100644
--- a/hw/lance.c
+++ b/hw/lance.c
@@ -118,7 +118,8 @@ static int lance_init(SysBusDevice *dev)
     PCNetState *s = &d->state;
 
     s->mmio_index =
-        cpu_register_io_memory(lance_mem_read, lance_mem_write, d);
+        cpu_register_io_memory(lance_mem_read, lance_mem_write, d,
+                               DEVICE_NATIVE_ENDIAN);
 
     qdev_init_gpio_in(&dev->qdev, parent_lance_reset, 1);
 
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index 1aef62f..0129ae3 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -2173,9 +2173,11 @@ static int lsi_scsi_init(PCIDevice *dev)
     pci_conf[PCI_INTERRUPT_PIN] = 0x01;
 
     s->mmio_io_addr = cpu_register_io_memory(lsi_mmio_readfn,
-                                             lsi_mmio_writefn, s);
+                                             lsi_mmio_writefn, s,
+                                             DEVICE_NATIVE_ENDIAN);
     s->ram_io_addr = cpu_register_io_memory(lsi_ram_readfn,
-                                            lsi_ram_writefn, s);
+                                            lsi_ram_writefn, s,
+                                            DEVICE_NATIVE_ENDIAN);
 
     pci_register_bar(&s->dev, 0, 256,
                            PCI_BASE_ADDRESS_SPACE_IO, lsi_io_mapfunc);
diff --git a/hw/m48t59.c b/hw/m48t59.c
index c7492a6..3c26b54 100644
--- a/hw/m48t59.c
+++ b/hw/m48t59.c
@@ -716,7 +716,8 @@ static int m48t59_init1(SysBusDevice *dev)
 
     sysbus_init_irq(dev, &s->IRQ);
 
-    mem_index = cpu_register_io_memory(nvram_read, nvram_write, s);
+    mem_index = cpu_register_io_memory(nvram_read, nvram_write, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, s->size, mem_index);
     m48t59_init_common(s);
 
diff --git a/hw/mac_dbdma.c b/hw/mac_dbdma.c
index 03d2d16..f449a59 100644
--- a/hw/mac_dbdma.c
+++ b/hw/mac_dbdma.c
@@ -844,7 +844,8 @@ void* DBDMA_init (int *dbdma_mem_index)
 
     s = qemu_mallocz(sizeof(DBDMA_channel) * DBDMA_CHANNELS);
 
-    *dbdma_mem_index = cpu_register_io_memory(dbdma_read, dbdma_write, s);
+    *dbdma_mem_index = cpu_register_io_memory(dbdma_read, dbdma_write, s,
+                                              DEVICE_NATIVE_ENDIAN);
     register_savevm(NULL, "dbdma", -1, 1, dbdma_save, dbdma_load, s);
     qemu_register_reset(dbdma_reset, s);
 
diff --git a/hw/mac_nvram.c b/hw/mac_nvram.c
index ce287c3..c2a2fc2 100644
--- a/hw/mac_nvram.c
+++ b/hw/mac_nvram.c
@@ -138,7 +138,8 @@ 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);
+    s->mem_index = cpu_register_io_memory(nvram_read, nvram_write, s,
+                                          DEVICE_NATIVE_ENDIAN);
     *mem_index = s->mem_index;
     register_savevm(NULL, "macio_nvram", -1, 1, macio_nvram_save,
                     macio_nvram_load, s);
diff --git a/hw/marvell_88w8618_audio.c b/hw/marvell_88w8618_audio.c
index 307b584..3eff925 100644
--- a/hw/marvell_88w8618_audio.c
+++ b/hw/marvell_88w8618_audio.c
@@ -249,7 +249,8 @@ static int mv88w8618_audio_init(SysBusDevice *dev)
     wm8750_data_req_set(s->wm, mv88w8618_audio_callback, s);
 
     iomemtype = cpu_register_io_memory(mv88w8618_audio_readfn,
-                                       mv88w8618_audio_writefn, s);
+                                       mv88w8618_audio_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, MP_AUDIO_SIZE, iomemtype);
 
     return 0;
diff --git a/hw/mcf5206.c b/hw/mcf5206.c
index c107de8..2a618d4 100644
--- a/hw/mcf5206.c
+++ b/hw/mcf5206.c
@@ -525,7 +525,8 @@ qemu_irq *mcf5206_init(uint32_t base, CPUState *env)
 
     s = (m5206_mbar_state *)qemu_mallocz(sizeof(m5206_mbar_state));
     iomemtype = cpu_register_io_memory(m5206_mbar_readfn,
-                                       m5206_mbar_writefn, s);
+                                       m5206_mbar_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x00001000, iomemtype);
 
     pic = qemu_allocate_irqs(m5206_mbar_set_irq, s, 14);
diff --git a/hw/mcf5208.c b/hw/mcf5208.c
index 38645f7..17a692d 100644
--- a/hw/mcf5208.c
+++ b/hw/mcf5208.c
@@ -179,7 +179,8 @@ static void mcf5208_sys_init(qemu_irq *pic)
     int i;
 
     iomemtype = cpu_register_io_memory(m5208_sys_readfn,
-                                       m5208_sys_writefn, NULL);
+                                       m5208_sys_writefn, NULL,
+                                       DEVICE_NATIVE_ENDIAN);
     /* SDRAMC.  */
     cpu_register_physical_memory(0xfc0a8000, 0x00004000, iomemtype);
     /* Timers.  */
@@ -188,7 +189,8 @@ static void mcf5208_sys_init(qemu_irq *pic)
         bh = qemu_bh_new(m5208_timer_trigger, s);
         s->timer = ptimer_init(bh);
         iomemtype = cpu_register_io_memory(m5208_timer_readfn,
-                                           m5208_timer_writefn, s);
+                                           m5208_timer_writefn, s,
+                                           DEVICE_NATIVE_ENDIAN);
         cpu_register_physical_memory(0xfc080000 + 0x4000 * i, 0x00004000,
                                      iomemtype);
         s->irq = pic[4 + i];
diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c
index 4e7fbed..21035da 100644
--- a/hw/mcf_fec.c
+++ b/hw/mcf_fec.c
@@ -467,7 +467,8 @@ void mcf_fec_init(NICInfo *nd, target_phys_addr_t base, qemu_irq *irq)
     s = (mcf_fec_state *)qemu_mallocz(sizeof(mcf_fec_state));
     s->irq = irq;
     s->mmio_index = cpu_register_io_memory(mcf_fec_readfn,
-                                           mcf_fec_writefn, s);
+                                           mcf_fec_writefn, s,
+                                           DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x400, s->mmio_index);
 
     memcpy(s->conf.macaddr.a, nd->macaddr, sizeof(nd->macaddr));
diff --git a/hw/mcf_intc.c b/hw/mcf_intc.c
index f01bd32..ac04295 100644
--- a/hw/mcf_intc.c
+++ b/hw/mcf_intc.c
@@ -149,7 +149,8 @@ qemu_irq *mcf_intc_init(target_phys_addr_t base, CPUState *env)
     mcf_intc_reset(s);
 
     iomemtype = cpu_register_io_memory(mcf_intc_readfn,
-                                       mcf_intc_writefn, s);
+                                       mcf_intc_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x100, iomemtype);
 
     return qemu_allocate_irqs(mcf_intc_set_irq, s, 64);
diff --git a/hw/mcf_uart.c b/hw/mcf_uart.c
index d16bac7..db57096 100644
--- a/hw/mcf_uart.c
+++ b/hw/mcf_uart.c
@@ -304,6 +304,7 @@ void mcf_uart_mm_init(target_phys_addr_t base, qemu_irq irq,
 
     s = mcf_uart_init(irq, chr);
     iomemtype = cpu_register_io_memory(mcf_uart_readfn,
-                                       mcf_uart_writefn, s);
+                                       mcf_uart_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x40, iomemtype);
 }
diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c
index 66397c0..1264743 100644
--- a/hw/mips_jazz.c
+++ b/hw/mips_jazz.c
@@ -191,7 +191,8 @@ void mips_jazz_init (ram_addr_t ram_size,
 
     /* Chipset */
     rc4030_opaque = rc4030_init(env->irq[6], env->irq[3], &rc4030, &dmas);
-    s_dma_dummy = cpu_register_io_memory(dma_dummy_read, dma_dummy_write, NULL);
+    s_dma_dummy = cpu_register_io_memory(dma_dummy_read, dma_dummy_write, NULL,
+                                         DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(0x8000d000, 0x00001000, s_dma_dummy);
 
     /* ISA devices */
@@ -259,7 +260,8 @@ void mips_jazz_init (ram_addr_t ram_size,
 
     /* Real time clock */
     rtc_init(1980, NULL);
-    s_rtc = cpu_register_io_memory(rtc_read, rtc_write, NULL);
+    s_rtc = cpu_register_io_memory(rtc_read, rtc_write, NULL,
+                                   DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(0x80004000, 0x00001000, s_rtc);
 
     /* Keyboard (i8042) */
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index 6be8aa7..5ef3fcb 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -436,7 +436,8 @@ static MaltaFPGAState *malta_fpga_init(target_phys_addr_t base, qemu_irq uart_ir
     s = (MaltaFPGAState *)qemu_mallocz(sizeof(MaltaFPGAState));
 
     malta = cpu_register_io_memory(malta_fpga_read,
-                                   malta_fpga_write, s);
+                                   malta_fpga_write, s,
+                                   DEVICE_NATIVE_ENDIAN);
 
     cpu_register_physical_memory(base, 0x900, malta);
     /* 0xa00 is less than a page, so will still get the right offsets.  */
diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c
index aa34890..afe52f3 100644
--- a/hw/mips_r4k.c
+++ b/hw/mips_r4k.c
@@ -204,7 +204,8 @@ void mips_r4k_init (ram_addr_t ram_size,
 
     if (!mips_qemu_iomemtype) {
         mips_qemu_iomemtype = cpu_register_io_memory(mips_qemu_read,
-                                                     mips_qemu_write, NULL);
+                                                     mips_qemu_write, NULL,
+                                                     DEVICE_NATIVE_ENDIAN);
     }
     cpu_register_physical_memory(0x1fbf0000, 0x10000, mips_qemu_iomemtype);
 
diff --git a/hw/mpcore.c b/hw/mpcore.c
index b4db191..fc05215 100644
--- a/hw/mpcore.c
+++ b/hw/mpcore.c
@@ -276,7 +276,8 @@ static int mpcore_priv_init(SysBusDevice *dev)
 
     gic_init(&s->gic, s->num_cpu);
     s->iomemtype = cpu_register_io_memory(mpcore_priv_readfn,
-                                          mpcore_priv_writefn, s);
+                                          mpcore_priv_writefn, s,
+                                          DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio_cb(dev, 0x2000, mpcore_priv_map);
     for (i = 0; i < s->num_cpu * 2; i++) {
         mpcore_timer_init(s, &s->timer[i], i);
diff --git a/hw/msix.c b/hw/msix.c
index f66d255..e123082 100644
--- a/hw/msix.c
+++ b/hw/msix.c
@@ -254,7 +254,8 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries,
     msix_mask_all(dev, nentries);
 
     dev->msix_mmio_index = cpu_register_io_memory(msix_mmio_read,
-                                                  msix_mmio_write, dev);
+                                                  msix_mmio_write, dev,
+                                                  DEVICE_NATIVE_ENDIAN);
     if (dev->msix_mmio_index == -1) {
         ret = -EBUSY;
         goto err_index;
diff --git a/hw/mst_fpga.c b/hw/mst_fpga.c
index 8fc348f..5252fc5 100644
--- a/hw/mst_fpga.c
+++ b/hw/mst_fpga.c
@@ -232,7 +232,7 @@ qemu_irq *mst_irq_init(PXA2xxState *cpu, uint32_t base, int irq)
 	s->pins = qi;
 
 	iomemtype = cpu_register_io_memory(mst_fpga_readfn,
-		mst_fpga_writefn, s);
+		mst_fpga_writefn, s, DEVICE_NATIVE_ENDIAN);
 	cpu_register_physical_memory(base, 0x00100000, iomemtype);
 	register_savevm(NULL, "mainstone_fpga", 0, 0, mst_fpga_save,
                         mst_fpga_load, s);
diff --git a/hw/musicpal.c b/hw/musicpal.c
index 56f2766..d98aa8d 100644
--- a/hw/musicpal.c
+++ b/hw/musicpal.c
@@ -388,7 +388,8 @@ static int mv88w8618_eth_init(SysBusDevice *dev)
     s->nic = qemu_new_nic(&net_mv88w8618_info, &s->conf,
                           dev->qdev.info->name, dev->qdev.id, s);
     s->mmio_index = cpu_register_io_memory(mv88w8618_eth_readfn,
-                                           mv88w8618_eth_writefn, s);
+                                           mv88w8618_eth_writefn, s,
+                                           DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, MP_ETH_SIZE, s->mmio_index);
     return 0;
 }
@@ -600,7 +601,8 @@ static int musicpal_lcd_init(SysBusDevice *dev)
     s->brightness = 7;
 
     iomemtype = cpu_register_io_memory(musicpal_lcd_readfn,
-                                       musicpal_lcd_writefn, s);
+                                       musicpal_lcd_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, MP_LCD_SIZE, iomemtype);
 
     s->ds = graphic_console_init(lcd_refresh, lcd_invalidate,
@@ -725,7 +727,8 @@ static int mv88w8618_pic_init(SysBusDevice *dev)
     qdev_init_gpio_in(&dev->qdev, mv88w8618_pic_set_irq, 32);
     sysbus_init_irq(dev, &s->parent_irq);
     iomemtype = cpu_register_io_memory(mv88w8618_pic_readfn,
-                                       mv88w8618_pic_writefn, s);
+                                       mv88w8618_pic_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, MP_PIC_SIZE, iomemtype);
     return 0;
 }
@@ -886,7 +889,8 @@ static int mv88w8618_pit_init(SysBusDevice *dev)
     }
 
     iomemtype = cpu_register_io_memory(mv88w8618_pit_readfn,
-                                       mv88w8618_pit_writefn, s);
+                                       mv88w8618_pit_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, MP_PIT_SIZE, iomemtype);
     return 0;
 }
@@ -976,7 +980,8 @@ static int mv88w8618_flashcfg_init(SysBusDevice *dev)
 
     s->cfgr0 = 0xfffe4285; /* Default as set by U-Boot for 8 MB flash */
     iomemtype = cpu_register_io_memory(mv88w8618_flashcfg_readfn,
-                                       mv88w8618_flashcfg_writefn, s);
+                                       mv88w8618_flashcfg_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, MP_FLASHCFG_SIZE, iomemtype);
     return 0;
 }
@@ -1037,7 +1042,8 @@ static void musicpal_misc_init(void)
     int iomemtype;
 
     iomemtype = cpu_register_io_memory(musicpal_misc_readfn,
-                                       musicpal_misc_writefn, NULL);
+                                       musicpal_misc_writefn, NULL,
+                                       DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(MP_MISC_BASE, MP_MISC_SIZE, iomemtype);
 }
 
@@ -1082,7 +1088,8 @@ static int mv88w8618_wlan_init(SysBusDevice *dev)
     int iomemtype;
 
     iomemtype = cpu_register_io_memory(mv88w8618_wlan_readfn,
-                                       mv88w8618_wlan_writefn, NULL);
+                                       mv88w8618_wlan_writefn, NULL,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, MP_WLAN_SIZE, iomemtype);
     return 0;
 }
@@ -1293,7 +1300,8 @@ static int musicpal_gpio_init(SysBusDevice *dev)
     sysbus_init_irq(dev, &s->irq);
 
     iomemtype = cpu_register_io_memory(musicpal_gpio_readfn,
-                                       musicpal_gpio_writefn, s);
+                                       musicpal_gpio_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, MP_GPIO_SIZE, iomemtype);
 
     qdev_init_gpio_out(&dev->qdev, s->out, ARRAY_SIZE(s->out));
diff --git a/hw/omap.h b/hw/omap.h
index fe32ca5..c227a82 100644
--- a/hw/omap.h
+++ b/hw/omap.h
@@ -1129,7 +1129,8 @@ inline static int debug_register_io_memory(CPUReadMemoryFunc * const *mem_read,
     s->mem_write = mem_write;
     s->opaque = opaque;
     s->in = 0;
-    return cpu_register_io_memory(io_readfn, io_writefn, s);
+    return cpu_register_io_memory(io_readfn, io_writefn, s,
+                                  DEVICE_NATIVE_ENDIAN);
 }
 #  define cpu_register_io_memory	debug_register_io_memory
 # endif
diff --git a/hw/omap1.c b/hw/omap1.c
index f4966f7..d5e4dab 100644
--- a/hw/omap1.c
+++ b/hw/omap1.c
@@ -264,7 +264,7 @@ static struct omap_mpu_timer_s *omap_mpu_timer_init(target_phys_addr_t base,
     omap_timer_clk_setup(s);
 
     iomemtype = cpu_register_io_memory(omap_mpu_timer_readfn,
-                    omap_mpu_timer_writefn, s);
+                    omap_mpu_timer_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x100, iomemtype);
 
     return s;
@@ -387,7 +387,7 @@ static struct omap_watchdog_timer_s *omap_wd_timer_init(target_phys_addr_t base,
     omap_timer_clk_setup(&s->timer);
 
     iomemtype = cpu_register_io_memory(omap_wd_timer_readfn,
-                    omap_wd_timer_writefn, s);
+                    omap_wd_timer_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x100, iomemtype);
 
     return s;
@@ -489,7 +489,7 @@ static struct omap_32khz_timer_s *omap_os_timer_init(target_phys_addr_t base,
     omap_timer_clk_setup(&s->timer);
 
     iomemtype = cpu_register_io_memory(omap_os_timer_readfn,
-                    omap_os_timer_writefn, s);
+                    omap_os_timer_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x800, iomemtype);
 
     return s;
@@ -716,7 +716,7 @@ static void omap_ulpd_pm_init(target_phys_addr_t base,
                 struct omap_mpu_state_s *mpu)
 {
     int iomemtype = cpu_register_io_memory(omap_ulpd_pm_readfn,
-                    omap_ulpd_pm_writefn, mpu);
+                    omap_ulpd_pm_writefn, mpu, DEVICE_NATIVE_ENDIAN);
 
     cpu_register_physical_memory(base, 0x800, iomemtype);
     omap_ulpd_pm_reset(mpu);
@@ -931,7 +931,7 @@ static void omap_pin_cfg_init(target_phys_addr_t base,
                 struct omap_mpu_state_s *mpu)
 {
     int iomemtype = cpu_register_io_memory(omap_pin_cfg_readfn,
-                    omap_pin_cfg_writefn, mpu);
+                    omap_pin_cfg_writefn, mpu, DEVICE_NATIVE_ENDIAN);
 
     cpu_register_physical_memory(base, 0x800, iomemtype);
     omap_pin_cfg_reset(mpu);
@@ -1001,7 +1001,7 @@ static CPUWriteMemoryFunc * const omap_id_writefn[] = {
 static void omap_id_init(struct omap_mpu_state_s *mpu)
 {
     int iomemtype = cpu_register_io_memory(omap_id_readfn,
-                    omap_id_writefn, mpu);
+                    omap_id_writefn, mpu, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory_offset(0xfffe1800, 0x800, iomemtype, 0xfffe1800);
     cpu_register_physical_memory_offset(0xfffed400, 0x100, iomemtype, 0xfffed400);
     if (!cpu_is_omap15xx(mpu))
@@ -1084,7 +1084,7 @@ static void omap_mpui_init(target_phys_addr_t base,
                 struct omap_mpu_state_s *mpu)
 {
     int iomemtype = cpu_register_io_memory(omap_mpui_readfn,
-                    omap_mpui_writefn, mpu);
+                    omap_mpui_writefn, mpu, DEVICE_NATIVE_ENDIAN);
 
     cpu_register_physical_memory(base, 0x100, iomemtype);
 
@@ -1193,7 +1193,7 @@ static struct omap_tipb_bridge_s *omap_tipb_bridge_init(target_phys_addr_t base,
     omap_tipb_bridge_reset(s);
 
     iomemtype = cpu_register_io_memory(omap_tipb_bridge_readfn,
-                    omap_tipb_bridge_writefn, s);
+                    omap_tipb_bridge_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x100, iomemtype);
 
     return s;
@@ -1299,7 +1299,7 @@ static void omap_tcmi_init(target_phys_addr_t base,
                 struct omap_mpu_state_s *mpu)
 {
     int iomemtype = cpu_register_io_memory(omap_tcmi_readfn,
-                    omap_tcmi_writefn, mpu);
+                    omap_tcmi_writefn, mpu, DEVICE_NATIVE_ENDIAN);
 
     cpu_register_physical_memory(base, 0x100, iomemtype);
     omap_tcmi_reset(mpu);
@@ -1372,7 +1372,7 @@ static void omap_dpll_init(struct dpll_ctl_s *s, target_phys_addr_t base,
                 omap_clk clk)
 {
     int iomemtype = cpu_register_io_memory(omap_dpll_readfn,
-                    omap_dpll_writefn, s);
+                    omap_dpll_writefn, s, DEVICE_NATIVE_ENDIAN);
 
     s->dpll = clk;
     omap_dpll_reset(s);
@@ -1776,8 +1776,10 @@ static void omap_clkm_init(target_phys_addr_t mpu_base,
                 target_phys_addr_t dsp_base, struct omap_mpu_state_s *s)
 {
     int iomemtype[2] = {
-        cpu_register_io_memory(omap_clkm_readfn, omap_clkm_writefn, s),
-        cpu_register_io_memory(omap_clkdsp_readfn, omap_clkdsp_writefn, s),
+        cpu_register_io_memory(omap_clkm_readfn, omap_clkm_writefn, s,
+                               DEVICE_NATIVE_ENDIAN),
+        cpu_register_io_memory(omap_clkdsp_readfn, omap_clkdsp_writefn, s,
+                               DEVICE_NATIVE_ENDIAN),
     };
 
     s->clkm.arm_idlect1 = 0x03ff;
@@ -2031,7 +2033,7 @@ struct omap_mpuio_s *omap_mpuio_init(target_phys_addr_t base,
     omap_mpuio_reset(s);
 
     iomemtype = cpu_register_io_memory(omap_mpuio_readfn,
-                    omap_mpuio_writefn, s);
+                    omap_mpuio_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x800, iomemtype);
 
     omap_clk_adduser(clk, qemu_allocate_irqs(omap_mpuio_onoff, s, 1)[0]);
@@ -2216,7 +2218,7 @@ struct omap_uwire_s *omap_uwire_init(target_phys_addr_t base,
     omap_uwire_reset(s);
 
     iomemtype = cpu_register_io_memory(omap_uwire_readfn,
-                    omap_uwire_writefn, s);
+                    omap_uwire_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x800, iomemtype);
 
     return s;
@@ -2317,7 +2319,7 @@ static void omap_pwl_init(target_phys_addr_t base, struct omap_mpu_state_s *s,
     omap_pwl_reset(s);
 
     iomemtype = cpu_register_io_memory(omap_pwl_readfn,
-                    omap_pwl_writefn, s);
+                    omap_pwl_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x800, iomemtype);
 
     omap_clk_adduser(clk, qemu_allocate_irqs(omap_pwl_clk_update, s, 1)[0]);
@@ -2412,7 +2414,7 @@ static void omap_pwt_init(target_phys_addr_t base, struct omap_mpu_state_s *s,
     omap_pwt_reset(s);
 
     iomemtype = cpu_register_io_memory(omap_pwt_readfn,
-                    omap_pwt_writefn, s);
+                    omap_pwt_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x800, iomemtype);
 }
 
@@ -2825,7 +2827,7 @@ static struct omap_rtc_s *omap_rtc_init(target_phys_addr_t base,
     omap_rtc_reset(s);
 
     iomemtype = cpu_register_io_memory(omap_rtc_readfn,
-                    omap_rtc_writefn, s);
+                    omap_rtc_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x800, iomemtype);
 
     return s;
@@ -3347,7 +3349,7 @@ struct omap_mcbsp_s *omap_mcbsp_init(target_phys_addr_t base,
     omap_mcbsp_reset(s);
 
     iomemtype = cpu_register_io_memory(omap_mcbsp_readfn,
-                    omap_mcbsp_writefn, s);
+                    omap_mcbsp_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x800, iomemtype);
 
     return s;
@@ -3519,7 +3521,7 @@ static struct omap_lpg_s *omap_lpg_init(target_phys_addr_t base, omap_clk clk)
     omap_lpg_reset(s);
 
     iomemtype = cpu_register_io_memory(omap_lpg_readfn,
-                    omap_lpg_writefn, s);
+                    omap_lpg_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x800, iomemtype);
 
     omap_clk_adduser(clk, qemu_allocate_irqs(omap_lpg_clk_update, s, 1)[0]);
@@ -3552,7 +3554,7 @@ static CPUWriteMemoryFunc * const omap_mpui_io_writefn[] = {
 static void omap_setup_mpui_io(struct omap_mpu_state_s *mpu)
 {
     int iomemtype = cpu_register_io_memory(omap_mpui_io_readfn,
-                    omap_mpui_io_writefn, mpu);
+                    omap_mpui_io_writefn, mpu, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(OMAP_MPUI_BASE, 0x7fff, iomemtype);
 }
 
diff --git a/hw/omap2.c b/hw/omap2.c
index e35a56e..0f13272 100644
--- a/hw/omap2.c
+++ b/hw/omap2.c
@@ -600,7 +600,7 @@ static struct omap_eac_s *omap_eac_init(struct omap_target_agent_s *ta,
     AUD_register_card("OMAP EAC", &s->codec.card);
 
     iomemtype = cpu_register_io_memory(omap_eac_readfn,
-                    omap_eac_writefn, s);
+                    omap_eac_writefn, s, DEVICE_NATIVE_ENDIAN);
     omap_l4_attach(ta, 0, iomemtype);
 
     return s;
@@ -788,7 +788,7 @@ static struct omap_sti_s *omap_sti_init(struct omap_target_agent_s *ta,
     omap_l4_attach(ta, 0, iomemtype);
 
     iomemtype = cpu_register_io_memory(omap_sti_fifo_readfn,
-                    omap_sti_fifo_writefn, s);
+                    omap_sti_fifo_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(channel_base, 0x10000, iomemtype);
 
     return s;
diff --git a/hw/omap_dma.c b/hw/omap_dma.c
index 3e718ba..8e2dcc9 100644
--- a/hw/omap_dma.c
+++ b/hw/omap_dma.c
@@ -1659,7 +1659,7 @@ struct soc_dma_s *omap_dma_init(target_phys_addr_t base, qemu_irq *irqs,
     omap_dma_clk_update(s, 0, 1);
 
     iomemtype = cpu_register_io_memory(omap_dma_readfn,
-                    omap_dma_writefn, s);
+                    omap_dma_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, memsize, iomemtype);
 
     mpu->drq = s->dma->drq;
@@ -2066,7 +2066,7 @@ struct soc_dma_s *omap_dma4_init(target_phys_addr_t base, qemu_irq *irqs,
     omap_dma_clk_update(s, 0, !!s->dma->freq);
 
     iomemtype = cpu_register_io_memory(omap_dma4_readfn,
-                    omap_dma4_writefn, s);
+                    omap_dma4_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x1000, iomemtype);
 
     mpu->drq = s->dma->drq;
diff --git a/hw/omap_dss.c b/hw/omap_dss.c
index 044f2d2..afe287a 100644
--- a/hw/omap_dss.c
+++ b/hw/omap_dss.c
@@ -1045,7 +1045,7 @@ struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta,
     iomemtype[3] = l4_register_io_memory(omap_venc1_readfn,
                     omap_venc1_writefn, s);
     iomemtype[4] = cpu_register_io_memory(omap_im3_readfn,
-                    omap_im3_writefn, s);
+                    omap_im3_writefn, s, DEVICE_NATIVE_ENDIAN);
     omap_l4_attach(ta, 0, iomemtype[0]);
     omap_l4_attach(ta, 1, iomemtype[1]);
     omap_l4_attach(ta, 2, iomemtype[2]);
diff --git a/hw/omap_gpio.c b/hw/omap_gpio.c
index d978c7a..478f7d9 100644
--- a/hw/omap_gpio.c
+++ b/hw/omap_gpio.c
@@ -183,7 +183,7 @@ struct omap_gpio_s *omap_gpio_init(target_phys_addr_t base,
     omap_gpio_reset(s);
 
     iomemtype = cpu_register_io_memory(omap_gpio_readfn,
-                    omap_gpio_writefn, s);
+                    omap_gpio_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x1000, iomemtype);
 
     return s;
diff --git a/hw/omap_gpmc.c b/hw/omap_gpmc.c
index 72cfecc..8bf3343 100644
--- a/hw/omap_gpmc.c
+++ b/hw/omap_gpmc.c
@@ -390,7 +390,7 @@ struct omap_gpmc_s *omap_gpmc_init(target_phys_addr_t base, qemu_irq irq)
     omap_gpmc_reset(s);
 
     iomemtype = cpu_register_io_memory(omap_gpmc_readfn,
-                    omap_gpmc_writefn, s);
+                    omap_gpmc_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x1000, iomemtype);
 
     return s;
diff --git a/hw/omap_i2c.c b/hw/omap_i2c.c
index d133977..5cabb5a 100644
--- a/hw/omap_i2c.c
+++ b/hw/omap_i2c.c
@@ -437,7 +437,7 @@ struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base,
     omap_i2c_reset(s);
 
     iomemtype = cpu_register_io_memory(omap_i2c_readfn,
-                    omap_i2c_writefn, s);
+                    omap_i2c_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x800, iomemtype);
 
     return s;
diff --git a/hw/omap_intc.c b/hw/omap_intc.c
index 59893b7..001e20b 100644
--- a/hw/omap_intc.c
+++ b/hw/omap_intc.c
@@ -371,7 +371,7 @@ struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base,
     omap_inth_reset(s);
 
     iomemtype = cpu_register_io_memory(omap_inth_readfn,
-                    omap_inth_writefn, s);
+                    omap_inth_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, size, iomemtype);
 
     return s;
@@ -591,7 +591,7 @@ struct omap_intr_handler_s *omap2_inth_init(target_phys_addr_t base,
     omap_inth_reset(s);
 
     iomemtype = cpu_register_io_memory(omap2_inth_readfn,
-                    omap2_inth_writefn, s);
+                    omap2_inth_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, size, iomemtype);
 
     return s;
diff --git a/hw/omap_l4.c b/hw/omap_l4.c
index bf8ba36..4af0ca8 100644
--- a/hw/omap_l4.c
+++ b/hw/omap_l4.c
@@ -107,7 +107,8 @@ int l4_register_io_memory(CPUReadMemoryFunc * const *mem_read,
                           CPUWriteMemoryFunc * const *mem_write,
                           void *opaque)
 {
-    return cpu_register_io_memory(mem_read, mem_write, opaque);
+    return cpu_register_io_memory(mem_read, mem_write, opaque,
+                                  DEVICE_NATIVE_ENDIAN);
 }
 #endif
 
@@ -131,7 +132,7 @@ struct omap_l4_s *omap_l4_init(target_phys_addr_t base, int ta_num)
 
     omap_cpu_io_entry =
             cpu_register_io_memory(omap_l4_io_readfn,
-                            omap_l4_io_writefn, bus);
+                            omap_l4_io_writefn, bus, DEVICE_NATIVE_ENDIAN);
 # define L4_PAGES	(0xb4000 / TARGET_PAGE_SIZE)
     omap_l4_io_readb_fn = qemu_mallocz(sizeof(void *) * L4_PAGES);
     omap_l4_io_readh_fn = qemu_mallocz(sizeof(void *) * L4_PAGES);
diff --git a/hw/omap_lcdc.c b/hw/omap_lcdc.c
index 6affef6..0c2c550 100644
--- a/hw/omap_lcdc.c
+++ b/hw/omap_lcdc.c
@@ -450,7 +450,7 @@ struct omap_lcd_panel_s *omap_lcdc_init(target_phys_addr_t base, qemu_irq irq,
     omap_lcdc_reset(s);
 
     iomemtype = cpu_register_io_memory(omap_lcdc_readfn,
-                    omap_lcdc_writefn, s);
+                    omap_lcdc_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x100, iomemtype);
 
     s->state = graphic_console_init(omap_update_display,
diff --git a/hw/omap_mmc.c b/hw/omap_mmc.c
index 9d167ff..e9ec2f3 100644
--- a/hw/omap_mmc.c
+++ b/hw/omap_mmc.c
@@ -587,7 +587,7 @@ struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base,
     omap_mmc_reset(s);
 
     iomemtype = cpu_register_io_memory(omap_mmc_readfn,
-                    omap_mmc_writefn, s);
+                    omap_mmc_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x800, iomemtype);
 
     /* Instantiate the storage */
diff --git a/hw/omap_sdrc.c b/hw/omap_sdrc.c
index aefaebe..e183762 100644
--- a/hw/omap_sdrc.c
+++ b/hw/omap_sdrc.c
@@ -158,7 +158,7 @@ struct omap_sdrc_s *omap_sdrc_init(target_phys_addr_t base)
     omap_sdrc_reset(s);
 
     iomemtype = cpu_register_io_memory(omap_sdrc_readfn,
-                    omap_sdrc_writefn, s);
+                    omap_sdrc_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x1000, iomemtype);
 
     return s;
diff --git a/hw/omap_sx1.c b/hw/omap_sx1.c
index 44dc514..06bccbd 100644
--- a/hw/omap_sx1.c
+++ b/hw/omap_sx1.c
@@ -143,12 +143,15 @@ static void sx1_init(ram_addr_t ram_size,
                                  qemu_ram_alloc(NULL, "omap_sx1.flash0-0",
                                                 flash_size) | IO_MEM_ROM);
 
-    io = cpu_register_io_memory(static_readfn, static_writefn, &cs0val);
+    io = cpu_register_io_memory(static_readfn, static_writefn, &cs0val,
+                                DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(OMAP_CS0_BASE + flash_size,
                     OMAP_CS0_SIZE - flash_size, io);
-    io = cpu_register_io_memory(static_readfn, static_writefn, &cs2val);
+    io = cpu_register_io_memory(static_readfn, static_writefn, &cs2val,
+                                DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(OMAP_CS2_BASE, OMAP_CS2_SIZE, io);
-    io = cpu_register_io_memory(static_readfn, static_writefn, &cs3val);
+    io = cpu_register_io_memory(static_readfn, static_writefn, &cs3val,
+                                DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(OMAP_CS3_BASE, OMAP_CS3_SIZE, io);
 
     fl_idx = 0;
@@ -175,7 +178,8 @@ static void sx1_init(ram_addr_t ram_size,
         cpu_register_physical_memory(OMAP_CS1_BASE, flash1_size,
                                      qemu_ram_alloc(NULL, "omap_sx1.flash1-0",
                                                     flash1_size) | IO_MEM_ROM);
-        io = cpu_register_io_memory(static_readfn, static_writefn, &cs1val);
+        io = cpu_register_io_memory(static_readfn, static_writefn, &cs1val,
+                                    DEVICE_NATIVE_ENDIAN);
         cpu_register_physical_memory(OMAP_CS1_BASE + flash1_size,
                         OMAP_CS1_SIZE - flash1_size, io);
 
@@ -189,7 +193,8 @@ static void sx1_init(ram_addr_t ram_size,
         }
         fl_idx++;
     } else {
-        io = cpu_register_io_memory(static_readfn, static_writefn, &cs1val);
+        io = cpu_register_io_memory(static_readfn, static_writefn, &cs1val,
+                                    DEVICE_NATIVE_ENDIAN);
         cpu_register_physical_memory(OMAP_CS1_BASE, OMAP_CS1_SIZE, io);
     }
 
diff --git a/hw/omap_uart.c b/hw/omap_uart.c
index cc66cd9..9cee81d 100644
--- a/hw/omap_uart.c
+++ b/hw/omap_uart.c
@@ -170,7 +170,7 @@ struct omap_uart_s *omap2_uart_init(struct omap_target_agent_s *ta,
     struct omap_uart_s *s = omap_uart_init(base, irq,
                     fclk, iclk, txdma, rxdma, label, chr);
     int iomemtype = cpu_register_io_memory(omap_uart_readfn,
-                    omap_uart_writefn, s);
+                    omap_uart_writefn, s, DEVICE_NATIVE_ENDIAN);
 
     s->ta = ta;
 
diff --git a/hw/onenand.c b/hw/onenand.c
index f7afeca..d9cdcf2 100644
--- a/hw/onenand.c
+++ b/hw/onenand.c
@@ -630,7 +630,7 @@ void *onenand_init(uint32_t id, int regshift, qemu_irq irq)
     s->blockwp = qemu_malloc(s->blocks);
     s->density_mask = (id & (1 << 11)) ? (1 << (6 + ((id >> 12) & 7))) : 0;
     s->iomemtype = cpu_register_io_memory(onenand_readfn,
-                    onenand_writefn, s);
+                    onenand_writefn, s, DEVICE_NATIVE_ENDIAN);
     if (!dinfo)
         s->image = memset(qemu_malloc(size + (size >> 5)),
                         0xff, size + (size >> 5));
diff --git a/hw/openpic.c b/hw/openpic.c
index f6b8f21..9e2500a 100644
--- a/hw/openpic.c
+++ b/hw/openpic.c
@@ -1035,7 +1035,8 @@ static void openpic_map(PCIDevice *pci_dev, int region_num,
     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);
+                                           openpic_src_write, NULL
+                                           DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(isu_base, 0x20 * (EXT_IRQ + 2),
                                  opp_io_memory);
 #endif
@@ -1202,8 +1203,8 @@ qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
     } else {
         opp = qemu_mallocz(sizeof(openpic_t));
     }
-    opp->mem_index = cpu_register_io_memory(openpic_read,
-                                            openpic_write, opp);
+    opp->mem_index = cpu_register_io_memory(openpic_read, openpic_write, opp,
+                                            DEVICE_NATIVE_ENDIAN);
 
     //    isu_base &= 0xFFFC0000;
     opp->nb_cpus = nb_cpus;
@@ -1671,7 +1672,8 @@ qemu_irq *mpic_init (target_phys_addr_t base, int nb_cpus,
     for (i = 0; i < sizeof(list)/sizeof(list[0]); i++) {
         int mem_index;
 
-        mem_index = cpu_register_io_memory(list[i].read, list[i].write, mpp);
+        mem_index = cpu_register_io_memory(list[i].read, list[i].write, mpp,
+                                           DEVICE_NATIVE_ENDIAN);
         if (mem_index < 0) {
             goto free;
         }
diff --git a/hw/palm.c b/hw/palm.c
index 193aa11..dd8d1e5 100644
--- a/hw/palm.c
+++ b/hw/palm.c
@@ -216,14 +216,18 @@ static void palmte_init(ram_addr_t ram_size,
                                  qemu_ram_alloc(NULL, "palmte.flash",
                                                 flash_size) | IO_MEM_ROM);
 
-    io = cpu_register_io_memory(static_readfn, static_writefn, &cs0val);
+    io = cpu_register_io_memory(static_readfn, static_writefn, &cs0val,
+                                DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(OMAP_CS0_BASE + flash_size,
                     OMAP_CS0_SIZE - flash_size, io);
-    io = cpu_register_io_memory(static_readfn, static_writefn, &cs1val);
+    io = cpu_register_io_memory(static_readfn, static_writefn, &cs1val,
+                                DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(OMAP_CS1_BASE, OMAP_CS1_SIZE, io);
-    io = cpu_register_io_memory(static_readfn, static_writefn, &cs2val);
+    io = cpu_register_io_memory(static_readfn, static_writefn, &cs2val,
+                                DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(OMAP_CS2_BASE, OMAP_CS2_SIZE, io);
-    io = cpu_register_io_memory(static_readfn, static_writefn, &cs3val);
+    io = cpu_register_io_memory(static_readfn, static_writefn, &cs3val,
+                                DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(OMAP_CS3_BASE, OMAP_CS3_SIZE, io);
 
     palmte_microwire_setup(cpu);
diff --git a/hw/parallel.c b/hw/parallel.c
index 6b11672..00005c4 100644
--- a/hw/parallel.c
+++ b/hw/parallel.c
@@ -577,7 +577,8 @@ ParallelState *parallel_mm_init(target_phys_addr_t base, int it_shift, qemu_irq
     s->it_shift = it_shift;
     qemu_register_reset(parallel_reset, s);
 
-    io_sw = cpu_register_io_memory(parallel_mm_read_sw, parallel_mm_write_sw, s);
+    io_sw = cpu_register_io_memory(parallel_mm_read_sw, parallel_mm_write_sw,
+                                   s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 8 << it_shift, io_sw);
     return s;
 }
diff --git a/hw/pcie_host.c b/hw/pcie_host.c
index c4feeca..21069ee 100644
--- a/hw/pcie_host.c
+++ b/hw/pcie_host.c
@@ -137,7 +137,8 @@ int pcie_host_init(PCIExpressHost *e)
 {
     e->base_addr = PCIE_BASE_ADDR_UNMAPPED;
     e->mmio_index =
-        cpu_register_io_memory(pcie_mmcfg_read, pcie_mmcfg_write, e);
+        cpu_register_io_memory(pcie_mmcfg_read, pcie_mmcfg_write, e,
+                               DEVICE_NATIVE_ENDIAN);
     if (e->mmio_index < 0) {
         return -1;
     }
diff --git a/hw/pckbd.c b/hw/pckbd.c
index 6e4e406..7f0e6bb 100644
--- a/hw/pckbd.c
+++ b/hw/pckbd.c
@@ -436,7 +436,8 @@ void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
     s->mask = mask;
 
     vmstate_register(NULL, 0, &vmstate_kbd, s);
-    s_io_memory = cpu_register_io_memory(kbd_mm_read, kbd_mm_write, s);
+    s_io_memory = cpu_register_io_memory(kbd_mm_read, kbd_mm_write, s,
+                                         DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, size, s_io_memory);
 
     s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c
index 3dfbe46..5c5bd21 100644
--- a/hw/pcnet-pci.c
+++ b/hw/pcnet-pci.c
@@ -294,7 +294,8 @@ static int pci_pcnet_init(PCIDevice *pci_dev)
 
     /* Handler for memory-mapped I/O */
     s->mmio_index =
-      cpu_register_io_memory(pcnet_mmio_read, pcnet_mmio_write, &d->state);
+      cpu_register_io_memory(pcnet_mmio_read, pcnet_mmio_write, &d->state,
+                             DEVICE_NATIVE_ENDIAN);
 
     pci_register_bar(pci_dev, 0, PCNET_IOPORT_SIZE,
                            PCI_BASE_ADDRESS_SPACE_IO, pcnet_ioport_map);
diff --git a/hw/pflash_cfi01.c b/hw/pflash_cfi01.c
index 19e13d6..fb20dfb 100644
--- a/hw/pflash_cfi01.c
+++ b/hw/pflash_cfi01.c
@@ -600,10 +600,12 @@ pflash_t *pflash_cfi01_register(target_phys_addr_t base, ram_addr_t off,
     pfl->storage = qemu_get_ram_ptr(off);
     if (be) {
         pfl->fl_mem = cpu_register_io_memory(pflash_read_ops_be,
-                                             pflash_write_ops_be, pfl);
+                                             pflash_write_ops_be, pfl,
+                                             DEVICE_NATIVE_ENDIAN);
     } else {
         pfl->fl_mem = cpu_register_io_memory(pflash_read_ops_le,
-                                             pflash_write_ops_le, pfl);
+                                             pflash_write_ops_le, pfl,
+                                             DEVICE_NATIVE_ENDIAN);
     }
     pfl->off = off;
     cpu_register_physical_memory(base, total_len,
diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c
index f3d3f41..3594a36 100644
--- a/hw/pflash_cfi02.c
+++ b/hw/pflash_cfi02.c
@@ -619,11 +619,11 @@ pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
     if (be) {
         pfl->fl_mem = cpu_register_io_memory(pflash_read_ops_be,
                                              pflash_write_ops_be,
-                                             pfl);
+                                             pfl, DEVICE_NATIVE_ENDIAN);
     } else {
         pfl->fl_mem = cpu_register_io_memory(pflash_read_ops_le,
                                              pflash_write_ops_le,
-                                             pfl);
+                                             pfl, DEVICE_NATIVE_ENDIAN);
     }
     pfl->off = off;
     pfl->base = base;
diff --git a/hw/pl011.c b/hw/pl011.c
index 02cf84a..77f0dbf 100644
--- a/hw/pl011.c
+++ b/hw/pl011.c
@@ -292,7 +292,8 @@ static int pl011_init(SysBusDevice *dev, const unsigned char *id)
     pl011_state *s = FROM_SYSBUS(pl011_state, dev);
 
     iomemtype = cpu_register_io_memory(pl011_readfn,
-                                       pl011_writefn, s);
+                                       pl011_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000,iomemtype);
     sysbus_init_irq(dev, &s->irq);
     s->id = id;
diff --git a/hw/pl022.c b/hw/pl022.c
index d7862bc..ffe05ab 100644
--- a/hw/pl022.c
+++ b/hw/pl022.c
@@ -294,7 +294,8 @@ static int pl022_init(SysBusDevice *dev)
     int iomemtype;
 
     iomemtype = cpu_register_io_memory(pl022_readfn,
-                                       pl022_writefn, s);
+                                       pl022_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, iomemtype);
     sysbus_init_irq(dev, &s->irq);
     s->ssi = ssi_create_bus(&dev->qdev, "ssi");
diff --git a/hw/pl031.c b/hw/pl031.c
index 45b7032..e3700c1 100644
--- a/hw/pl031.c
+++ b/hw/pl031.c
@@ -189,7 +189,8 @@ static int pl031_init(SysBusDevice *dev)
     pl031_state *s = FROM_SYSBUS(pl031_state, dev);
     struct tm tm;
 
-    iomemtype = cpu_register_io_memory(pl031_readfn, pl031_writefn, s);
+    iomemtype = cpu_register_io_memory(pl031_readfn, pl031_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     if (iomemtype == -1) {
         hw_error("pl031_init: Can't register I/O memory\n");
     }
diff --git a/hw/pl050.c b/hw/pl050.c
index a47786c..0573839 100644
--- a/hw/pl050.c
+++ b/hw/pl050.c
@@ -128,7 +128,8 @@ static int pl050_init(SysBusDevice *dev, int is_mouse)
     int iomemtype;
 
     iomemtype = cpu_register_io_memory(pl050_readfn,
-                                       pl050_writefn, s);
+                                       pl050_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, iomemtype);
     sysbus_init_irq(dev, &s->irq);
     s->is_mouse = is_mouse;
diff --git a/hw/pl061.c b/hw/pl061.c
index e4505f5..1997b7c 100644
--- a/hw/pl061.c
+++ b/hw/pl061.c
@@ -297,7 +297,8 @@ static int pl061_init(SysBusDevice *dev)
     pl061_state *s = FROM_SYSBUS(pl061_state, dev);
 
     iomemtype = cpu_register_io_memory(pl061_readfn,
-                                       pl061_writefn, s);
+                                       pl061_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, iomemtype);
     sysbus_init_irq(dev, &s->irq);
     qdev_init_gpio_in(&dev->qdev, pl061_set_irq, 8);
diff --git a/hw/pl080.c b/hw/pl080.c
index 2df65fa..1a3e06c 100644
--- a/hw/pl080.c
+++ b/hw/pl080.c
@@ -325,7 +325,8 @@ static int pl08x_init(SysBusDevice *dev, int nchannels)
     pl080_state *s = FROM_SYSBUS(pl080_state, dev);
 
     iomemtype = cpu_register_io_memory(pl080_readfn,
-                                       pl080_writefn, s);
+                                       pl080_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, iomemtype);
     sysbus_init_irq(dev, &s->irq);
     s->nchannels = nchannels;
diff --git a/hw/pl110.c b/hw/pl110.c
index 173458a..a4adb63 100644
--- a/hw/pl110.c
+++ b/hw/pl110.c
@@ -358,7 +358,8 @@ static int pl110_init(SysBusDevice *dev)
     int iomemtype;
 
     iomemtype = cpu_register_io_memory(pl110_readfn,
-                                       pl110_writefn, s);
+                                       pl110_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, iomemtype);
     sysbus_init_irq(dev, &s->irq);
     s->ds = graphic_console_init(pl110_update_display,
diff --git a/hw/pl181.c b/hw/pl181.c
index 85cadc4..3e5f92f 100644
--- a/hw/pl181.c
+++ b/hw/pl181.c
@@ -451,8 +451,8 @@ static int pl181_init(SysBusDevice *dev)
     pl181_state *s = FROM_SYSBUS(pl181_state, dev);
     BlockDriverState *bd;
 
-    iomemtype = cpu_register_io_memory(pl181_readfn,
-                                       pl181_writefn, s);
+    iomemtype = cpu_register_io_memory(pl181_readfn, pl181_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, iomemtype);
     sysbus_init_irq(dev, &s->irq[0]);
     sysbus_init_irq(dev, &s->irq[1]);
diff --git a/hw/pl190.c b/hw/pl190.c
index a4bc9c1..e04e6c1 100644
--- a/hw/pl190.c
+++ b/hw/pl190.c
@@ -233,7 +233,8 @@ static int pl190_init(SysBusDevice *dev)
     int iomemtype;
 
     iomemtype = cpu_register_io_memory(pl190_readfn,
-                                       pl190_writefn, s);
+                                       pl190_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, iomemtype);
     qdev_init_gpio_in(&dev->qdev, pl190_set_irq, 32);
     sysbus_init_irq(dev, &s->irq);
diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c
index c5897a9..9abede7 100644
--- a/hw/ppc405_boards.c
+++ b/hw/ppc405_boards.c
@@ -164,7 +164,8 @@ static void ref405ep_fpga_init (uint32_t base)
 
     fpga = qemu_mallocz(sizeof(ref405ep_fpga_t));
     fpga_memory = cpu_register_io_memory(ref405ep_fpga_read,
-                                         ref405ep_fpga_write, fpga);
+                                         ref405ep_fpga_write, fpga,
+                                         DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x00000100, fpga_memory);
     qemu_register_reset(&ref405ep_fpga_reset, fpga);
 }
@@ -488,7 +489,8 @@ static void taihu_cpld_init (uint32_t base)
 
     cpld = qemu_mallocz(sizeof(taihu_cpld_t));
     cpld_memory = cpu_register_io_memory(taihu_cpld_read,
-                                         taihu_cpld_write, cpld);
+                                         taihu_cpld_write, cpld,
+                                         DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x00000100, cpld_memory);
     qemu_register_reset(&taihu_cpld_reset, cpld);
 }
diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c
index 3600737..8136cb9 100644
--- a/hw/ppc405_uc.c
+++ b/hw/ppc405_uc.c
@@ -383,7 +383,8 @@ static void ppc4xx_opba_init(target_phys_addr_t base)
 #ifdef DEBUG_OPBA
     printf("%s: offset " TARGET_FMT_plx "\n", __func__, base);
 #endif
-    io = cpu_register_io_memory(opba_read, opba_write, opba);
+    io = cpu_register_io_memory(opba_read, opba_write, opba,
+                                DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x002, io);
     qemu_register_reset(ppc4xx_opba_reset, opba);
 }
@@ -809,7 +810,8 @@ static void ppc405_gpio_init(target_phys_addr_t base)
 #ifdef DEBUG_GPIO
     printf("%s: offset " TARGET_FMT_plx "\n", __func__, base);
 #endif
-    io = cpu_register_io_memory(ppc405_gpio_read, ppc405_gpio_write, gpio);
+    io = cpu_register_io_memory(ppc405_gpio_read, ppc405_gpio_write, gpio,
+                                DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x038, io);
     qemu_register_reset(&ppc405_gpio_reset, gpio);
 }
@@ -1218,7 +1220,8 @@ static void ppc405_i2c_init(target_phys_addr_t base, qemu_irq irq)
 #ifdef DEBUG_I2C
     printf("%s: offset " TARGET_FMT_plx "\n", __func__, base);
 #endif
-    io = cpu_register_io_memory(i2c_read, i2c_write, i2c);
+    io = cpu_register_io_memory(i2c_read, i2c_write, i2c,
+                                DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x011, io);
     qemu_register_reset(ppc4xx_i2c_reset, i2c);
 }
@@ -1501,7 +1504,7 @@ static void ppc4xx_gpt_init(target_phys_addr_t base, qemu_irq irqs[5])
 #ifdef DEBUG_GPT
     printf("%s: offset " TARGET_FMT_plx "\n", __func__, base);
 #endif
-    io = cpu_register_io_memory(gpt_read, gpt_write, gpt);
+    io = cpu_register_io_memory(gpt_read, gpt_write, gpt, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x0d4, io);
     qemu_register_reset(ppc4xx_gpt_reset, gpt);
 }
diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c
index 6e437e7..f2ecece 100644
--- a/hw/ppc4xx_pci.c
+++ b/hw/ppc4xx_pci.c
@@ -372,7 +372,8 @@ PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4],
 
     /* CFGADDR */
     index = cpu_register_io_memory(pci4xx_cfgaddr_read,
-                                   pci4xx_cfgaddr_write, controller);
+                                   pci4xx_cfgaddr_write, controller,
+                                   DEVICE_NATIVE_ENDIAN);
     if (index < 0)
         goto free;
     cpu_register_physical_memory(config_space + PCIC0_CFGADDR, 4, index);
@@ -384,7 +385,8 @@ PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4],
     cpu_register_physical_memory(config_space + PCIC0_CFGDATA, 4, index);
 
     /* Internal registers */
-    index = cpu_register_io_memory(pci_reg_read, pci_reg_write, controller);
+    index = cpu_register_io_memory(pci_reg_read, pci_reg_write, controller,
+                                   DEVICE_NATIVE_ENDIAN);
     if (index < 0)
         goto free;
     cpu_register_physical_memory(registers, PCI_REG_SIZE, index);
diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c
index 305b2d4..49b046b 100644
--- a/hw/ppc_newworld.c
+++ b/hw/ppc_newworld.c
@@ -260,7 +260,8 @@ static void ppc_core99_init (ram_addr_t ram_size,
     isa_mmio_init(0xf2000000, 0x00800000, 1);
 
     /* UniN init */
-    unin_memory = cpu_register_io_memory(unin_read, unin_write, NULL);
+    unin_memory = cpu_register_io_memory(unin_read, unin_write, NULL,
+                                         DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(0xf8000000, 0x00001000, unin_memory);
 
     openpic_irqs = qemu_mallocz(smp_cpus * sizeof(qemu_irq *));
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index b1f9cc7..80f5db6 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -690,7 +690,8 @@ static void ppc_prep_init (ram_addr_t ram_size,
     //    pci_bus = i440fx_init();
     /* Register 8 MB of ISA IO space (needed for non-contiguous map) */
     PPC_io_memory = cpu_register_io_memory(PPC_prep_io_read,
-                                           PPC_prep_io_write, sysctrl);
+                                           PPC_prep_io_write, sysctrl,
+                                           DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(0x80000000, 0x00800000, PPC_io_memory);
 
     /* init basic PC hardware */
@@ -755,12 +756,13 @@ static void ppc_prep_init (ram_addr_t ram_size,
     register_ioport_write(0x0800, 0x52, 1, &PREP_io_800_writeb, sysctrl);
     /* PCI intack location */
     PPC_io_memory = cpu_register_io_memory(PPC_intack_read,
-                                           PPC_intack_write, NULL);
+                                           PPC_intack_write, NULL,
+                                           DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(0xBFFFFFF0, 0x4, PPC_io_memory);
     /* PowerPC control and status register group */
 #if 0
     PPC_io_memory = cpu_register_io_memory(PPC_XCSR_read, PPC_XCSR_write,
-                                           NULL);
+                                           NULL, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(0xFEFF0000, 0x1000, PPC_io_memory);
 #endif
 
diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c
index 8ac99f2..71302ba 100644
--- a/hw/ppce500_pci.c
+++ b/hw/ppce500_pci.c
@@ -304,7 +304,8 @@ PCIBus *ppce500_pci_init(qemu_irq pci_irqs[4], target_phys_addr_t registers)
     cpu_register_physical_memory(registers + PCIE500_CFGDATA, 4, index);
 
     index = cpu_register_io_memory(e500_pci_reg_read,
-                                   e500_pci_reg_write, controller);
+                                   e500_pci_reg_write, controller,
+                                   DEVICE_NATIVE_ENDIAN);
     if (index < 0)
         goto free;
     cpu_register_physical_memory(registers + PCIE500_REG_BASE,
diff --git a/hw/prep_pci.c b/hw/prep_pci.c
index 0c2afe9..f88b825 100644
--- a/hw/prep_pci.c
+++ b/hw/prep_pci.c
@@ -125,7 +125,8 @@ PCIBus *pci_prep_init(qemu_irq *pic)
     pci_host_data_register_ioport(0xcfc, s);
 
     PPC_io_memory = cpu_register_io_memory(PPC_PCIIO_read,
-                                           PPC_PCIIO_write, s);
+                                           PPC_PCIIO_write, s,
+                                           DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(0x80800000, 0x00400000, PPC_io_memory);
 
     /* PCI host bridge */
diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c
index 6e04645..ab524a7 100644
--- a/hw/pxa2xx.c
+++ b/hw/pxa2xx.c
@@ -859,7 +859,8 @@ static int pxa2xx_ssp_init(SysBusDevice *dev)
     sysbus_init_irq(dev, &s->irq);
 
     iomemtype = cpu_register_io_memory(pxa2xx_ssp_readfn,
-                                       pxa2xx_ssp_writefn, s);
+                                       pxa2xx_ssp_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, iomemtype);
     register_savevm(&dev->qdev, "pxa2xx_ssp", -1, 0,
                     pxa2xx_ssp_save, pxa2xx_ssp_load, s);
@@ -1512,7 +1513,7 @@ PXA2xxI2CState *pxa2xx_i2c_init(target_phys_addr_t base,
     s->offset = base - (base & (~region_size) & TARGET_PAGE_MASK);
 
     iomemtype = cpu_register_io_memory(pxa2xx_i2c_readfn,
-                    pxa2xx_i2c_writefn, s);
+                    pxa2xx_i2c_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base & ~region_size,
                     region_size + 1, iomemtype);
 
@@ -1749,7 +1750,7 @@ static PXA2xxI2SState *pxa2xx_i2s_init(target_phys_addr_t base,
     pxa2xx_i2s_reset(s);
 
     iomemtype = cpu_register_io_memory(pxa2xx_i2s_readfn,
-                    pxa2xx_i2s_writefn, s);
+                    pxa2xx_i2s_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x100000, iomemtype);
 
     register_savevm(NULL, "pxa2xx_i2s", base, 0,
@@ -2009,7 +2010,7 @@ static PXA2xxFIrState *pxa2xx_fir_init(target_phys_addr_t base,
     pxa2xx_fir_reset(s);
 
     iomemtype = cpu_register_io_memory(pxa2xx_fir_readfn,
-                    pxa2xx_fir_writefn, s);
+                    pxa2xx_fir_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x1000, iomemtype);
 
     if (chr)
@@ -2102,7 +2103,7 @@ PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision)
     s->cm_regs[CCCR >> 2] = 0x02000210;	/* 416.0 MHz */
     s->clkcfg = 0x00000009;		/* Turbo mode active */
     iomemtype = cpu_register_io_memory(pxa2xx_cm_readfn,
-                    pxa2xx_cm_writefn, s);
+                    pxa2xx_cm_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(s->cm_base, 0x1000, iomemtype);
     register_savevm(NULL, "pxa2xx_cm", 0, 0, pxa2xx_cm_save, pxa2xx_cm_load, s);
 
@@ -2113,13 +2114,13 @@ PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision)
     s->mm_regs[MDREFR >> 2] = 0x03ca4000;
     s->mm_regs[MECR >> 2] = 0x00000001;	/* Two PC Card sockets */
     iomemtype = cpu_register_io_memory(pxa2xx_mm_readfn,
-                    pxa2xx_mm_writefn, s);
+                    pxa2xx_mm_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(s->mm_base, 0x1000, iomemtype);
     register_savevm(NULL, "pxa2xx_mm", 0, 0, pxa2xx_mm_save, pxa2xx_mm_load, s);
 
     s->pm_base = 0x40f00000;
     iomemtype = cpu_register_io_memory(pxa2xx_pm_readfn,
-                    pxa2xx_pm_writefn, s);
+                    pxa2xx_pm_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(s->pm_base, 0x100, iomemtype);
     register_savevm(NULL, "pxa2xx_pm", 0, 0, pxa2xx_pm_save, pxa2xx_pm_load, s);
 
@@ -2142,7 +2143,7 @@ PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision)
 
     s->rtc_base = 0x40900000;
     iomemtype = cpu_register_io_memory(pxa2xx_rtc_readfn,
-                    pxa2xx_rtc_writefn, s);
+                    pxa2xx_rtc_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(s->rtc_base, 0x1000, iomemtype);
     pxa2xx_rtc_init(s);
     register_savevm(NULL, "pxa2xx_rtc", 0, 0, pxa2xx_rtc_save,
@@ -2225,7 +2226,7 @@ PXA2xxState *pxa255_init(unsigned int sdram_size)
     s->cm_regs[CCCR >> 2] = 0x02000210;	/* 416.0 MHz */
     s->clkcfg = 0x00000009;		/* Turbo mode active */
     iomemtype = cpu_register_io_memory(pxa2xx_cm_readfn,
-                    pxa2xx_cm_writefn, s);
+                    pxa2xx_cm_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(s->cm_base, 0x1000, iomemtype);
     register_savevm(NULL, "pxa2xx_cm", 0, 0, pxa2xx_cm_save, pxa2xx_cm_load, s);
 
@@ -2236,13 +2237,13 @@ PXA2xxState *pxa255_init(unsigned int sdram_size)
     s->mm_regs[MDREFR >> 2] = 0x03ca4000;
     s->mm_regs[MECR >> 2] = 0x00000001;	/* Two PC Card sockets */
     iomemtype = cpu_register_io_memory(pxa2xx_mm_readfn,
-                    pxa2xx_mm_writefn, s);
+                    pxa2xx_mm_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(s->mm_base, 0x1000, iomemtype);
     register_savevm(NULL, "pxa2xx_mm", 0, 0, pxa2xx_mm_save, pxa2xx_mm_load, s);
 
     s->pm_base = 0x40f00000;
     iomemtype = cpu_register_io_memory(pxa2xx_pm_readfn,
-                    pxa2xx_pm_writefn, s);
+                    pxa2xx_pm_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(s->pm_base, 0x100, iomemtype);
     register_savevm(NULL, "pxa2xx_pm", 0, 0, pxa2xx_pm_save, pxa2xx_pm_load, s);
 
@@ -2265,7 +2266,7 @@ PXA2xxState *pxa255_init(unsigned int sdram_size)
 
     s->rtc_base = 0x40900000;
     iomemtype = cpu_register_io_memory(pxa2xx_rtc_readfn,
-                    pxa2xx_rtc_writefn, s);
+                    pxa2xx_rtc_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(s->rtc_base, 0x1000, iomemtype);
     pxa2xx_rtc_init(s);
     register_savevm(NULL, "pxa2xx_rtc", 0, 0, pxa2xx_rtc_save,
diff --git a/hw/pxa2xx_dma.c b/hw/pxa2xx_dma.c
index 9c479df..b512d34 100644
--- a/hw/pxa2xx_dma.c
+++ b/hw/pxa2xx_dma.c
@@ -504,7 +504,7 @@ static PXA2xxDMAState *pxa2xx_dma_init(target_phys_addr_t base,
     memset(s->req, 0, sizeof(uint8_t) * PXA2XX_DMA_NUM_REQUESTS);
 
     iomemtype = cpu_register_io_memory(pxa2xx_dma_readfn,
-                    pxa2xx_dma_writefn, s);
+                    pxa2xx_dma_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x00010000, iomemtype);
 
     register_savevm(NULL, "pxa2xx_dma", 0, 0, pxa2xx_dma_save, pxa2xx_dma_load, s);
diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c
index 2abcb65..0d03446 100644
--- a/hw/pxa2xx_gpio.c
+++ b/hw/pxa2xx_gpio.c
@@ -309,7 +309,7 @@ PXA2xxGPIOInfo *pxa2xx_gpio_init(target_phys_addr_t base,
     s->in = qemu_allocate_irqs(pxa2xx_gpio_set, s, lines);
 
     iomemtype = cpu_register_io_memory(pxa2xx_gpio_readfn,
-                    pxa2xx_gpio_writefn, s);
+                    pxa2xx_gpio_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x00001000, iomemtype);
 
     register_savevm(NULL, "pxa2xx_gpio", 0, 0,
diff --git a/hw/pxa2xx_keypad.c b/hw/pxa2xx_keypad.c
index dfa8945..4c99917 100644
--- a/hw/pxa2xx_keypad.c
+++ b/hw/pxa2xx_keypad.c
@@ -314,7 +314,7 @@ PXA2xxKeyPadState *pxa27x_keypad_init(target_phys_addr_t base,
     s->irq = irq;
 
     iomemtype = cpu_register_io_memory(pxa2xx_keypad_readfn,
-                    pxa2xx_keypad_writefn, s);
+                    pxa2xx_keypad_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x00100000, iomemtype);
 
     register_savevm(NULL, "pxa2xx_keypad", 0, 0,
diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c
index 111a0dc..1f2211a 100644
--- a/hw/pxa2xx_lcd.c
+++ b/hw/pxa2xx_lcd.c
@@ -929,7 +929,7 @@ PXA2xxLCDState *pxa2xx_lcdc_init(target_phys_addr_t base, qemu_irq irq)
     pxa2xx_lcdc_orientation(s, graphic_rotate);
 
     iomemtype = cpu_register_io_memory(pxa2xx_lcdc_readfn,
-                    pxa2xx_lcdc_writefn, s);
+                    pxa2xx_lcdc_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x00100000, iomemtype);
 
     s->ds = graphic_console_init(pxa2xx_update_display,
diff --git a/hw/pxa2xx_mmci.c b/hw/pxa2xx_mmci.c
index ca98660..24d409d 100644
--- a/hw/pxa2xx_mmci.c
+++ b/hw/pxa2xx_mmci.c
@@ -528,7 +528,7 @@ PXA2xxMMCIState *pxa2xx_mmci_init(target_phys_addr_t base,
     s->dma = dma;
 
     iomemtype = cpu_register_io_memory(pxa2xx_mmci_readfn,
-                    pxa2xx_mmci_writefn, s);
+                    pxa2xx_mmci_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x00100000, iomemtype);
 
     /* Instantiate the actual storage */
diff --git a/hw/pxa2xx_pcmcia.c b/hw/pxa2xx_pcmcia.c
index be1309f..50d4649 100644
--- a/hw/pxa2xx_pcmcia.c
+++ b/hw/pxa2xx_pcmcia.c
@@ -140,19 +140,19 @@ PXA2xxPCMCIAState *pxa2xx_pcmcia_init(target_phys_addr_t base)
 
     /* Socket I/O Memory Space */
     iomemtype = cpu_register_io_memory(pxa2xx_pcmcia_io_readfn,
-                    pxa2xx_pcmcia_io_writefn, s);
+                    pxa2xx_pcmcia_io_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base | 0x00000000, 0x04000000, iomemtype);
 
     /* Then next 64 MB is reserved */
 
     /* Socket Attribute Memory Space */
     iomemtype = cpu_register_io_memory(pxa2xx_pcmcia_attr_readfn,
-                    pxa2xx_pcmcia_attr_writefn, s);
+                    pxa2xx_pcmcia_attr_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base | 0x08000000, 0x04000000, iomemtype);
 
     /* Socket Common Memory Space */
     iomemtype = cpu_register_io_memory(pxa2xx_pcmcia_common_readfn,
-                    pxa2xx_pcmcia_common_writefn, s);
+                    pxa2xx_pcmcia_common_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base | 0x0c000000, 0x04000000, iomemtype);
 
     if (base == 0x30000000)
diff --git a/hw/pxa2xx_pic.c b/hw/pxa2xx_pic.c
index 4d8944b..a36da23 100644
--- a/hw/pxa2xx_pic.c
+++ b/hw/pxa2xx_pic.c
@@ -300,7 +300,7 @@ qemu_irq *pxa2xx_pic_init(target_phys_addr_t base, CPUState *env)
 
     /* Enable IC memory-mapped registers access.  */
     iomemtype = cpu_register_io_memory(pxa2xx_pic_readfn,
-                    pxa2xx_pic_writefn, s);
+                    pxa2xx_pic_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x00100000, iomemtype);
 
     /* Enable IC coprocessor access.  */
diff --git a/hw/pxa2xx_timer.c b/hw/pxa2xx_timer.c
index 0f0ffd3..b556d11 100644
--- a/hw/pxa2xx_timer.c
+++ b/hw/pxa2xx_timer.c
@@ -452,7 +452,7 @@ static pxa2xx_timer_info *pxa2xx_timer_init(target_phys_addr_t base,
     }
 
     iomemtype = cpu_register_io_memory(pxa2xx_timer_readfn,
-                    pxa2xx_timer_writefn, s);
+                    pxa2xx_timer_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x00001000, iomemtype);
 
     register_savevm(NULL, "pxa2xx_timer", 0, 0,
diff --git a/hw/r2d.c b/hw/r2d.c
index a58f653..c4f32ef 100644
--- a/hw/r2d.c
+++ b/hw/r2d.c
@@ -189,7 +189,8 @@ static qemu_irq *r2d_fpga_init(target_phys_addr_t base, qemu_irq irl)
     s->irl = irl;
 
     iomemtype = cpu_register_io_memory(r2d_fpga_readfn,
-				       r2d_fpga_writefn, s);
+				       r2d_fpga_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x40, iomemtype);
     return qemu_allocate_irqs(r2d_fpga_irq_set, s, NR_IRQS);
 }
diff --git a/hw/rc4030.c b/hw/rc4030.c
index abbc3eb..0a9d98d 100644
--- a/hw/rc4030.c
+++ b/hw/rc4030.c
@@ -819,9 +819,11 @@ void *rc4030_init(qemu_irq timer, qemu_irq jazz_bus,
     register_savevm(NULL, "rc4030", 0, 2, rc4030_save, rc4030_load, s);
     rc4030_reset(s);
 
-    s_chipset = cpu_register_io_memory(rc4030_read, rc4030_write, s);
+    s_chipset = cpu_register_io_memory(rc4030_read, rc4030_write, s,
+                                       DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(0x80000000, 0x300, s_chipset);
-    s_jazzio = cpu_register_io_memory(jazzio_read, jazzio_write, s);
+    s_jazzio = cpu_register_io_memory(jazzio_read, jazzio_write, s,
+                                      DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(0xf0000000, 0x00001000, s_jazzio);
 
     return s;
diff --git a/hw/realview.c b/hw/realview.c
index e9fcbc9..6eb6c6a 100644
--- a/hw/realview.c
+++ b/hw/realview.c
@@ -81,7 +81,8 @@ static int realview_i2c_init(SysBusDevice *dev)
     bus = i2c_init_bus(&dev->qdev, "i2c");
     s->bitbang = bitbang_i2c_init(bus);
     iomemtype = cpu_register_io_memory(realview_i2c_readfn,
-                                       realview_i2c_writefn, s);
+                                       realview_i2c_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, iomemtype);
     return 0;
 }
diff --git a/hw/realview_gic.c b/hw/realview_gic.c
index bd02b09..db908b6 100644
--- a/hw/realview_gic.c
+++ b/hw/realview_gic.c
@@ -64,7 +64,8 @@ static int realview_gic_init(SysBusDevice *dev)
 
     gic_init(&s->gic);
     s->iomemtype = cpu_register_io_memory(realview_gic_cpu_readfn,
-                                          realview_gic_cpu_writefn, s);
+                                          realview_gic_cpu_writefn, s,
+                                          DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio_cb(dev, 0x2000, realview_gic_map);
     return 0;
 }
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index d92981d..30a3960 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -3366,7 +3366,8 @@ static int pci_rtl8139_init(PCIDevice *dev)
 
     /* I/O handler for memory-mapped I/O */
     s->rtl8139_mmio_io_addr =
-        cpu_register_io_memory(rtl8139_mmio_read, rtl8139_mmio_write, s);
+        cpu_register_io_memory(rtl8139_mmio_read, rtl8139_mmio_write, s,
+                               DEVICE_NATIVE_ENDIAN);
 
     pci_register_bar(&s->dev, 0, 0x100,
                            PCI_BASE_ADDRESS_SPACE_IO,  rtl8139_ioport_map);
diff --git a/hw/sbi.c b/hw/sbi.c
index c4adc09..53f66f2 100644
--- a/hw/sbi.c
+++ b/hw/sbi.c
@@ -125,7 +125,8 @@ static int sbi_init1(SysBusDevice *dev)
         sysbus_init_irq(dev, &s->cpu_irqs[i]);
     }
 
-    sbi_io_memory = cpu_register_io_memory(sbi_mem_read, sbi_mem_write, s);
+    sbi_io_memory = cpu_register_io_memory(sbi_mem_read, sbi_mem_write, s,
+                                           DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, SBI_SIZE, sbi_io_memory);
 
     return 0;
diff --git a/hw/serial.c b/hw/serial.c
index 9ebc452..d21cbe9 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -955,10 +955,12 @@ SerialState *serial_mm_init (target_phys_addr_t base, int it_shift,
     if (ioregister) {
         if (be) {
             s_io_memory = cpu_register_io_memory(serial_mm_read_be,
-                                                 serial_mm_write_be, s);
+                                                 serial_mm_write_be, s,
+                                                 DEVICE_NATIVE_ENDIAN);
         } else {
             s_io_memory = cpu_register_io_memory(serial_mm_read_le,
-                                                 serial_mm_write_le, s);
+                                                 serial_mm_write_le, s,
+                                                 DEVICE_NATIVE_ENDIAN);
         }
         cpu_register_physical_memory(base, 8 << it_shift, s_io_memory);
     }
diff --git a/hw/sh7750.c b/hw/sh7750.c
index 0291d5f..9e54ad1 100644
--- a/hw/sh7750.c
+++ b/hw/sh7750.c
@@ -713,7 +713,8 @@ SH7750State *sh7750_init(CPUSH4State * cpu)
     s->cpu = cpu;
     s->periph_freq = 60000000;	/* 60MHz */
     sh7750_io_memory = cpu_register_io_memory(sh7750_mem_read,
-					      sh7750_mem_write, s);
+					      sh7750_mem_write, s,
+                                              DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory_offset(0x1f000000, 0x1000,
                                         sh7750_io_memory, 0x1f000000);
     cpu_register_physical_memory_offset(0xff000000, 0x1000,
@@ -728,7 +729,8 @@ SH7750State *sh7750_init(CPUSH4State * cpu)
                                         sh7750_io_memory, 0x1fc00000);
 
     sh7750_mm_cache_and_tlb = cpu_register_io_memory(sh7750_mmct_read,
-						     sh7750_mmct_write, s);
+						     sh7750_mmct_write, s,
+                                                     DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(0xf0000000, 0x08000000,
 				 sh7750_mm_cache_and_tlb);
 
diff --git a/hw/sh_intc.c b/hw/sh_intc.c
index d3f5ea5..0734da9 100644
--- a/hw/sh_intc.c
+++ b/hw/sh_intc.c
@@ -442,7 +442,8 @@ int sh_intc_init(struct intc_desc *desc,
     desc->irqs = qemu_allocate_irqs(sh_intc_set_irq, desc, nr_sources);
  
     desc->iomemtype = cpu_register_io_memory(sh_intc_readfn,
-					     sh_intc_writefn, desc);
+					     sh_intc_writefn, desc,
+                                             DEVICE_NATIVE_ENDIAN);
     if (desc->mask_regs) {
         for (i = 0; i < desc->nr_mask_regs; i++) {
 	    struct intc_mask_reg *mr = desc->mask_regs + i;
diff --git a/hw/sh_pci.c b/hw/sh_pci.c
index cc2f190..6042d9c 100644
--- a/hw/sh_pci.c
+++ b/hw/sh_pci.c
@@ -103,7 +103,8 @@ PCIBus *sh_pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
 
     p->dev = pci_register_device(p->bus, "SH PCIC", sizeof(PCIDevice),
                                  -1, NULL, NULL);
-    reg = cpu_register_io_memory(sh_pci_reg.r, sh_pci_reg.w, p);
+    reg = cpu_register_io_memory(sh_pci_reg.r, sh_pci_reg.w, p,
+                                 DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(0x1e200000, 0x224, reg);
     cpu_register_physical_memory(0xfe200000, 0x224, reg);
 
diff --git a/hw/sh_serial.c b/hw/sh_serial.c
index 93dc144..1bdc0a5 100644
--- a/hw/sh_serial.c
+++ b/hw/sh_serial.c
@@ -395,7 +395,8 @@ void sh_serial_init (target_phys_addr_t base, int feat,
     sh_serial_clear_fifo(s);
 
     s_io_memory = cpu_register_io_memory(sh_serial_readfn,
-					 sh_serial_writefn, s);
+					 sh_serial_writefn, s,
+                                         DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(P4ADDR(base), 0x28, s_io_memory);
     cpu_register_physical_memory(A7ADDR(base), 0x28, s_io_memory);
 
diff --git a/hw/sh_timer.c b/hw/sh_timer.c
index fd2146a..5eec6b7 100644
--- a/hw/sh_timer.c
+++ b/hw/sh_timer.c
@@ -319,7 +319,8 @@ void tmu012_init(target_phys_addr_t base, int feat, uint32_t freq,
         s->timer[2] = sh_timer_init(freq, timer_feat | TIMER_FEAT_CAPT,
 				    ch2_irq0); /* ch2_irq1 not supported */
     iomemtype = cpu_register_io_memory(tmu012_readfn,
-                                       tmu012_writefn, s);
+                                       tmu012_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(P4ADDR(base), 0x00001000, iomemtype);
     cpu_register_physical_memory(A7ADDR(base), 0x00001000, iomemtype);
     /* ??? Save/restore.  */
diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c
index 9d5ad86..fd69354 100644
--- a/hw/slavio_intctl.c
+++ b/hw/slavio_intctl.c
@@ -422,7 +422,8 @@ static int slavio_intctl_init1(SysBusDevice *dev)
 
     qdev_init_gpio_in(&dev->qdev, slavio_set_irq_all, 32 + MAX_CPUS);
     io_memory = cpu_register_io_memory(slavio_intctlm_mem_read,
-                                       slavio_intctlm_mem_write, s);
+                                       slavio_intctlm_mem_write, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, INTCTLM_SIZE, io_memory);
 
     for (i = 0; i < MAX_CPUS; i++) {
@@ -431,7 +432,8 @@ static int slavio_intctl_init1(SysBusDevice *dev)
         }
         io_memory = cpu_register_io_memory(slavio_intctl_mem_read,
                                            slavio_intctl_mem_write,
-                                           &s->slaves[i]);
+                                           &s->slaves[i],
+                                           DEVICE_NATIVE_ENDIAN);
         sysbus_init_mmio(dev, INTCTL_SIZE, io_memory);
         s->slaves[i].cpu = i;
         s->slaves[i].master = s;
diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c
index 1d81a63..198360d 100644
--- a/hw/slavio_misc.c
+++ b/hw/slavio_misc.c
@@ -412,7 +412,8 @@ static int apc_init1(SysBusDevice *dev)
     sysbus_init_irq(dev, &s->cpu_halt);
 
     /* Power management (APC) XXX: not a Slavio device */
-    io = cpu_register_io_memory(apc_mem_read, apc_mem_write, s);
+    io = cpu_register_io_memory(apc_mem_read, apc_mem_write, s,
+                                DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, MISC_SIZE, io);
     return 0;
 }
@@ -428,39 +429,46 @@ static int slavio_misc_init1(SysBusDevice *dev)
     /* 8 bit registers */
     /* Slavio control */
     io = cpu_register_io_memory(slavio_cfg_mem_read,
-                                slavio_cfg_mem_write, s);
+                                slavio_cfg_mem_write, s,
+                                DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, MISC_SIZE, io);
 
     /* Diagnostics */
     io = cpu_register_io_memory(slavio_diag_mem_read,
-                                slavio_diag_mem_write, s);
+                                slavio_diag_mem_write, s,
+                                DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, MISC_SIZE, io);
 
     /* Modem control */
     io = cpu_register_io_memory(slavio_mdm_mem_read,
-                                slavio_mdm_mem_write, s);
+                                slavio_mdm_mem_write, s,
+                                DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, MISC_SIZE, io);
 
     /* 16 bit registers */
     /* ss600mp diag LEDs */
     io = cpu_register_io_memory(slavio_led_mem_read,
-                                slavio_led_mem_write, s);
+                                slavio_led_mem_write, s,
+                                DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, MISC_SIZE, io);
 
     /* 32 bit registers */
     /* System control */
     io = cpu_register_io_memory(slavio_sysctrl_mem_read,
-                                slavio_sysctrl_mem_write, s);
+                                slavio_sysctrl_mem_write, s,
+                                DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, SYSCTRL_SIZE, io);
 
     /* AUX 1 (Misc System Functions) */
     io = cpu_register_io_memory(slavio_aux1_mem_read,
-                                slavio_aux1_mem_write, s);
+                                slavio_aux1_mem_write, s,
+                                DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, MISC_SIZE, io);
 
     /* AUX 2 (Software Powerdown Control) */
     io = cpu_register_io_memory(slavio_aux2_mem_read,
-                                slavio_aux2_mem_write, s);
+                                slavio_aux2_mem_write, s,
+                                DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, MISC_SIZE, io);
 
     qdev_init_gpio_in(&dev->qdev, slavio_set_power_fail, 1);
diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c
index 13f1e62..5511313 100644
--- a/hw/slavio_timer.c
+++ b/hw/slavio_timer.c
@@ -390,7 +390,8 @@ static int slavio_timer_init1(SysBusDevice *dev)
         ptimer_set_period(s->cputimer[i].timer, TIMER_PERIOD);
 
         io = cpu_register_io_memory(slavio_timer_mem_read,
-                                    slavio_timer_mem_write, tc);
+                                    slavio_timer_mem_write, tc,
+                                    DEVICE_NATIVE_ENDIAN);
         if (i == 0) {
             sysbus_init_mmio(dev, SYS_TIMER_SIZE, io);
         } else {
diff --git a/hw/sm501.c b/hw/sm501.c
index 705e0a5..f16e6e4 100644
--- a/hw/sm501.c
+++ b/hw/sm501.c
@@ -1379,15 +1379,18 @@ void sm501_init(uint32_t base, uint32_t local_mem_bytes, qemu_irq irq,
     /* map mmio */
     sm501_system_config_index
 	= cpu_register_io_memory(sm501_system_config_readfn,
-				 sm501_system_config_writefn, s);
+				 sm501_system_config_writefn, s,
+                                 DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base + MMIO_BASE_OFFSET,
 				 0x6c, sm501_system_config_index);
     sm501_disp_ctrl_index = cpu_register_io_memory(sm501_disp_ctrl_readfn,
-						   sm501_disp_ctrl_writefn, s);
+						   sm501_disp_ctrl_writefn, s,
+                                                   DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base + MMIO_BASE_OFFSET + SM501_DC,
                                  0x1000, sm501_disp_ctrl_index);
     sm501_2d_engine_index = cpu_register_io_memory(sm501_2d_engine_readfn,
-                                                   sm501_2d_engine_writefn, s);
+                                                   sm501_2d_engine_writefn, s,
+                                                   DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base + MMIO_BASE_OFFSET + SM501_2D_ENGINE,
                                  0x54, sm501_2d_engine_index);
 
diff --git a/hw/smc91c111.c b/hw/smc91c111.c
index f7d58e1..fc714d7 100644
--- a/hw/smc91c111.c
+++ b/hw/smc91c111.c
@@ -719,7 +719,8 @@ static int smc91c111_init1(SysBusDevice *dev)
     smc91c111_state *s = FROM_SYSBUS(smc91c111_state, dev);
 
     s->mmio_index = cpu_register_io_memory(smc91c111_readfn,
-                                           smc91c111_writefn, s);
+                                           smc91c111_writefn, s,
+                                           DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 16, s->mmio_index);
     sysbus_init_irq(dev, &s->irq);
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c
index 0904188..e78f025 100644
--- a/hw/sparc32_dma.c
+++ b/hw/sparc32_dma.c
@@ -257,7 +257,8 @@ static int sparc32_dma_init1(SysBusDevice *dev)
 
     sysbus_init_irq(dev, &s->irq);
 
-    dma_io_memory = cpu_register_io_memory(dma_mem_read, dma_mem_write, s);
+    dma_io_memory = cpu_register_io_memory(dma_mem_read, dma_mem_write, s,
+                                           DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, DMA_SIZE, dma_io_memory);
 
     qdev_init_gpio_in(&dev->qdev, dma_set_irq, 1);
diff --git a/hw/spitz.c b/hw/spitz.c
index a064460..092bb64 100644
--- a/hw/spitz.c
+++ b/hw/spitz.c
@@ -176,7 +176,7 @@ static void sl_flash_register(PXA2xxState *cpu, int size)
         s->nand = nand_init(NAND_MFR_SAMSUNG, 0xf1);
 
     iomemtype = cpu_register_io_memory(sl_readfn,
-                    sl_writefn, s);
+                    sl_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(FLASH_BASE, 0x40, iomemtype);
 
     register_savevm(NULL, "sl_flash", 0, 0, sl_save, sl_load, s);
diff --git a/hw/stellaris.c b/hw/stellaris.c
index ccad134..b903273 100644
--- a/hw/stellaris.c
+++ b/hw/stellaris.c
@@ -348,7 +348,8 @@ static int stellaris_gptm_init(SysBusDevice *dev)
     qdev_init_gpio_out(&dev->qdev, &s->trigger, 1);
 
     iomemtype = cpu_register_io_memory(gptm_readfn,
-                                       gptm_writefn, s);
+                                       gptm_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, iomemtype);
 
     s->opaque[0] = s->opaque[1] = s;
@@ -671,7 +672,8 @@ static int stellaris_sys_init(uint32_t base, qemu_irq irq,
     s->user1 = macaddr[3] | (macaddr[4] << 8) | (macaddr[5] << 16);
 
     iomemtype = cpu_register_io_memory(ssys_readfn,
-                                       ssys_writefn, s);
+                                       ssys_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x00001000, iomemtype);
     ssys_reset(s);
     register_savevm(NULL, "stellaris_sys", -1, 1, ssys_save, ssys_load, s);
@@ -884,7 +886,8 @@ static int stellaris_i2c_init(SysBusDevice * dev)
     s->bus = bus;
 
     iomemtype = cpu_register_io_memory(stellaris_i2c_readfn,
-                                       stellaris_i2c_writefn, s);
+                                       stellaris_i2c_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, iomemtype);
     /* ??? For now we only implement the master interface.  */
     stellaris_i2c_reset(s);
@@ -1193,7 +1196,8 @@ static int stellaris_adc_init(SysBusDevice *dev)
     }
 
     iomemtype = cpu_register_io_memory(stellaris_adc_readfn,
-                                       stellaris_adc_writefn, s);
+                                       stellaris_adc_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, iomemtype);
     stellaris_adc_reset(s);
     qdev_init_gpio_in(&dev->qdev, stellaris_adc_trigger, 1);
diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c
index 330a9d6..6a0583a 100644
--- a/hw/stellaris_enet.c
+++ b/hw/stellaris_enet.c
@@ -409,7 +409,8 @@ static int stellaris_enet_init(SysBusDevice *dev)
     stellaris_enet_state *s = FROM_SYSBUS(stellaris_enet_state, dev);
 
     s->mmio_index = cpu_register_io_memory(stellaris_enet_readfn,
-                                           stellaris_enet_writefn, s);
+                                           stellaris_enet_writefn, s,
+                                           DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, s->mmio_index);
     sysbus_init_irq(dev, &s->irq);
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
diff --git a/hw/sun4c_intctl.c b/hw/sun4c_intctl.c
index 7d7542d..5c7fdef 100644
--- a/hw/sun4c_intctl.c
+++ b/hw/sun4c_intctl.c
@@ -196,7 +196,8 @@ static int sun4c_intctl_init1(SysBusDevice *dev)
     unsigned int i;
 
     io_memory = cpu_register_io_memory(sun4c_intctl_mem_read,
-                                       sun4c_intctl_mem_write, s);
+                                       sun4c_intctl_mem_write, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, INTCTL_SIZE, io_memory);
     qdev_init_gpio_in(&dev->qdev, sun4c_set_irq, 8);
 
diff --git a/hw/sun4m_iommu.c b/hw/sun4m_iommu.c
index 720ee3f..bba69ee 100644
--- a/hw/sun4m_iommu.c
+++ b/hw/sun4m_iommu.c
@@ -351,7 +351,8 @@ static int iommu_init1(SysBusDevice *dev)
 
     sysbus_init_irq(dev, &s->irq);
 
-    io = cpu_register_io_memory(iommu_mem_read, iommu_mem_write, s);
+    io = cpu_register_io_memory(iommu_mem_read, iommu_mem_write, s,
+                                DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, IOMMU_NREGS * sizeof(uint32_t), io);
 
     return 0;
diff --git a/hw/syborg_fb.c b/hw/syborg_fb.c
index ed57203..7e37364 100644
--- a/hw/syborg_fb.c
+++ b/hw/syborg_fb.c
@@ -510,7 +510,8 @@ static int syborg_fb_init(SysBusDevice *dev)
 
     sysbus_init_irq(dev, &s->irq);
     iomemtype = cpu_register_io_memory(syborg_fb_readfn,
-                                       syborg_fb_writefn, s);
+                                       syborg_fb_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, iomemtype);
 
     s->ds = graphic_console_init(syborg_fb_update_display,
diff --git a/hw/syborg_interrupt.c b/hw/syborg_interrupt.c
index 30140fb..5217983 100644
--- a/hw/syborg_interrupt.c
+++ b/hw/syborg_interrupt.c
@@ -210,7 +210,8 @@ static int syborg_int_init(SysBusDevice *dev)
     sysbus_init_irq(dev, &s->parent_irq);
     qdev_init_gpio_in(&dev->qdev, syborg_int_set_irq, s->num_irqs);
     iomemtype = cpu_register_io_memory(syborg_int_readfn,
-                                       syborg_int_writefn, s);
+                                       syborg_int_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, iomemtype);
     s->flags = qemu_mallocz(s->num_irqs * sizeof(syborg_int_flags));
 
diff --git a/hw/syborg_keyboard.c b/hw/syborg_keyboard.c
index 7709100..d295e99 100644
--- a/hw/syborg_keyboard.c
+++ b/hw/syborg_keyboard.c
@@ -210,7 +210,8 @@ static int syborg_keyboard_init(SysBusDevice *dev)
 
     sysbus_init_irq(dev, &s->irq);
     iomemtype = cpu_register_io_memory(syborg_keyboard_readfn,
-                                       syborg_keyboard_writefn, s);
+                                       syborg_keyboard_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, iomemtype);
     if (s->fifo_size <= 0) {
         fprintf(stderr, "syborg_keyboard: fifo too small\n");
diff --git a/hw/syborg_pointer.c b/hw/syborg_pointer.c
index 69b8d96..a886888 100644
--- a/hw/syborg_pointer.c
+++ b/hw/syborg_pointer.c
@@ -206,7 +206,8 @@ static int syborg_pointer_init(SysBusDevice *dev)
 
     sysbus_init_irq(dev, &s->irq);
     iomemtype = cpu_register_io_memory(syborg_pointer_readfn,
-				       syborg_pointer_writefn, s);
+				       syborg_pointer_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, iomemtype);
 
     if (s->fifo_size <= 0) {
diff --git a/hw/syborg_rtc.c b/hw/syborg_rtc.c
index 78d5edb..329aa42 100644
--- a/hw/syborg_rtc.c
+++ b/hw/syborg_rtc.c
@@ -130,7 +130,8 @@ static int syborg_rtc_init(SysBusDevice *dev)
     int iomemtype;
 
     iomemtype = cpu_register_io_memory(syborg_rtc_readfn,
-                                       syborg_rtc_writefn, s);
+                                       syborg_rtc_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, iomemtype);
 
     qemu_get_timedate(&tm, 0);
diff --git a/hw/syborg_serial.c b/hw/syborg_serial.c
index 8c42956..34ce076 100644
--- a/hw/syborg_serial.c
+++ b/hw/syborg_serial.c
@@ -322,7 +322,8 @@ static int syborg_serial_init(SysBusDevice *dev)
 
     sysbus_init_irq(dev, &s->irq);
     iomemtype = cpu_register_io_memory(syborg_serial_readfn,
-                                       syborg_serial_writefn, s);
+                                       syborg_serial_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, iomemtype);
     s->chr = qdev_init_chardev(&dev->qdev);
     if (s->chr) {
diff --git a/hw/syborg_timer.c b/hw/syborg_timer.c
index 95e07d7..cedcd8e 100644
--- a/hw/syborg_timer.c
+++ b/hw/syborg_timer.c
@@ -215,7 +215,8 @@ static int syborg_timer_init(SysBusDevice *dev)
     }
     sysbus_init_irq(dev, &s->irq);
     iomemtype = cpu_register_io_memory(syborg_timer_readfn,
-                                       syborg_timer_writefn, s);
+                                       syborg_timer_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, iomemtype);
 
     bh = qemu_bh_new(syborg_timer_tick, s);
diff --git a/hw/syborg_virtio.c b/hw/syborg_virtio.c
index 4dfd1a8..ee08c49 100644
--- a/hw/syborg_virtio.c
+++ b/hw/syborg_virtio.c
@@ -265,7 +265,8 @@ static int syborg_virtio_init(SyborgVirtIOProxy *proxy, VirtIODevice *vdev)
     proxy->vdev->nvectors = 0;
     sysbus_init_irq(&proxy->busdev, &proxy->irq);
     iomemtype = cpu_register_io_memory(syborg_virtio_readfn,
-                                       syborg_virtio_writefn, proxy);
+                                       syborg_virtio_writefn, proxy,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(&proxy->busdev, 0x1000, iomemtype);
 
     proxy->id = ((uint32_t)0x1af4 << 16) | vdev->device_id;
diff --git a/hw/tc6393xb.c b/hw/tc6393xb.c
index 16db51d..c3fbe4e 100644
--- a/hw/tc6393xb.c
+++ b/hw/tc6393xb.c
@@ -590,7 +590,7 @@ TC6393xbState *tc6393xb_init(uint32_t base, qemu_irq irq)
     s->flash = nand_init(NAND_MFR_TOSHIBA, 0x76);
 
     iomemtype = cpu_register_io_memory(tc6393xb_readfn,
-                    tc6393xb_writefn, s);
+                    tc6393xb_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(base, 0x10000, iomemtype);
 
     s->vram_addr = qemu_ram_alloc(NULL, "tc6393xb.vram", 0x100000);
diff --git a/hw/tcx.c b/hw/tcx.c
index 6ee65bb..0e32830 100644
--- a/hw/tcx.c
+++ b/hw/tcx.c
@@ -522,12 +522,13 @@ static int tcx_init1(SysBusDevice *dev)
     vram_base += size;
 
     /* DAC */
-    io_memory = cpu_register_io_memory(tcx_dac_read, tcx_dac_write, s);
+    io_memory = cpu_register_io_memory(tcx_dac_read, tcx_dac_write, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, TCX_DAC_NREGS, io_memory);
 
     /* TEC (dummy) */
     dummy_memory = cpu_register_io_memory(tcx_dummy_read, tcx_dummy_write,
-                                          s);
+                                          s, DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, TCX_TEC_NREGS, dummy_memory);
     /* THC: NetBSD writes here even with 8-bit display: dummy */
     sysbus_init_mmio(dev, TCX_THC_NREGS_24, dummy_memory);
diff --git a/hw/tusb6010.c b/hw/tusb6010.c
index 4864be5..0005e1c 100644
--- a/hw/tusb6010.c
+++ b/hw/tusb6010.c
@@ -740,7 +740,7 @@ TUSBState *tusb6010_init(qemu_irq intr)
     s->intr = 0x00000000;
     s->otg_timer_val = 0;
     s->iomemtype[1] = cpu_register_io_memory(tusb_async_readfn,
-                    tusb_async_writefn, s);
+                    tusb_async_writefn, s, DEVICE_NATIVE_ENDIAN);
     s->irq = intr;
     s->otg_timer = qemu_new_timer(vm_clock, tusb_otg_tick, s);
     s->pwr_timer = qemu_new_timer(vm_clock, tusb_power_tick, s);
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index 8fb2f83..ba1ebbc 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -1697,7 +1697,8 @@ static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
                 usb_frame_time, usb_bit_time);
     }
 
-    ohci->mem = cpu_register_io_memory(ohci_readfn, ohci_writefn, ohci);
+    ohci->mem = cpu_register_io_memory(ohci_readfn, ohci_writefn, ohci,
+                                       DEVICE_NATIVE_ENDIAN);
     ohci->localmem_base = localmem_base;
 
     ohci->name = dev->info->name;
diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c
index a76bdfa..3baad96 100644
--- a/hw/versatile_pci.c
+++ b/hw/versatile_pci.c
@@ -132,7 +132,8 @@ static int pci_vpb_init(SysBusDevice *dev)
     /* ??? Register memory space.  */
 
     s->mem_config = cpu_register_io_memory(pci_vpb_config_read,
-                                           pci_vpb_config_write, bus);
+                                           pci_vpb_config_write, bus,
+                                           DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio_cb(dev, 0x04000000, pci_vpb_map);
 
     pci_create_simple(bus, -1, "versatile_pci_host");
diff --git a/hw/versatilepb.c b/hw/versatilepb.c
index c51ee02..be758e4 100644
--- a/hw/versatilepb.c
+++ b/hw/versatilepb.c
@@ -143,7 +143,8 @@ static int vpb_sic_init(SysBusDevice *dev)
     }
     s->irq = 31;
     iomemtype = cpu_register_io_memory(vpb_sic_readfn,
-                                       vpb_sic_writefn, s);
+                                       vpb_sic_writefn, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, 0x1000, iomemtype);
     /* ??? Save/restore.  */
     return 0;
diff --git a/hw/vga-isa-mm.c b/hw/vga-isa-mm.c
index 680b557..4954bb1 100644
--- a/hw/vga-isa-mm.c
+++ b/hw/vga-isa-mm.c
@@ -97,8 +97,10 @@ static void vga_mm_init(ISAVGAMMState *s, target_phys_addr_t vram_base,
     int 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);
-    vga_io_memory = cpu_register_io_memory(vga_mem_read, vga_mem_write, s);
+    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);
 
     vmstate_register(NULL, 0, &vmstate_vga_common, s);
 
diff --git a/hw/vga.c b/hw/vga.c
index c057f4f..b5c8741 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -2320,7 +2320,8 @@ void vga_init(VGACommonState *s)
 #endif
 #endif /* CONFIG_BOCHS_VBE */
 
-    vga_io_memory = cpu_register_io_memory(vga_mem_read, vga_mem_write, s);
+    vga_io_memory = cpu_register_io_memory(vga_mem_read, vga_mem_write, s,
+                                           DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
                                  vga_io_memory);
     qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000);
diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
index d0f4e1b..d9dd52f 100644
--- a/hw/vmware_vga.c
+++ b/hw/vmware_vga.c
@@ -1250,7 +1250,7 @@ static void pci_vmsvga_map_mem(PCIDevice *pci_dev, int region_num,
     s->vram_base = addr;
 #ifdef DIRECT_VRAM
     iomemtype = cpu_register_io_memory(vmsvga_vram_read,
-                    vmsvga_vram_write, s);
+                    vmsvga_vram_write, s, DEVICE_NATIVE_ENDIAN);
 #else
     iomemtype = s->vga.vram_offset | IO_MEM_RAM;
 #endif
diff --git a/hw/wdt_i6300esb.c b/hw/wdt_i6300esb.c
index 46e1df8..09f2f58 100644
--- a/hw/wdt_i6300esb.c
+++ b/hw/wdt_i6300esb.c
@@ -361,7 +361,8 @@ static void i6300esb_map(PCIDevice *dev, int region_num,
     i6300esb_debug("addr = %"FMT_PCIBUS", size = %"FMT_PCIBUS", type = %d\n",
                    addr, size, type);
 
-    io_mem = cpu_register_io_memory(mem_read, mem_write, d);
+    io_mem = cpu_register_io_memory(mem_read, mem_write, d,
+                                    DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory (addr, 0x10, io_mem);
     /* qemu_register_coalesced_mmio (addr, 0x10); ? */
 }
diff --git a/hw/xilinx_ethlite.c b/hw/xilinx_ethlite.c
index 37e33ec..54b57d7 100644
--- a/hw/xilinx_ethlite.c
+++ b/hw/xilinx_ethlite.c
@@ -224,7 +224,7 @@ static int xilinx_ethlite_init(SysBusDevice *dev)
     sysbus_init_irq(dev, &s->irq);
     s->rxbuf = 0;
 
-    regs = cpu_register_io_memory(eth_read, eth_write, s);
+    regs = cpu_register_io_memory(eth_read, eth_write, s, DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, R_MAX * 4, regs);
 
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
diff --git a/hw/xilinx_intc.c b/hw/xilinx_intc.c
index 8ef6474..cb72d5a 100644
--- a/hw/xilinx_intc.c
+++ b/hw/xilinx_intc.c
@@ -153,7 +153,7 @@ static int xilinx_intc_init(SysBusDevice *dev)
     qdev_init_gpio_in(&dev->qdev, irq_handler, 32);
     sysbus_init_irq(dev, &p->parent_irq);
 
-    pic_regs = cpu_register_io_memory(pic_read, pic_write, p);
+    pic_regs = cpu_register_io_memory(pic_read, pic_write, p, DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, R_MAX * 4, pic_regs);
     return 0;
 }
diff --git a/hw/xilinx_timer.c b/hw/xilinx_timer.c
index e2d9541..30827b0 100644
--- a/hw/xilinx_timer.c
+++ b/hw/xilinx_timer.c
@@ -210,7 +210,8 @@ static int xilinx_timer_init(SysBusDevice *dev)
         ptimer_set_freq(xt->ptimer, t->freq_hz);
     }
 
-    timer_regs = cpu_register_io_memory(timer_read, timer_write, t);
+    timer_regs = cpu_register_io_memory(timer_read, timer_write, t,
+                                        DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, R_MAX * 4 * t->nr_timers, timer_regs);
     return 0;
 }
diff --git a/hw/xilinx_uartlite.c b/hw/xilinx_uartlite.c
index adab759..9b94e98 100644
--- a/hw/xilinx_uartlite.c
+++ b/hw/xilinx_uartlite.c
@@ -201,7 +201,8 @@ static int xilinx_uartlite_init(SysBusDevice *dev)
     sysbus_init_irq(dev, &s->irq);
 
     uart_update_status(s);
-    uart_regs = cpu_register_io_memory(uart_read, uart_write, s);
+    uart_regs = cpu_register_io_memory(uart_read, uart_write, s,
+                                       DEVICE_NATIVE_ENDIAN);
     sysbus_init_mmio(dev, R_MAX * 4, uart_regs);
 
     s->chr = qdev_init_chardev(&dev->qdev);
diff --git a/hw/zaurus.c b/hw/zaurus.c
index dd999d7..54ec3f0 100644
--- a/hw/zaurus.c
+++ b/hw/zaurus.c
@@ -228,7 +228,7 @@ ScoopInfo *scoop_init(PXA2xxState *cpu,
     s->status = 0x02;
     s->in = qemu_allocate_irqs(scoop_gpio_set, s, 16);
     iomemtype = cpu_register_io_memory(scoop_readfn,
-                    scoop_writefn, s);
+                    scoop_writefn, s, DEVICE_NATIVE_ENDIAN);
     cpu_register_physical_memory(target_base, 0x1000, iomemtype);
     register_savevm(NULL, "scoop", instance, 1, scoop_save, scoop_load, s);
 
diff --git a/rwhandler.c b/rwhandler.c
index 1f9b6db..88dfcc5 100644
--- a/rwhandler.c
+++ b/rwhandler.c
@@ -42,7 +42,7 @@ int cpu_register_io_memory_simple(struct ReadWriteHandler *handler)
     }
     return cpu_register_io_memory(cpu_io_memory_simple_read,
                                   cpu_io_memory_simple_write,
-                                  handler);
+                                  handler, DEVICE_NATIVE_ENDIAN);
 }
 
 RWHANDLER_WRITE(ioport_simple_writeb, 1, uint32_t);
commit dd310534e3bf8045096654df41471fd7132887b2
Author: Alexander Graf <agraf at suse.de>
Date:   Wed Dec 8 12:05:36 2010 +0100

    exec: introduce endianness swapped mmio
    
    The way we're currently modeling mmio is too simplified. We assume that
    every device has the same endianness as the target CPU. In reality,
    most devices are little endian (all PCI and ISA ones I'm aware of). Some
    are big endian (special system devices) and a very little fraction is
    target native endian (fw_cfg).
    
    So instead of assuming every device to be native endianness, let's move
    to a model where the device tells us which endianness it's in.
    
    That way we can compile the devices only once and get rid of all the ugly
    swap will be done by the underlying layer.
    
    For the same of readability, this patch only introduces the helper framework
    but doesn't allow the registering code to set its endianness yet.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/cpu-common.h b/cpu-common.h
index bb6b137..6d4a898 100644
--- a/cpu-common.h
+++ b/cpu-common.h
@@ -20,6 +20,12 @@
 
 #if !defined(CONFIG_USER_ONLY)
 
+enum device_endian {
+    DEVICE_NATIVE_ENDIAN,
+    DEVICE_BIG_ENDIAN,
+    DEVICE_LITTLE_ENDIAN,
+};
+
 /* address in the RAM (different from a physical address) */
 typedef unsigned long ram_addr_t;
 
@@ -55,7 +61,7 @@ ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr);
 
 int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read,
                            CPUWriteMemoryFunc * const *mem_write,
-                           void *opaque);
+                           void *opaque, enum device_endian endian);
 void cpu_unregister_io_memory(int table_address);
 
 void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
diff --git a/exec.c b/exec.c
index 42a35e0..af1e89d 100644
--- a/exec.c
+++ b/exec.c
@@ -3355,6 +3355,106 @@ static int get_free_io_mem_idx(void)
     return -1;
 }
 
+/*
+ * Usually, devices operate in little endian mode. There are devices out
+ * there that operate in big endian too. Each device gets byte swapped
+ * mmio if plugged onto a CPU that does the other endianness.
+ *
+ * CPU          Device           swap?
+ *
+ * little       little           no
+ * little       big              yes
+ * big          little           yes
+ * big          big              no
+ */
+
+typedef struct SwapEndianContainer {
+    CPUReadMemoryFunc *read[3];
+    CPUWriteMemoryFunc *write[3];
+    void *opaque;
+} SwapEndianContainer;
+
+static uint32_t swapendian_mem_readb (void *opaque, target_phys_addr_t addr)
+{
+    uint32_t val;
+    SwapEndianContainer *c = opaque;
+    val = c->read[0](c->opaque, addr);
+    return val;
+}
+
+static uint32_t swapendian_mem_readw(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t val;
+    SwapEndianContainer *c = opaque;
+    val = bswap16(c->read[1](c->opaque, addr));
+    return val;
+}
+
+static uint32_t swapendian_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t val;
+    SwapEndianContainer *c = opaque;
+    val = bswap32(c->read[2](c->opaque, addr));
+    return val;
+}
+
+static CPUReadMemoryFunc * const swapendian_readfn[3]={
+    swapendian_mem_readb,
+    swapendian_mem_readw,
+    swapendian_mem_readl
+};
+
+static void swapendian_mem_writeb(void *opaque, target_phys_addr_t addr,
+                                  uint32_t val)
+{
+    SwapEndianContainer *c = opaque;
+    c->write[0](c->opaque, addr, val);
+}
+
+static void swapendian_mem_writew(void *opaque, target_phys_addr_t addr,
+                                  uint32_t val)
+{
+    SwapEndianContainer *c = opaque;
+    c->write[1](c->opaque, addr, bswap16(val));
+}
+
+static void swapendian_mem_writel(void *opaque, target_phys_addr_t addr,
+                                  uint32_t val)
+{
+    SwapEndianContainer *c = opaque;
+    c->write[2](c->opaque, addr, bswap32(val));
+}
+
+static CPUWriteMemoryFunc * const swapendian_writefn[3]={
+    swapendian_mem_writeb,
+    swapendian_mem_writew,
+    swapendian_mem_writel
+};
+
+static void swapendian_init(int io_index)
+{
+    SwapEndianContainer *c = qemu_malloc(sizeof(SwapEndianContainer));
+    int i;
+
+    /* Swap mmio for big endian targets */
+    c->opaque = io_mem_opaque[io_index];
+    for (i = 0; i < 3; i++) {
+        c->read[i] = io_mem_read[io_index][i];
+        c->write[i] = io_mem_write[io_index][i];
+
+        io_mem_read[io_index][i] = swapendian_readfn[i];
+        io_mem_write[io_index][i] = swapendian_writefn[i];
+    }
+    io_mem_opaque[io_index] = c;
+}
+
+static void swapendian_del(int io_index)
+{
+    if (io_mem_read[io_index][0] == swapendian_readfn[0]) {
+        qemu_free(io_mem_opaque[io_index]);
+    }
+}
+
 /* mem_read and mem_write are arrays of functions containing the
    function to access byte (index 0), word (index 1) and dword (index
    2). Functions can be omitted with a NULL function pointer.
@@ -3365,9 +3465,10 @@ static int get_free_io_mem_idx(void)
 static int cpu_register_io_memory_fixed(int io_index,
                                         CPUReadMemoryFunc * const *mem_read,
                                         CPUWriteMemoryFunc * const *mem_write,
-                                        void *opaque)
+                                        void *opaque, enum device_endian endian)
 {
     int i;
+    int endian = DEVICE_NATIVE_ENDIAN;
 
     if (io_index <= 0) {
         io_index = get_free_io_mem_idx();
@@ -3389,12 +3490,28 @@ static int cpu_register_io_memory_fixed(int io_index,
     }
     io_mem_opaque[io_index] = opaque;
 
+    switch (endian) {
+    case DEVICE_BIG_ENDIAN:
+#ifndef TARGET_WORDS_BIGENDIAN
+        swapendian_init(io_index);
+#endif
+        break;
+    case DEVICE_LITTLE_ENDIAN:
+#ifdef TARGET_WORDS_BIGENDIAN
+        swapendian_init(io_index);
+#endif
+        break;
+    case DEVICE_NATIVE_ENDIAN:
+    default:
+        break;
+    }
+
     return (io_index << IO_MEM_SHIFT);
 }
 
 int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read,
                            CPUWriteMemoryFunc * const *mem_write,
-                           void *opaque)
+                           void *opaque, enum device_endian endian)
 {
     return cpu_register_io_memory_fixed(0, mem_read, mem_write, opaque);
 }
@@ -3404,6 +3521,8 @@ void cpu_unregister_io_memory(int io_table_address)
     int i;
     int io_index = io_table_address >> IO_MEM_SHIFT;
 
+    swapendian_del(io_index);
+
     for (i=0;i < 3; i++) {
         io_mem_read[io_index][i] = unassigned_mem_read[i];
         io_mem_write[io_index][i] = unassigned_mem_write[i];
commit 85882c71a946796c0ddc87dc84cc6fcb05b375c7
Author: Michael Walle <michael at walle.cc>
Date:   Thu Dec 9 00:34:51 2010 +0100

    noaudio: fix return value for read()
    
    Read should return bytes instead of samples.
    
    Signed-off-by: Michael Walle <michael at walle.cc>
    Signed-off-by: malc <av1474 at comtv.ru>

diff --git a/audio/noaudio.c b/audio/noaudio.c
index 4925234..8015858 100644
--- a/audio/noaudio.c
+++ b/audio/noaudio.c
@@ -121,7 +121,7 @@ static int no_read (SWVoiceIn *sw, void *buf, int size)
     int total = sw->hw->total_samples_captured - sw->total_hw_samples_acquired;
     int to_clear = audio_MIN (samples, total);
     audio_pcm_info_clear_buf (&sw->info, buf, to_clear);
-    return to_clear;
+    return to_clear << sw->info.shift;
 }
 
 static int no_ctl_in (HWVoiceIn *hw, int cmd, ...)
commit 7572150c189c6553c2448334116ab717680de66d
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Oct 7 12:22:54 2010 +0200

    vnc/spice: add set_passwd monitor command.
    
    This patch adds new set_password and expire_password monitor commands
    which allows to change and expire the password for spice and vnc
    connections.  See the doc update patch chunk for details.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 23024ba..f0ae3b9 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1135,6 +1135,60 @@ Set the encrypted device @var{device} password to @var{password}
 ETEXI
 
     {
+        .name       = "set_password",
+        .args_type  = "protocol:s,password:s,connected:s?",
+        .params     = "protocol password action-if-connected",
+        .help       = "set spice/vnc password",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = set_password,
+    },
+
+STEXI
+ at item set_password [ vnc | spice ] password [ action-if-connected ]
+ at findex set_password
+
+Change spice/vnc password.  Use zero to make the password stay valid
+forever.  @var{action-if-connected} specifies what should happen in
+case a connection is established: @var{fail} makes the password change
+fail.  @var{disconnect} changes the password and disconnects the
+client.  @var{keep} changes the password and keeps the connection up.
+ at var{keep} is the default.
+ETEXI
+
+    {
+        .name       = "expire_password",
+        .args_type  = "protocol:s,time:s",
+        .params     = "protocol time",
+        .help       = "set spice/vnc password expire-time",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = expire_password,
+    },
+
+STEXI
+ at item expire_password [ vnc | spice ] expire-time
+ at findex expire_password
+
+Specify when a password for spice/vnc becomes
+invalid. @var{expire-time} accepts:
+
+ at table @var
+ at item now
+Invalidate password instantly.
+
+ at item never
+Password stays valid forever.
+
+ at item +nsec
+Password stays valid for @var{nsec} seconds starting now.
+
+ at item nsec
+Password is invalidated at the given time.  @var{nsec} are the seconds
+passed since 1970, i.e. unix epoch.
+
+ at end table
+ETEXI
+
+    {
         .name       = "info",
         .args_type  = "item:s?",
         .params     = "[subcommand]",
diff --git a/monitor.c b/monitor.c
index 1047cee..b13a363 100644
--- a/monitor.c
+++ b/monitor.c
@@ -34,6 +34,7 @@
 #include "net.h"
 #include "net/slirp.h"
 #include "qemu-char.h"
+#include "ui/qemu-spice.h"
 #include "sysemu.h"
 #include "monitor.h"
 #include "readline.h"
@@ -1075,6 +1076,105 @@ static int do_change(Monitor *mon, const QDict *qdict, QObject **ret_data)
     return ret;
 }
 
+static int set_password(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    const char *protocol  = qdict_get_str(qdict, "protocol");
+    const char *password  = qdict_get_str(qdict, "password");
+    const char *connected = qdict_get_try_str(qdict, "connected");
+    int disconnect_if_connected = 0;
+    int fail_if_connected = 0;
+    int rc;
+
+    if (connected) {
+        if (strcmp(connected, "fail") == 0) {
+            fail_if_connected = 1;
+        } else if (strcmp(connected, "disconnect") == 0) {
+            disconnect_if_connected = 1;
+        } else if (strcmp(connected, "keep") == 0) {
+            /* nothing */
+        } else {
+            qerror_report(QERR_INVALID_PARAMETER, "connected");
+            return -1;
+        }
+    }
+
+    if (strcmp(protocol, "spice") == 0) {
+        if (!using_spice) {
+            /* correct one? spice isn't a device ,,, */
+            qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice");
+            return -1;
+        }
+        rc = qemu_spice_set_passwd(password, fail_if_connected,
+                                   disconnect_if_connected);
+        if (rc != 0) {
+            qerror_report(QERR_SET_PASSWD_FAILED);
+            return -1;
+        }
+        return 0;
+    }
+
+    if (strcmp(protocol, "vnc") == 0) {
+        if (fail_if_connected || disconnect_if_connected) {
+            /* vnc supports "connected=keep" only */
+            qerror_report(QERR_INVALID_PARAMETER, "connected");
+            return -1;
+        }
+        rc = vnc_display_password(NULL, password);
+        if (rc != 0) {
+            qerror_report(QERR_SET_PASSWD_FAILED);
+            return -1;
+        }
+        return 0;
+    }
+
+    qerror_report(QERR_INVALID_PARAMETER, "protocol");
+    return -1;
+}
+
+static int expire_password(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    const char *protocol  = qdict_get_str(qdict, "protocol");
+    const char *whenstr = qdict_get_str(qdict, "time");
+    time_t when;
+    int rc;
+
+    if (strcmp(whenstr, "now")) {
+        when = 0;
+    } else if (strcmp(whenstr, "never")) {
+        when = TIME_MAX;
+    } else if (whenstr[0] == '+') {
+        when = time(NULL) + strtoull(whenstr+1, NULL, 10);
+    } else {
+        when = strtoull(whenstr, NULL, 10);
+    }
+
+    if (strcmp(protocol, "spice") == 0) {
+        if (!using_spice) {
+            /* correct one? spice isn't a device ,,, */
+            qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice");
+            return -1;
+        }
+        rc = qemu_spice_set_pw_expire(when);
+        if (rc != 0) {
+            qerror_report(QERR_SET_PASSWD_FAILED);
+            return -1;
+        }
+        return 0;
+    }
+
+    if (strcmp(protocol, "vnc") == 0) {
+        rc = vnc_display_pw_expire(NULL, when);
+        if (rc != 0) {
+            qerror_report(QERR_SET_PASSWD_FAILED);
+            return -1;
+        }
+        return 0;
+    }
+
+    qerror_report(QERR_INVALID_PARAMETER, "protocol");
+    return -1;
+}
+
 static int do_screen_dump(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     vga_hw_screen_dump(qdict_get_str(qdict, "filename"));
diff --git a/qmp-commands.hx b/qmp-commands.hx
index b4e6017..1d71711 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -738,6 +738,63 @@ Example:
 EQMP
 
     {
+        .name       = "set_password",
+        .args_type  = "protocol:s,password:s,connected:s?",
+        .params     = "protocol password action-if-connected",
+        .help       = "set spice/vnc password",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = set_password,
+    },
+
+SQMP
+set_password
+------------
+
+Set the password for vnc/spice protocols.
+
+Arguments:
+
+- "protocol": protocol name (json-string)
+- "password": password (json-string)
+- "connected": [ keep | disconnect | fail ] (josn-string, optional)
+
+Example:
+
+-> { "execute": "set_password", "arguments": { "protocol": "vnc",
+                                               "password": "secret" } }
+<- { "return": {} }
+
+EQMP
+
+    {
+        .name       = "expire_password",
+        .args_type  = "protocol:s,time:s",
+        .params     = "protocol time",
+        .help       = "set spice/vnc password expire-time",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = expire_password,
+    },
+
+SQMP
+expire_password
+---------------
+
+Set the password expire time for vnc/spice protocols.
+
+Arguments:
+
+- "protocol": protocol name (json-string)
+- "time": [ now | never | +secs | secs ] (json-string)
+
+Example:
+
+-> { "execute": "expire_password", "arguments": { "protocol": "vnc",
+                                                  "time": "+60" } }
+<- { "return": {} }
+
+EQMP
+
+    {
         .name       = "qmp_capabilities",
         .args_type  = "",
         .params     = "",
diff --git a/ui/qemu-spice.h b/ui/qemu-spice.h
index 8b23ac9..48239c3 100644
--- a/ui/qemu-spice.h
+++ b/ui/qemu-spice.h
@@ -32,6 +32,9 @@ void qemu_spice_input_init(void);
 void qemu_spice_audio_init(void);
 void qemu_spice_display_init(DisplayState *ds);
 int qemu_spice_add_interface(SpiceBaseInstance *sin);
+int qemu_spice_set_passwd(const char *passwd,
+                          bool fail_if_connected, bool disconnect_if_connected);
+int qemu_spice_set_pw_expire(time_t expires);
 
 void do_info_spice_print(Monitor *mon, const QObject *data);
 void do_info_spice(Monitor *mon, QObject **ret_data);
@@ -39,6 +42,8 @@ void do_info_spice(Monitor *mon, QObject **ret_data);
 #else  /* CONFIG_SPICE */
 
 #define using_spice 0
+#define qemu_spice_set_passwd(_p, _f1, _f2) (-1)
+#define qemu_spice_set_pw_expire(_e) (-1)
 
 #endif /* CONFIG_SPICE */
 
diff --git a/ui/spice-core.c b/ui/spice-core.c
index d29d203..27a1ced 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -36,6 +36,8 @@
 
 static SpiceServer *spice_server;
 static const char *auth = "spice";
+static char *auth_passwd;
+static time_t auth_expires = TIME_MAX;
 int using_spice = 0;
 
 struct SpiceTimer {
@@ -599,6 +601,39 @@ int qemu_spice_add_interface(SpiceBaseInstance *sin)
     return spice_server_add_interface(spice_server, sin);
 }
 
+static int qemu_spice_set_ticket(bool fail_if_conn, bool disconnect_if_conn)
+{
+    time_t lifetime, now = time(NULL);
+    char *passwd;
+
+    if (now < auth_expires) {
+        passwd = auth_passwd;
+        lifetime = (auth_expires - now);
+        if (lifetime > INT_MAX) {
+            lifetime = INT_MAX;
+        }
+    } else {
+        passwd = NULL;
+        lifetime = 1;
+    }
+    return spice_server_set_ticket(spice_server, passwd, lifetime,
+                                   fail_if_conn, disconnect_if_conn);
+}
+
+int qemu_spice_set_passwd(const char *passwd,
+                          bool fail_if_conn, bool disconnect_if_conn)
+{
+    free(auth_passwd);
+    auth_passwd = strdup(passwd);
+    return qemu_spice_set_ticket(fail_if_conn, disconnect_if_conn);
+}
+
+int qemu_spice_set_pw_expire(time_t expires)
+{
+    auth_expires = expires;
+    return qemu_spice_set_ticket(false, false);
+}
+
 static void spice_register_config(void)
 {
     qemu_add_opts(&qemu_spice_opts);
commit 3c9405a0f7d76602415b3cbe8d52d7714b6ce5af
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Oct 7 11:50:45 2010 +0200

    vnc: support password expire
    
    This patch adds support for expiring passwords to vnc.  It adds a new
    vnc_display_pw_expire() function which specifies the time when the
    password will expire.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/console.h b/console.h
index aafb031..b2fc908 100644
--- a/console.h
+++ b/console.h
@@ -369,6 +369,7 @@ void vnc_display_init(DisplayState *ds);
 void vnc_display_close(DisplayState *ds);
 int vnc_display_open(DisplayState *ds, const char *display);
 int vnc_display_password(DisplayState *ds, const char *password);
+int vnc_display_pw_expire(DisplayState *ds, time_t expires);
 void do_info_vnc_print(Monitor *mon, const QObject *data);
 void do_info_vnc(Monitor *mon, QObject **ret_data);
 char *vnc_display_local_addr(DisplayState *ds);
diff --git a/qemu-common.h b/qemu-common.h
index de82c2e..188b05f 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -50,6 +50,9 @@ typedef struct DeviceState DeviceState;
 #if !defined(ENOTSUP)
 #define ENOTSUP 4096
 #endif
+#ifndef TIME_MAX
+#define TIME_MAX LONG_MAX
+#endif
 
 #ifndef CONFIG_IOVEC
 #define CONFIG_IOVEC
diff --git a/ui/vnc.c b/ui/vnc.c
index da70757..495d6d6 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -2082,11 +2082,16 @@ static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
     unsigned char response[VNC_AUTH_CHALLENGE_SIZE];
     int i, j, pwlen;
     unsigned char key[8];
+    time_t now = time(NULL);
 
     if (!vs->vd->password || !vs->vd->password[0]) {
         VNC_DEBUG("No password configured on server");
         goto reject;
     }
+    if (vs->vd->expires < now) {
+        VNC_DEBUG("Password is expired");
+        goto reject;
+    }
 
     memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE);
 
@@ -2432,6 +2437,7 @@ void vnc_display_init(DisplayState *ds)
 
     vs->ds = ds;
     QTAILQ_INIT(&vs->clients);
+    vs->expires = TIME_MAX;
 
     if (keyboard_layout)
         vs->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
@@ -2503,6 +2509,14 @@ int vnc_display_password(DisplayState *ds, const char *password)
     return 0;
 }
 
+int vnc_display_pw_expire(DisplayState *ds, time_t expires)
+{
+    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
+
+    vs->expires = expires;
+    return 0;
+}
+
 char *vnc_display_local_addr(DisplayState *ds)
 {
     VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
diff --git a/ui/vnc.h b/ui/vnc.h
index 9619b24..4f895be 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -120,6 +120,7 @@ struct VncDisplay
 
     char *display;
     char *password;
+    time_t expires;
     int auth;
     bool lossy;
 #ifdef CONFIG_VNC_TLS
commit 6bffdf0f83263bad1dd2187c533758d7cb6f5bcf
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Oct 7 11:50:24 2010 +0200

    vnc: auth reject cleanup
    
    protocol_client_auth_vnc() has two places where the auth can fail,
    with identical code sending the reject message to the client.
    Move the common code to the end of the function and make both
    error paths jump there.  No functional change.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/ui/vnc.c b/ui/vnc.c
index 864342e..da70757 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -2085,15 +2085,7 @@ static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
 
     if (!vs->vd->password || !vs->vd->password[0]) {
         VNC_DEBUG("No password configured on server");
-        vnc_write_u32(vs, 1); /* Reject auth */
-        if (vs->minor >= 8) {
-            static const char err[] = "Authentication failed";
-            vnc_write_u32(vs, sizeof(err));
-            vnc_write(vs, err, sizeof(err));
-        }
-        vnc_flush(vs);
-        vnc_client_error(vs);
-        return 0;
+        goto reject;
     }
 
     memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE);
@@ -2109,14 +2101,7 @@ static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
     /* Compare expected vs actual challenge response */
     if (memcmp(response, data, VNC_AUTH_CHALLENGE_SIZE) != 0) {
         VNC_DEBUG("Client challenge reponse did not match\n");
-        vnc_write_u32(vs, 1); /* Reject auth */
-        if (vs->minor >= 8) {
-            static const char err[] = "Authentication failed";
-            vnc_write_u32(vs, sizeof(err));
-            vnc_write(vs, err, sizeof(err));
-        }
-        vnc_flush(vs);
-        vnc_client_error(vs);
+        goto reject;
     } else {
         VNC_DEBUG("Accepting VNC challenge response\n");
         vnc_write_u32(vs, 0); /* Accept auth */
@@ -2125,6 +2110,17 @@ static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
         start_client_init(vs);
     }
     return 0;
+
+reject:
+    vnc_write_u32(vs, 1); /* Reject auth */
+    if (vs->minor >= 8) {
+        static const char err[] = "Authentication failed";
+        vnc_write_u32(vs, sizeof(err));
+        vnc_write(vs, err, sizeof(err));
+    }
+    vnc_flush(vs);
+    vnc_client_error(vs);
+    return 0;
 }
 
 void start_auth_vnc(VncState *vs)
commit cb42a870c3f5b38911b1428cb785dd702bc47d0f
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Nov 30 11:02:51 2010 +0100

    spice: add qmp 'query-spice' and hmp 'info spice' commands.
    
    The patch adds a 'query-spice' monitor command which returns
    informations about the spice server configuration and also a list of
    channel connections.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/monitor.c b/monitor.c
index f04dda5..1047cee 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2581,6 +2581,16 @@ static const mon_cmd_t info_cmds[] = {
         .user_print = do_info_vnc_print,
         .mhandler.info_new = do_info_vnc,
     },
+#if defined(CONFIG_SPICE)
+    {
+        .name       = "spice",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show the spice server status",
+        .user_print = do_info_spice_print,
+        .mhandler.info_new = do_info_spice,
+    },
+#endif
     {
         .name       = "name",
         .args_type  = "",
@@ -2768,6 +2778,16 @@ static const mon_cmd_t qmp_query_cmds[] = {
         .user_print = do_info_vnc_print,
         .mhandler.info_new = do_info_vnc,
     },
+#if defined(CONFIG_SPICE)
+    {
+        .name       = "spice",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show the spice server status",
+        .user_print = do_info_spice_print,
+        .mhandler.info_new = do_info_spice,
+    },
+#endif
     {
         .name       = "name",
         .args_type  = "",
diff --git a/qmp-commands.hx b/qmp-commands.hx
index e5f157f..b4e6017 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1439,6 +1439,76 @@ Example:
 EQMP
 
 SQMP
+query-spice
+-----------
+
+Show SPICE server information.
+
+Return a json-object with server information. Connected clients are returned
+as a json-array of json-objects.
+
+The main json-object contains the following:
+
+- "enabled": true or false (json-bool)
+- "host": server's IP address (json-string)
+- "port": server's port number (json-int, optional)
+- "tls-port": server's port number (json-int, optional)
+- "auth": authentication method (json-string)
+         - Possible values: "none", "spice"
+- "channels": a json-array of all active channels clients
+
+Channels are described by a json-object, each one contain the following:
+
+- "host": client's IP address (json-string)
+- "family": address family (json-string)
+         - Possible values: "ipv4", "ipv6", "unix", "unknown"
+- "port": client's port number (json-string)
+- "connection-id": spice connection id.  All channels with the same id
+                   belong to the same spice session (json-int)
+- "channel-type": channel type.  "1" is the main control channel, filter for
+                  this one if you want track spice sessions only (json-int)
+- "channel-id": channel id.  Usually "0", might be different needed when
+                multiple channels of the same type exist, such as multiple
+                display channels in a multihead setup (json-int)
+- "tls": whevener the channel is encrypted (json-bool)
+
+Example:
+
+-> { "execute": "query-spice" }
+<- {
+      "return": {
+         "enabled": true,
+         "auth": "spice",
+         "port": 5920,
+         "tls-port": 5921,
+         "host": "0.0.0.0",
+         "channels": [
+            {
+               "port": "54924",
+               "family": "ipv4",
+               "channel-type": 1,
+               "connection-id": 1804289383,
+               "host": "127.0.0.1",
+               "channel-id": 0,
+               "tls": true
+            },
+            {
+               "port": "36710",
+               "family": "ipv4",
+               "channel-type": 4,
+               "connection-id": 1804289383,
+               "host": "127.0.0.1",
+               "channel-id": 0,
+               "tls": false
+            },
+            [ ... more channels follow ... ]
+         ]
+      }
+   }
+
+EQMP
+
+SQMP
 query-name
 ----------
 
diff --git a/ui/qemu-spice.h b/ui/qemu-spice.h
index 0e3ad9b..8b23ac9 100644
--- a/ui/qemu-spice.h
+++ b/ui/qemu-spice.h
@@ -33,6 +33,9 @@ void qemu_spice_audio_init(void);
 void qemu_spice_display_init(DisplayState *ds);
 int qemu_spice_add_interface(SpiceBaseInstance *sin);
 
+void do_info_spice_print(Monitor *mon, const QObject *data);
+void do_info_spice(Monitor *mon, QObject **ret_data);
+
 #else  /* CONFIG_SPICE */
 
 #define using_spice 0
diff --git a/ui/spice-core.c b/ui/spice-core.c
index 93461c6..d29d203 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -131,6 +131,36 @@ static void watch_remove(SpiceWatch *watch)
 
 #if SPICE_INTERFACE_CORE_MINOR >= 3
 
+typedef struct ChannelList ChannelList;
+struct ChannelList {
+    SpiceChannelEventInfo *info;
+    QTAILQ_ENTRY(ChannelList) link;
+};
+static QTAILQ_HEAD(, ChannelList) channel_list = QTAILQ_HEAD_INITIALIZER(channel_list);
+
+static void channel_list_add(SpiceChannelEventInfo *info)
+{
+    ChannelList *item;
+
+    item = qemu_mallocz(sizeof(*item));
+    item->info = info;
+    QTAILQ_INSERT_TAIL(&channel_list, item, link);
+}
+
+static void channel_list_del(SpiceChannelEventInfo *info)
+{
+    ChannelList *item;
+
+    QTAILQ_FOREACH(item, &channel_list, link) {
+        if (item->info != info) {
+            continue;
+        }
+        QTAILQ_REMOVE(&channel_list, item, link);
+        qemu_free(item);
+        return;
+    }
+}
+
 static void add_addr_info(QDict *dict, struct sockaddr *addr, int len)
 {
     char host[NI_MAXHOST], port[NI_MAXSERV];
@@ -155,6 +185,22 @@ static void add_channel_info(QDict *dict, SpiceChannelEventInfo *info)
     qdict_put(dict, "tls", qbool_from_int(tls));
 }
 
+static QList *channel_list_get(void)
+{
+    ChannelList *item;
+    QList *list;
+    QDict *dict;
+
+    list = qlist_new();
+    QTAILQ_FOREACH(item, &channel_list, link) {
+        dict = qdict_new();
+        add_addr_info(dict, &item->info->paddr, item->info->plen);
+        add_channel_info(dict, item->info);
+        qlist_append(list, dict);
+    }
+    return list;
+}
+
 static void channel_event(int event, SpiceChannelEventInfo *info)
 {
     static const int qevent[] = {
@@ -174,6 +220,10 @@ static void channel_event(int event, SpiceChannelEventInfo *info)
     if (event == SPICE_CHANNEL_EVENT_INITIALIZED) {
         qdict_put(server, "auth", qstring_from_str(auth));
         add_channel_info(client, info);
+        channel_list_add(info);
+    }
+    if (event == SPICE_CHANNEL_EVENT_DISCONNECTED) {
+        channel_list_del(info);
     }
 
     data = qobject_from_jsonf("{ 'client': %p, 'server': %p }",
@@ -278,6 +328,92 @@ static const char *wan_compression_names[] = {
 
 /* functions for the rest of qemu */
 
+static void info_spice_iter(QObject *obj, void *opaque)
+{
+    QDict *client;
+    Monitor *mon = opaque;
+
+    client = qobject_to_qdict(obj);
+    monitor_printf(mon, "Channel:\n");
+    monitor_printf(mon, "     address: %s:%s%s\n",
+                   qdict_get_str(client, "host"),
+                   qdict_get_str(client, "port"),
+                   qdict_get_bool(client, "tls") ? " [tls]" : "");
+    monitor_printf(mon, "     session: %" PRId64 "\n",
+                   qdict_get_int(client, "connection-id"));
+    monitor_printf(mon, "     channel: %d:%d\n",
+                   (int)qdict_get_int(client, "channel-type"),
+                   (int)qdict_get_int(client, "channel-id"));
+}
+
+void do_info_spice_print(Monitor *mon, const QObject *data)
+{
+    QDict *server;
+    QList *channels;
+    const char *host;
+    int port;
+
+    server = qobject_to_qdict(data);
+    if (qdict_get_bool(server, "enabled") == 0) {
+        monitor_printf(mon, "Server: disabled\n");
+        return;
+    }
+
+    monitor_printf(mon, "Server:\n");
+    host = qdict_get_str(server, "host");
+    port = qdict_get_try_int(server, "port", -1);
+    if (port != -1) {
+        monitor_printf(mon, "     address: %s:%d\n", host, port);
+    }
+    port = qdict_get_try_int(server, "tls-port", -1);
+    if (port != -1) {
+        monitor_printf(mon, "     address: %s:%d [tls]\n", host, port);
+    }
+    monitor_printf(mon, "        auth: %s\n", qdict_get_str(server, "auth"));
+
+    channels = qdict_get_qlist(server, "channels");
+    if (qlist_empty(channels)) {
+        monitor_printf(mon, "Channels: none\n");
+    } else {
+        qlist_iter(channels, info_spice_iter, mon);
+    }
+}
+
+void do_info_spice(Monitor *mon, QObject **ret_data)
+{
+    QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head);
+    QDict *server;
+    QList *clist;
+    const char *addr;
+    int port, tls_port;
+
+    if (!spice_server) {
+        *ret_data = qobject_from_jsonf("{ 'enabled': false }");
+        return;
+    }
+
+    addr = qemu_opt_get(opts, "addr");
+    port = qemu_opt_get_number(opts, "port", 0);
+    tls_port = qemu_opt_get_number(opts, "tls-port", 0);
+    clist = channel_list_get();
+
+    server = qdict_new();
+    qdict_put(server, "enabled", qbool_from_int(true));
+    qdict_put(server, "auth", qstring_from_str(auth));
+    qdict_put(server, "host", qstring_from_str(addr ? addr : "0.0.0.0"));
+    if (port) {
+        qdict_put(server, "port", qint_from_int(port));
+    }
+    if (tls_port) {
+        qdict_put(server, "tls-port", qint_from_int(tls_port));
+    }
+    if (clist) {
+        qdict_put(server, "channels", clist);
+    }
+
+    *ret_data = QOBJECT(server);
+}
+
 static int add_channel(const char *name, const char *value, void *opaque)
 {
     int security = 0;
commit 6f8c63fbd7edc0b41c09f8f8e2d41a3a65464a43
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Mon Oct 11 18:03:51 2010 +0200

    spice: connection events.
    
    This patch adds support for connection events to spice.  The events are
    quite simliar to the vnc events.  Unlike vnc spice uses multiple tcp
    channels though.  qemu will report every single tcp connection (aka
    spice channel).  If you want track spice sessions only you can filter
    for the main channel (channel-type == 1).
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/QMP/qmp-events.txt b/QMP/qmp-events.txt
index aa20210..0ce5d4e 100644
--- a/QMP/qmp-events.txt
+++ b/QMP/qmp-events.txt
@@ -182,6 +182,70 @@ Example:
                     "host": "127.0.0.1", "sasl_username": "luiz" } },
         "timestamp": { "seconds": 1263475302, "microseconds": 150772 } }
 
+SPICE_CONNECTED, SPICE_DISCONNECTED
+-----------------------------------
+
+Emitted when a SPICE client connects or disconnects.
+
+Data:
+
+- "server": Server information (json-object)
+  - "host": IP address (json-string)
+  - "port": port number (json-string)
+  - "family": address family (json-string, "ipv4" or "ipv6")
+- "client": Client information (json-object)
+  - "host": IP address (json-string)
+  - "port": port number (json-string)
+  - "family": address family (json-string, "ipv4" or "ipv6")
+
+Example:
+
+{ "timestamp": {"seconds": 1290688046, "microseconds": 388707},
+  "event": "SPICE_CONNECTED",
+  "data": {
+    "server": { "port": "5920", "family": "ipv4", "host": "127.0.0.1"},
+    "client": {"port": "52873", "family": "ipv4", "host": "127.0.0.1"}
+}}
+
+
+SPICE_INITIALIZED
+-----------------
+
+Emitted after initial handshake and authentication takes place (if any)
+and the SPICE channel is up'n'running
+
+Data:
+
+- "server": Server information (json-object)
+  - "host": IP address (json-string)
+  - "port": port number (json-string)
+  - "family": address family (json-string, "ipv4" or "ipv6")
+  - "auth": authentication method (json-string, optional)
+- "client": Client information (json-object)
+  - "host": IP address (json-string)
+  - "port": port number (json-string)
+  - "family": address family (json-string, "ipv4" or "ipv6")
+  - "connection-id": spice connection id.  All channels with the same id
+                     belong to the same spice session (json-int)
+  - "channel-type": channel type.  "1" is the main control channel, filter for
+                    this one if you want track spice sessions only (json-int)
+  - "channel-id": channel id.  Usually "0", might be different needed when
+                  multiple channels of the same type exist, such as multiple
+                  display channels in a multihead setup (json-int)
+  - "tls": whevener the channel is encrypted (json-bool)
+
+Example:
+
+{ "timestamp": {"seconds": 1290688046, "microseconds": 417172},
+  "event": "SPICE_INITIALIZED",
+  "data": {"server": {"auth": "spice", "port": "5921",
+                      "family": "ipv4", "host": "127.0.0.1"},
+           "client": {"port": "49004", "family": "ipv4", "channel-type": 3,
+                      "connection-id": 1804289383, "host": "127.0.0.1",
+                      "channel-id": 0, "tls": true}
+}}
+
+
 WATCHDOG
 --------
 
diff --git a/monitor.c b/monitor.c
index ec31eac..f04dda5 100644
--- a/monitor.c
+++ b/monitor.c
@@ -59,6 +59,7 @@
 #ifdef CONFIG_SIMPLE_TRACE
 #include "trace.h"
 #endif
+#include "ui/qemu-spice.h"
 
 //#define DEBUG
 //#define DEBUG_COMPLETION
@@ -459,6 +460,15 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)
         case QEVENT_WATCHDOG:
             event_name = "WATCHDOG";
             break;
+        case QEVENT_SPICE_CONNECTED:
+            event_name = "SPICE_CONNECTED";
+            break;
+        case QEVENT_SPICE_INITIALIZED:
+            event_name = "SPICE_INITIALIZED";
+            break;
+        case QEVENT_SPICE_DISCONNECTED:
+            event_name = "SPICE_DISCONNECTED";
+            break;
         default:
             abort();
             break;
diff --git a/monitor.h b/monitor.h
index 2d36bba..4f2d328 100644
--- a/monitor.h
+++ b/monitor.h
@@ -32,6 +32,9 @@ typedef enum MonitorEvent {
     QEVENT_BLOCK_IO_ERROR,
     QEVENT_RTC_CHANGE,
     QEVENT_WATCHDOG,
+    QEVENT_SPICE_CONNECTED,
+    QEVENT_SPICE_INITIALIZED,
+    QEVENT_SPICE_DISCONNECTED,
     QEVENT_MAX,
 } MonitorEvent;
 
diff --git a/ui/spice-core.c b/ui/spice-core.c
index b7fa031..93461c6 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -18,16 +18,24 @@
 #include <spice.h>
 #include <spice-experimental.h>
 
+#include <netdb.h>
+
 #include "qemu-common.h"
 #include "qemu-spice.h"
 #include "qemu-timer.h"
 #include "qemu-queue.h"
 #include "qemu-x509.h"
+#include "qemu_socket.h"
+#include "qint.h"
+#include "qbool.h"
+#include "qstring.h"
+#include "qjson.h"
 #include "monitor.h"
 
 /* core bits */
 
 static SpiceServer *spice_server;
+static const char *auth = "spice";
 int using_spice = 0;
 
 struct SpiceTimer {
@@ -121,6 +129,68 @@ static void watch_remove(SpiceWatch *watch)
     qemu_free(watch);
 }
 
+#if SPICE_INTERFACE_CORE_MINOR >= 3
+
+static void add_addr_info(QDict *dict, struct sockaddr *addr, int len)
+{
+    char host[NI_MAXHOST], port[NI_MAXSERV];
+    const char *family;
+
+    getnameinfo(addr, len, host, sizeof(host), port, sizeof(port),
+                NI_NUMERICHOST | NI_NUMERICSERV);
+    family = inet_strfamily(addr->sa_family);
+
+    qdict_put(dict, "host", qstring_from_str(host));
+    qdict_put(dict, "port", qstring_from_str(port));
+    qdict_put(dict, "family", qstring_from_str(family));
+}
+
+static void add_channel_info(QDict *dict, SpiceChannelEventInfo *info)
+{
+    int tls = info->flags & SPICE_CHANNEL_EVENT_FLAG_TLS;
+
+    qdict_put(dict, "connection-id", qint_from_int(info->connection_id));
+    qdict_put(dict, "channel-type", qint_from_int(info->type));
+    qdict_put(dict, "channel-id", qint_from_int(info->id));
+    qdict_put(dict, "tls", qbool_from_int(tls));
+}
+
+static void channel_event(int event, SpiceChannelEventInfo *info)
+{
+    static const int qevent[] = {
+        [ SPICE_CHANNEL_EVENT_CONNECTED    ] = QEVENT_SPICE_CONNECTED,
+        [ SPICE_CHANNEL_EVENT_INITIALIZED  ] = QEVENT_SPICE_INITIALIZED,
+        [ SPICE_CHANNEL_EVENT_DISCONNECTED ] = QEVENT_SPICE_DISCONNECTED,
+    };
+    QDict *server, *client;
+    QObject *data;
+
+    client = qdict_new();
+    add_addr_info(client, &info->paddr, info->plen);
+
+    server = qdict_new();
+    add_addr_info(server, &info->laddr, info->llen);
+
+    if (event == SPICE_CHANNEL_EVENT_INITIALIZED) {
+        qdict_put(server, "auth", qstring_from_str(auth));
+        add_channel_info(client, info);
+    }
+
+    data = qobject_from_jsonf("{ 'client': %p, 'server': %p }",
+                              QOBJECT(client), QOBJECT(server));
+    monitor_protocol_event(qevent[event], data);
+    qobject_decref(data);
+}
+
+#else /* SPICE_INTERFACE_CORE_MINOR >= 3 */
+
+static QList *channel_list_get(void)
+{
+    return NULL;
+}
+
+#endif /* SPICE_INTERFACE_CORE_MINOR >= 3 */
+
 static SpiceCoreInterface core_interface = {
     .base.type          = SPICE_INTERFACE_CORE,
     .base.description   = "qemu core services",
@@ -135,6 +205,10 @@ static SpiceCoreInterface core_interface = {
     .watch_add          = watch_add,
     .watch_update_mask  = watch_update_mask,
     .watch_remove       = watch_remove,
+
+#if SPICE_INTERFACE_CORE_MINOR >= 3
+    .channel_event      = channel_event,
+#endif
 };
 
 /* config string parsing */
@@ -316,6 +390,7 @@ void qemu_spice_init(void)
         spice_server_set_ticket(spice_server, password, 0, 0, 0);
     }
     if (qemu_opt_get_bool(opts, "disable-ticketing", 0)) {
+        auth = "none";
         spice_server_set_noauth(spice_server);
     }
 
commit a19cbfb346425cc760ed19b4e746417df636b761
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Apr 27 11:50:11 2010 +0200

    spice: add qxl device
    
    qxl is a paravirtual graphics card.  The qxl device is the bridge
    between the guest and the spice server (aka libspice-server).  The
    spice server will send the rendering commands to the spice client, which
    will actually render them.
    
    The spice server is also able to render locally, which is done in case
    the guest wants read something from video memory.  Local rendering is
    also used to support display over vnc and sdl.
    
    qxl is activated using "-vga qxl".  qxl supports multihead, additional
    cards can be added via '-device qxl".
    
    [ v2: add copyright to files                     ]
    [ v2: use qemu-common.h for standard includes    ]
    [ v2: create separate qxl-vga device for primary ]
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/Makefile.target b/Makefile.target
index 5784844..c40833b 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -224,6 +224,7 @@ obj-i386-y += vmmouse.o vmport.o hpet.o applesmc.o
 obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
 obj-i386-y += debugcon.o multiboot.o
 obj-i386-y += pc_piix.o
+obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
 
 # shared objects
 obj-ppc-y = ppc.o
diff --git a/hw/hw.h b/hw/hw.h
index 77bfb58..163a683 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -528,6 +528,17 @@ extern const VMStateInfo vmstate_info_unused_buffer;
     .start        = (_start),                                        \
 }
 
+#define VMSTATE_VBUFFER_UINT32(_field, _state, _version, _test, _start, _field_size) { \
+    .name         = (stringify(_field)),                             \
+    .version_id   = (_version),                                      \
+    .field_exists = (_test),                                         \
+    .size_offset  = vmstate_offset_value(_state, _field_size, uint32_t),\
+    .info         = &vmstate_info_buffer,                            \
+    .flags        = VMS_VBUFFER|VMS_POINTER,                         \
+    .offset       = offsetof(_state, _field),                        \
+    .start        = (_start),                                        \
+}
+
 #define VMSTATE_BUFFER_UNSAFE_INFO(_field, _state, _version, _info, _size) { \
     .name       = (stringify(_field)),                               \
     .version_id = (_version),                                        \
@@ -745,6 +756,9 @@ extern const VMStateDescription vmstate_i2c_slave;
 #define VMSTATE_PARTIAL_VBUFFER(_f, _s, _size)                        \
     VMSTATE_VBUFFER(_f, _s, 0, NULL, 0, _size)
 
+#define VMSTATE_PARTIAL_VBUFFER_UINT32(_f, _s, _size)                        \
+    VMSTATE_VBUFFER_UINT32(_f, _s, 0, NULL, 0, _size)
+
 #define VMSTATE_SUB_VBUFFER(_f, _s, _start, _size)                    \
     VMSTATE_VBUFFER(_f, _s, 0, NULL, _start, _size)
 
diff --git a/hw/pc.c b/hw/pc.c
index 119c110..f28e237 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -40,6 +40,7 @@
 #include "sysbus.h"
 #include "sysemu.h"
 #include "blockdev.h"
+#include "ui/qemu-spice.h"
 
 /* output Bochs bios info messages */
 //#define DEBUG_BIOS
@@ -991,6 +992,13 @@ void pc_vga_init(PCIBus *pci_bus)
             pci_vmsvga_init(pci_bus);
         else
             fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__);
+#ifdef CONFIG_SPICE
+    } else if (qxl_enabled) {
+        if (pci_bus)
+            pci_create_simple(pci_bus, -1, "qxl-vga");
+        else
+            fprintf(stderr, "%s: qxl: no PCI bus\n", __FUNCTION__);
+#endif
     } else if (std_vga_enabled) {
         if (pci_bus) {
             pci_vga_init(pci_bus);
diff --git a/hw/qxl-logger.c b/hw/qxl-logger.c
new file mode 100644
index 0000000..76f43e6
--- /dev/null
+++ b/hw/qxl-logger.c
@@ -0,0 +1,248 @@
+/*
+ * qxl command logging -- for debug purposes
+ *
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * maintained by Gerd Hoffmann <kraxel at redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qxl.h"
+
+static const char *qxl_type[] = {
+    [ QXL_CMD_NOP ]     = "nop",
+    [ QXL_CMD_DRAW ]    = "draw",
+    [ QXL_CMD_UPDATE ]  = "update",
+    [ QXL_CMD_CURSOR ]  = "cursor",
+    [ QXL_CMD_MESSAGE ] = "message",
+    [ QXL_CMD_SURFACE ] = "surface",
+};
+
+static const char *qxl_draw_type[] = {
+    [ QXL_DRAW_NOP         ] = "nop",
+    [ QXL_DRAW_FILL        ] = "fill",
+    [ QXL_DRAW_OPAQUE      ] = "opaque",
+    [ QXL_DRAW_COPY        ] = "copy",
+    [ QXL_COPY_BITS        ] = "copy-bits",
+    [ QXL_DRAW_BLEND       ] = "blend",
+    [ QXL_DRAW_BLACKNESS   ] = "blackness",
+    [ QXL_DRAW_WHITENESS   ] = "whitemess",
+    [ QXL_DRAW_INVERS      ] = "invers",
+    [ QXL_DRAW_ROP3        ] = "rop3",
+    [ QXL_DRAW_STROKE      ] = "stroke",
+    [ QXL_DRAW_TEXT        ] = "text",
+    [ QXL_DRAW_TRANSPARENT ] = "transparent",
+    [ QXL_DRAW_ALPHA_BLEND ] = "alpha-blend",
+};
+
+static const char *qxl_draw_effect[] = {
+    [ QXL_EFFECT_BLEND            ] = "blend",
+    [ QXL_EFFECT_OPAQUE           ] = "opaque",
+    [ QXL_EFFECT_REVERT_ON_DUP    ] = "revert-on-dup",
+    [ QXL_EFFECT_BLACKNESS_ON_DUP ] = "blackness-on-dup",
+    [ QXL_EFFECT_WHITENESS_ON_DUP ] = "whiteness-on-dup",
+    [ QXL_EFFECT_NOP_ON_DUP       ] = "nop-on-dup",
+    [ QXL_EFFECT_NOP              ] = "nop",
+    [ QXL_EFFECT_OPAQUE_BRUSH     ] = "opaque-brush",
+};
+
+static const char *qxl_surface_cmd[] = {
+   [ QXL_SURFACE_CMD_CREATE  ] = "create",
+   [ QXL_SURFACE_CMD_DESTROY ] = "destroy",
+};
+
+static const char *spice_surface_fmt[] = {
+   [ SPICE_SURFACE_FMT_INVALID  ] = "invalid",
+   [ SPICE_SURFACE_FMT_1_A      ] = "alpha/1",
+   [ SPICE_SURFACE_FMT_8_A      ] = "alpha/8",
+   [ SPICE_SURFACE_FMT_16_555   ] = "555/16",
+   [ SPICE_SURFACE_FMT_16_565   ] = "565/16",
+   [ SPICE_SURFACE_FMT_32_xRGB  ] = "xRGB/32",
+   [ SPICE_SURFACE_FMT_32_ARGB  ] = "ARGB/32",
+};
+
+static const char *qxl_cursor_cmd[] = {
+   [ QXL_CURSOR_SET   ] = "set",
+   [ QXL_CURSOR_MOVE  ] = "move",
+   [ QXL_CURSOR_HIDE  ] = "hide",
+   [ QXL_CURSOR_TRAIL ] = "trail",
+};
+
+static const char *spice_cursor_type[] = {
+   [ SPICE_CURSOR_TYPE_ALPHA   ] = "alpha",
+   [ SPICE_CURSOR_TYPE_MONO    ] = "mono",
+   [ SPICE_CURSOR_TYPE_COLOR4  ] = "color4",
+   [ SPICE_CURSOR_TYPE_COLOR8  ] = "color8",
+   [ SPICE_CURSOR_TYPE_COLOR16 ] = "color16",
+   [ SPICE_CURSOR_TYPE_COLOR24 ] = "color24",
+   [ SPICE_CURSOR_TYPE_COLOR32 ] = "color32",
+};
+
+static const char *qxl_v2n(const char *n[], size_t l, int v)
+{
+    if (v >= l || !n[v]) {
+        return "???";
+    }
+    return n[v];
+}
+#define qxl_name(_list, _value) qxl_v2n(_list, ARRAY_SIZE(_list), _value)
+
+static void qxl_log_image(PCIQXLDevice *qxl, QXLPHYSICAL addr, int group_id)
+{
+    QXLImage *image;
+    QXLImageDescriptor *desc;
+
+    image = qxl_phys2virt(qxl, addr, group_id);
+    desc = &image->descriptor;
+    fprintf(stderr, " (id %" PRIx64 " type %d flags %d width %d height %d",
+            desc->id, desc->type, desc->flags, desc->width, desc->height);
+    switch (desc->type) {
+    case SPICE_IMAGE_TYPE_BITMAP:
+        fprintf(stderr, ", fmt %d flags %d x %d y %d stride %d"
+                " palette %" PRIx64 " data %" PRIx64,
+                image->bitmap.format, image->bitmap.flags,
+                image->bitmap.x, image->bitmap.y,
+                image->bitmap.stride,
+                image->bitmap.palette, image->bitmap.data);
+        break;
+    }
+    fprintf(stderr, ")");
+}
+
+static void qxl_log_rect(QXLRect *rect)
+{
+    fprintf(stderr, " %dx%d+%d+%d",
+            rect->right - rect->left,
+            rect->bottom - rect->top,
+            rect->left, rect->top);
+}
+
+static void qxl_log_cmd_draw_copy(PCIQXLDevice *qxl, QXLCopy *copy, int group_id)
+{
+    fprintf(stderr, " src %" PRIx64,
+            copy->src_bitmap);
+    qxl_log_image(qxl, copy->src_bitmap, group_id);
+    fprintf(stderr, " area");
+    qxl_log_rect(&copy->src_area);
+    fprintf(stderr, " rop %d", copy->rop_descriptor);
+}
+
+static void qxl_log_cmd_draw(PCIQXLDevice *qxl, QXLDrawable *draw, int group_id)
+{
+    fprintf(stderr, ": surface_id %d type %s effect %s",
+            draw->surface_id,
+            qxl_name(qxl_draw_type, draw->type),
+            qxl_name(qxl_draw_effect, draw->effect));
+    switch (draw->type) {
+    case QXL_DRAW_COPY:
+        qxl_log_cmd_draw_copy(qxl, &draw->u.copy, group_id);
+        break;
+    }
+}
+
+static void qxl_log_cmd_draw_compat(PCIQXLDevice *qxl, QXLCompatDrawable *draw,
+                                    int group_id)
+{
+    fprintf(stderr, ": type %s effect %s",
+            qxl_name(qxl_draw_type, draw->type),
+            qxl_name(qxl_draw_effect, draw->effect));
+    if (draw->bitmap_offset) {
+        fprintf(stderr, ": bitmap %d",
+                draw->bitmap_offset);
+        qxl_log_rect(&draw->bitmap_area);
+    }
+    switch (draw->type) {
+    case QXL_DRAW_COPY:
+        qxl_log_cmd_draw_copy(qxl, &draw->u.copy, group_id);
+        break;
+    }
+}
+
+static void qxl_log_cmd_surface(PCIQXLDevice *qxl, QXLSurfaceCmd *cmd)
+{
+    fprintf(stderr, ": %s id %d",
+            qxl_name(qxl_surface_cmd, cmd->type),
+            cmd->surface_id);
+    if (cmd->type == QXL_SURFACE_CMD_CREATE) {
+        fprintf(stderr, " size %dx%d stride %d format %s (count %d, max %d)",
+                cmd->u.surface_create.width,
+                cmd->u.surface_create.height,
+                cmd->u.surface_create.stride,
+                qxl_name(spice_surface_fmt, cmd->u.surface_create.format),
+                qxl->guest_surfaces.count, qxl->guest_surfaces.max);
+    }
+    if (cmd->type == QXL_SURFACE_CMD_DESTROY) {
+        fprintf(stderr, " (count %d)", qxl->guest_surfaces.count);
+    }
+}
+
+void qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id)
+{
+    QXLCursor *cursor;
+
+    fprintf(stderr, ": %s",
+            qxl_name(qxl_cursor_cmd, cmd->type));
+    switch (cmd->type) {
+    case QXL_CURSOR_SET:
+        fprintf(stderr, " +%d+%d visible %s, shape @ 0x%" PRIx64,
+                cmd->u.set.position.x,
+                cmd->u.set.position.y,
+                cmd->u.set.visible ? "yes" : "no",
+                cmd->u.set.shape);
+        cursor = qxl_phys2virt(qxl, cmd->u.set.shape, group_id);
+        fprintf(stderr, " type %s size %dx%d hot-spot +%d+%d"
+                " unique 0x%" PRIx64 " data-size %d",
+                qxl_name(spice_cursor_type, cursor->header.type),
+                cursor->header.width, cursor->header.height,
+                cursor->header.hot_spot_x, cursor->header.hot_spot_y,
+                cursor->header.unique, cursor->data_size);
+        break;
+    case QXL_CURSOR_MOVE:
+        fprintf(stderr, " +%d+%d", cmd->u.position.x, cmd->u.position.y);
+        break;
+    }
+}
+
+void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext)
+{
+    bool compat = ext->flags & QXL_COMMAND_FLAG_COMPAT;
+    void *data;
+
+    if (!qxl->cmdlog) {
+        return;
+    }
+    fprintf(stderr, "qxl-%d/%s:", qxl->id, ring);
+    fprintf(stderr, " cmd @ 0x%" PRIx64 " %s%s", ext->cmd.data,
+            qxl_name(qxl_type, ext->cmd.type),
+            compat ? "(compat)" : "");
+
+    data = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
+    switch (ext->cmd.type) {
+    case QXL_CMD_DRAW:
+        if (!compat) {
+            qxl_log_cmd_draw(qxl, data, ext->group_id);
+        } else {
+            qxl_log_cmd_draw_compat(qxl, data, ext->group_id);
+        }
+        break;
+    case QXL_CMD_SURFACE:
+        qxl_log_cmd_surface(qxl, data);
+        break;
+    case QXL_CMD_CURSOR:
+        qxl_log_cmd_cursor(qxl, data, ext->group_id);
+        break;
+    }
+    fprintf(stderr, "\n");
+}
diff --git a/hw/qxl-render.c b/hw/qxl-render.c
new file mode 100644
index 0000000..58965e0
--- /dev/null
+++ b/hw/qxl-render.c
@@ -0,0 +1,226 @@
+/*
+ * qxl local rendering (aka display on sdl/vnc)
+ *
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * maintained by Gerd Hoffmann <kraxel at redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qxl.h"
+
+static void qxl_flip(PCIQXLDevice *qxl, QXLRect *rect)
+{
+    uint8_t *src = qxl->guest_primary.data;
+    uint8_t *dst = qxl->guest_primary.flipped;
+    int len, i;
+
+    src += (qxl->guest_primary.surface.height - rect->top - 1) *
+        qxl->guest_primary.stride;
+    dst += rect->top  * qxl->guest_primary.stride;
+    src += rect->left * qxl->guest_primary.bytes_pp;
+    dst += rect->left * qxl->guest_primary.bytes_pp;
+    len  = (rect->right - rect->left) * qxl->guest_primary.bytes_pp;
+
+    for (i = rect->top; i < rect->bottom; i++) {
+        memcpy(dst, src, len);
+        dst += qxl->guest_primary.stride;
+        src -= qxl->guest_primary.stride;
+    }
+}
+
+void qxl_render_resize(PCIQXLDevice *qxl)
+{
+    QXLSurfaceCreate *sc = &qxl->guest_primary.surface;
+
+    qxl->guest_primary.stride = sc->stride;
+    qxl->guest_primary.resized++;
+    switch (sc->format) {
+    case SPICE_SURFACE_FMT_16_555:
+        qxl->guest_primary.bytes_pp = 2;
+        qxl->guest_primary.bits_pp = 15;
+        break;
+    case SPICE_SURFACE_FMT_16_565:
+        qxl->guest_primary.bytes_pp = 2;
+        qxl->guest_primary.bits_pp = 16;
+        break;
+    case SPICE_SURFACE_FMT_32_xRGB:
+    case SPICE_SURFACE_FMT_32_ARGB:
+        qxl->guest_primary.bytes_pp = 4;
+        qxl->guest_primary.bits_pp = 32;
+        break;
+    default:
+        fprintf(stderr, "%s: unhandled format: %x\n", __FUNCTION__,
+                qxl->guest_primary.surface.format);
+        qxl->guest_primary.bytes_pp = 4;
+        qxl->guest_primary.bits_pp = 32;
+        break;
+    }
+}
+
+void qxl_render_update(PCIQXLDevice *qxl)
+{
+    VGACommonState *vga = &qxl->vga;
+    QXLRect dirty[32], update;
+    void *ptr;
+    int i;
+
+    if (qxl->guest_primary.resized) {
+        qxl->guest_primary.resized = 0;
+
+        if (qxl->guest_primary.flipped) {
+            qemu_free(qxl->guest_primary.flipped);
+            qxl->guest_primary.flipped = NULL;
+        }
+        qemu_free_displaysurface(vga->ds);
+
+        qxl->guest_primary.data = qemu_get_ram_ptr(qxl->vga.vram_offset);
+        if (qxl->guest_primary.stride < 0) {
+            /* spice surface is upside down -> need extra buffer to flip */
+            qxl->guest_primary.stride = -qxl->guest_primary.stride;
+            qxl->guest_primary.flipped = qemu_malloc(qxl->guest_primary.surface.width *
+                                                     qxl->guest_primary.stride);
+            ptr = qxl->guest_primary.flipped;
+        } else {
+            ptr = qxl->guest_primary.data;
+        }
+        dprint(qxl, 1, "%s: %dx%d, stride %d, bpp %d, depth %d, flip %s\n",
+               __FUNCTION__,
+               qxl->guest_primary.surface.width,
+               qxl->guest_primary.surface.height,
+               qxl->guest_primary.stride,
+               qxl->guest_primary.bytes_pp,
+               qxl->guest_primary.bits_pp,
+               qxl->guest_primary.flipped ? "yes" : "no");
+        vga->ds->surface =
+            qemu_create_displaysurface_from(qxl->guest_primary.surface.width,
+                                            qxl->guest_primary.surface.height,
+                                            qxl->guest_primary.bits_pp,
+                                            qxl->guest_primary.stride,
+                                            ptr);
+        dpy_resize(vga->ds);
+    }
+
+    if (!qxl->guest_primary.commands) {
+        return;
+    }
+    qxl->guest_primary.commands = 0;
+
+    update.left   = 0;
+    update.right  = qxl->guest_primary.surface.width;
+    update.top    = 0;
+    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);
+
+    for (i = 0; i < ARRAY_SIZE(dirty); i++) {
+        if (qemu_spice_rect_is_empty(dirty+i)) {
+            break;
+        }
+        if (qxl->guest_primary.flipped) {
+            qxl_flip(qxl, dirty+i);
+        }
+        dpy_update(vga->ds,
+                   dirty[i].left, dirty[i].top,
+                   dirty[i].right - dirty[i].left,
+                   dirty[i].bottom - dirty[i].top);
+    }
+}
+
+static QEMUCursor *qxl_cursor(PCIQXLDevice *qxl, QXLCursor *cursor)
+{
+    QEMUCursor *c;
+    uint8_t *image, *mask;
+    int size;
+
+    c = cursor_alloc(cursor->header.width, cursor->header.height);
+    c->hot_x = cursor->header.hot_spot_x;
+    c->hot_y = cursor->header.hot_spot_y;
+    switch (cursor->header.type) {
+    case SPICE_CURSOR_TYPE_ALPHA:
+        size = cursor->header.width * cursor->header.height * sizeof(uint32_t);
+        memcpy(c->data, cursor->chunk.data, size);
+        if (qxl->debug > 2) {
+            cursor_print_ascii_art(c, "qxl/alpha");
+        }
+        break;
+    case SPICE_CURSOR_TYPE_MONO:
+        mask  = cursor->chunk.data;
+        image = mask + cursor_get_mono_bpl(c) * c->width;
+        cursor_set_mono(c, 0xffffff, 0x000000, image, 1, mask);
+        if (qxl->debug > 2) {
+            cursor_print_ascii_art(c, "qxl/mono");
+        }
+        break;
+    default:
+        fprintf(stderr, "%s: not implemented: type %d\n",
+                __FUNCTION__, cursor->header.type);
+        goto fail;
+    }
+    return c;
+
+fail:
+    cursor_put(c);
+    return NULL;
+}
+
+
+/* called from spice server thread context only */
+void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext)
+{
+    QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
+    QXLCursor *cursor;
+    QEMUCursor *c;
+    int x = -1, y = -1;
+
+    if (!qxl->ssd.ds->mouse_set || !qxl->ssd.ds->cursor_define) {
+        return;
+    }
+
+    if (qxl->debug > 1 && cmd->type != QXL_CURSOR_MOVE) {
+        fprintf(stderr, "%s", __FUNCTION__);
+        qxl_log_cmd_cursor(qxl, cmd, ext->group_id);
+        fprintf(stderr, "\n");
+    }
+    switch (cmd->type) {
+    case QXL_CURSOR_SET:
+        x = cmd->u.set.position.x;
+        y = cmd->u.set.position.y;
+        cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id);
+        if (cursor->chunk.data_size != cursor->data_size) {
+            fprintf(stderr, "%s: multiple chunks\n", __FUNCTION__);
+            return;
+        }
+        c = qxl_cursor(qxl, cursor);
+        if (c == NULL) {
+            c = cursor_builtin_left_ptr();
+        }
+        qemu_mutex_lock_iothread();
+        qxl->ssd.ds->cursor_define(c);
+        qxl->ssd.ds->mouse_set(x, y, 1);
+        qemu_mutex_unlock_iothread();
+        cursor_put(c);
+        break;
+    case QXL_CURSOR_MOVE:
+        x = cmd->u.position.x;
+        y = cmd->u.position.y;
+        qemu_mutex_lock_iothread();
+        qxl->ssd.ds->mouse_set(x, y, 1);
+        qemu_mutex_unlock_iothread();
+        break;
+    }
+}
diff --git a/hw/qxl.c b/hw/qxl.c
new file mode 100644
index 0000000..207aa63
--- /dev/null
+++ b/hw/qxl.c
@@ -0,0 +1,1587 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * written by Yaniv Kamay, Izik Eidus, Gerd Hoffmann
+ * maintained by Gerd Hoffmann <kraxel at redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <pthread.h>
+
+#include "qemu-common.h"
+#include "qemu-timer.h"
+#include "qemu-queue.h"
+#include "monitor.h"
+#include "sysemu.h"
+
+#include "qxl.h"
+
+#undef SPICE_RING_PROD_ITEM
+#define SPICE_RING_PROD_ITEM(r, ret) {                                  \
+        typeof(r) start = r;                                            \
+        typeof(r) end = r + 1;                                          \
+        uint32_t prod = (r)->prod & SPICE_RING_INDEX_MASK(r);           \
+        typeof(&(r)->items[prod]) m_item = &(r)->items[prod];           \
+        if (!((uint8_t*)m_item >= (uint8_t*)(start) && (uint8_t*)(m_item + 1) <= (uint8_t*)(end))) { \
+            abort();                                                    \
+        }                                                               \
+        ret = &m_item->el;                                              \
+    }
+
+#undef SPICE_RING_CONS_ITEM
+#define SPICE_RING_CONS_ITEM(r, ret) {                                  \
+        typeof(r) start = r;                                            \
+        typeof(r) end = r + 1;                                          \
+        uint32_t cons = (r)->cons & SPICE_RING_INDEX_MASK(r);           \
+        typeof(&(r)->items[cons]) m_item = &(r)->items[cons];           \
+        if (!((uint8_t*)m_item >= (uint8_t*)(start) && (uint8_t*)(m_item + 1) <= (uint8_t*)(end))) { \
+            abort();                                                    \
+        }                                                               \
+        ret = &m_item->el;                                              \
+    }
+
+#undef ALIGN
+#define ALIGN(a, b) (((a) + ((b) - 1)) & ~((b) - 1))
+
+#define PIXEL_SIZE 0.2936875 //1280x1024 is 14.8" x 11.9" 
+
+#define QXL_MODE(_x, _y, _b, _o)                  \
+    {   .x_res = _x,                              \
+        .y_res = _y,                              \
+        .bits  = _b,                              \
+        .stride = (_x) * (_b) / 8,                \
+        .x_mili = PIXEL_SIZE * (_x),              \
+        .y_mili = PIXEL_SIZE * (_y),              \
+        .orientation = _o,                        \
+    }
+
+#define QXL_MODE_16_32(x_res, y_res, orientation) \
+    QXL_MODE(x_res, y_res, 16, orientation),      \
+    QXL_MODE(x_res, y_res, 32, orientation)
+
+#define QXL_MODE_EX(x_res, y_res)                 \
+    QXL_MODE_16_32(x_res, y_res, 0),              \
+    QXL_MODE_16_32(y_res, x_res, 1),              \
+    QXL_MODE_16_32(x_res, y_res, 2),              \
+    QXL_MODE_16_32(y_res, x_res, 3)
+
+static QXLMode qxl_modes[] = {
+    QXL_MODE_EX(640, 480),
+    QXL_MODE_EX(800, 480),
+    QXL_MODE_EX(800, 600),
+    QXL_MODE_EX(832, 624),
+    QXL_MODE_EX(960, 640),
+    QXL_MODE_EX(1024, 600),
+    QXL_MODE_EX(1024, 768),
+    QXL_MODE_EX(1152, 864),
+    QXL_MODE_EX(1152, 870),
+    QXL_MODE_EX(1280, 720),
+    QXL_MODE_EX(1280, 760),
+    QXL_MODE_EX(1280, 768),
+    QXL_MODE_EX(1280, 800),
+    QXL_MODE_EX(1280, 960),
+    QXL_MODE_EX(1280, 1024),
+    QXL_MODE_EX(1360, 768),
+    QXL_MODE_EX(1366, 768),
+    QXL_MODE_EX(1400, 1050),
+    QXL_MODE_EX(1440, 900),
+    QXL_MODE_EX(1600, 900),
+    QXL_MODE_EX(1600, 1200),
+    QXL_MODE_EX(1680, 1050),
+    QXL_MODE_EX(1920, 1080),
+#if VGA_RAM_SIZE >= (16 * 1024 * 1024)
+    /* these modes need more than 8 MB video memory */
+    QXL_MODE_EX(1920, 1200),
+    QXL_MODE_EX(1920, 1440),
+    QXL_MODE_EX(2048, 1536),
+    QXL_MODE_EX(2560, 1440),
+    QXL_MODE_EX(2560, 1600),
+#endif
+#if VGA_RAM_SIZE >= (32 * 1024 * 1024)
+    /* these modes need more than 16 MB video memory */
+    QXL_MODE_EX(2560, 2048),
+    QXL_MODE_EX(2800, 2100),
+    QXL_MODE_EX(3200, 2400),
+#endif
+};
+
+static PCIQXLDevice *qxl0;
+
+static void qxl_send_events(PCIQXLDevice *d, uint32_t events);
+static void qxl_destroy_primary(PCIQXLDevice *d);
+static void qxl_reset_memslots(PCIQXLDevice *d);
+static void qxl_reset_surfaces(PCIQXLDevice *d);
+static void qxl_ring_set_dirty(PCIQXLDevice *qxl);
+
+static inline uint32_t msb_mask(uint32_t val)
+{
+    uint32_t mask;
+
+    do {
+        mask = ~(val - 1) & val;
+        val &= ~mask;
+    } while (mask < val);
+
+    return mask;
+}
+
+static ram_addr_t qxl_rom_size(void)
+{
+    uint32_t rom_size = sizeof(QXLRom) + sizeof(QXLModes) + sizeof(qxl_modes);
+    rom_size = MAX(rom_size, TARGET_PAGE_SIZE);
+    rom_size = msb_mask(rom_size * 2 - 1);
+    return rom_size;
+}
+
+static void init_qxl_rom(PCIQXLDevice *d)
+{
+    QXLRom *rom = qemu_get_ram_ptr(d->rom_offset);
+    QXLModes *modes = (QXLModes *)(rom + 1);
+    uint32_t ram_header_size;
+    uint32_t surface0_area_size;
+    uint32_t num_pages;
+    uint32_t fb, maxfb = 0;
+    int i;
+
+    memset(rom, 0, d->rom_size);
+
+    rom->magic         = cpu_to_le32(QXL_ROM_MAGIC);
+    rom->id            = cpu_to_le32(d->id);
+    rom->log_level     = cpu_to_le32(d->guestdebug);
+    rom->modes_offset  = cpu_to_le32(sizeof(QXLRom));
+
+    rom->slot_gen_bits = MEMSLOT_GENERATION_BITS;
+    rom->slot_id_bits  = MEMSLOT_SLOT_BITS;
+    rom->slots_start   = 1;
+    rom->slots_end     = NUM_MEMSLOTS - 1;
+    rom->n_surfaces    = cpu_to_le32(NUM_SURFACES);
+
+    modes->n_modes     = cpu_to_le32(ARRAY_SIZE(qxl_modes));
+    for (i = 0; i < modes->n_modes; i++) {
+        fb = qxl_modes[i].y_res * qxl_modes[i].stride;
+        if (maxfb < fb) {
+            maxfb = fb;
+        }
+        modes->modes[i].id          = cpu_to_le32(i);
+        modes->modes[i].x_res       = cpu_to_le32(qxl_modes[i].x_res);
+        modes->modes[i].y_res       = cpu_to_le32(qxl_modes[i].y_res);
+        modes->modes[i].bits        = cpu_to_le32(qxl_modes[i].bits);
+        modes->modes[i].stride      = cpu_to_le32(qxl_modes[i].stride);
+        modes->modes[i].x_mili      = cpu_to_le32(qxl_modes[i].x_mili);
+        modes->modes[i].y_mili      = cpu_to_le32(qxl_modes[i].y_mili);
+        modes->modes[i].orientation = cpu_to_le32(qxl_modes[i].orientation);
+    }
+    if (maxfb < VGA_RAM_SIZE && d->id == 0)
+        maxfb = VGA_RAM_SIZE;
+
+    ram_header_size    = ALIGN(sizeof(QXLRam), 4096);
+    surface0_area_size = ALIGN(maxfb, 4096);
+    num_pages          = d->vga.vram_size;
+    num_pages         -= ram_header_size;
+    num_pages         -= surface0_area_size;
+    num_pages          = num_pages / TARGET_PAGE_SIZE;
+
+    rom->draw_area_offset   = cpu_to_le32(0);
+    rom->surface0_area_size = cpu_to_le32(surface0_area_size);
+    rom->pages_offset       = cpu_to_le32(surface0_area_size);
+    rom->num_pages          = cpu_to_le32(num_pages);
+    rom->ram_header_offset  = cpu_to_le32(d->vga.vram_size - ram_header_size);
+
+    d->shadow_rom = *rom;
+    d->rom        = rom;
+    d->modes      = modes;
+}
+
+static void init_qxl_ram(PCIQXLDevice *d)
+{
+    uint8_t *buf;
+    uint64_t *item;
+
+    buf = d->vga.vram_ptr;
+    d->ram = (QXLRam *)(buf + le32_to_cpu(d->shadow_rom.ram_header_offset));
+    d->ram->magic       = cpu_to_le32(QXL_RAM_MAGIC);
+    d->ram->int_pending = cpu_to_le32(0);
+    d->ram->int_mask    = cpu_to_le32(0);
+    SPICE_RING_INIT(&d->ram->cmd_ring);
+    SPICE_RING_INIT(&d->ram->cursor_ring);
+    SPICE_RING_INIT(&d->ram->release_ring);
+    SPICE_RING_PROD_ITEM(&d->ram->release_ring, item);
+    *item = 0;
+    qxl_ring_set_dirty(d);
+}
+
+/* can be called from spice server thread context */
+static void qxl_set_dirty(ram_addr_t addr, ram_addr_t end)
+{
+    while (addr < end) {
+        cpu_physical_memory_set_dirty(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);
+}
+
+/* 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);
+}
+
+/* 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);
+}
+
+/*
+ * keep track of some command state, for savevm/loadvm.
+ * called from spice server thread context only
+ */
+static void qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext)
+{
+    switch (le32_to_cpu(ext->cmd.type)) {
+    case QXL_CMD_SURFACE:
+    {
+        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);
+        if (cmd->type == QXL_SURFACE_CMD_CREATE) {
+            qxl->guest_surfaces.cmds[id] = ext->cmd.data;
+            qxl->guest_surfaces.count++;
+            if (qxl->guest_surfaces.max < qxl->guest_surfaces.count)
+                qxl->guest_surfaces.max = qxl->guest_surfaces.count;
+        }
+        if (cmd->type == QXL_SURFACE_CMD_DESTROY) {
+            qxl->guest_surfaces.cmds[id] = 0;
+            qxl->guest_surfaces.count--;
+        }
+        break;
+    }
+    case QXL_CMD_CURSOR:
+    {
+        QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
+        if (cmd->type == QXL_CURSOR_SET) {
+            qxl->guest_cursor = ext->cmd.data;
+        }
+        break;
+    }
+    }
+}
+
+/* spice display interface callbacks */
+
+static void interface_attach_worker(QXLInstance *sin, QXLWorker *qxl_worker)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+
+    dprint(qxl, 1, "%s:\n", __FUNCTION__);
+    qxl->ssd.worker = qxl_worker;
+}
+
+static void interface_set_compression_level(QXLInstance *sin, int level)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+
+    dprint(qxl, 1, "%s: %d\n", __FUNCTION__, level);
+    qxl->shadow_rom.compression_level = cpu_to_le32(level);
+    qxl->rom->compression_level = cpu_to_le32(level);
+    qxl_rom_set_dirty(qxl);
+}
+
+static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+
+    qxl->shadow_rom.mm_clock = cpu_to_le32(mm_time);
+    qxl->rom->mm_clock = cpu_to_le32(mm_time);
+    qxl_rom_set_dirty(qxl);
+}
+
+static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+
+    dprint(qxl, 1, "%s:\n", __FUNCTION__);
+    info->memslot_gen_bits = MEMSLOT_GENERATION_BITS;
+    info->memslot_id_bits = MEMSLOT_SLOT_BITS;
+    info->num_memslots = NUM_MEMSLOTS;
+    info->num_memslots_groups = NUM_MEMSLOTS_GROUPS;
+    info->internal_groupslot_id = 0;
+    info->qxl_ram_size = le32_to_cpu(qxl->shadow_rom.num_pages) << TARGET_PAGE_BITS;
+    info->n_surfaces = NUM_SURFACES;
+}
+
+/* called from spice server thread context only */
+static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    SimpleSpiceUpdate *update;
+    QXLCommandRing *ring;
+    QXLCommand *cmd;
+    int notify;
+
+    switch (qxl->mode) {
+    case QXL_MODE_VGA:
+        dprint(qxl, 2, "%s: vga\n", __FUNCTION__);
+        update = qemu_spice_create_update(&qxl->ssd);
+        if (update == NULL) {
+            return false;
+        }
+        *ext = update->ext;
+        qxl_log_command(qxl, "vga", ext);
+        return true;
+    case QXL_MODE_COMPAT:
+    case QXL_MODE_NATIVE:
+    case QXL_MODE_UNDEFINED:
+        dprint(qxl, 2, "%s: %s\n", __FUNCTION__,
+               qxl->cmdflags ? "compat" : "native");
+        ring = &qxl->ram->cmd_ring;
+        if (SPICE_RING_IS_EMPTY(ring)) {
+            return false;
+        }
+        SPICE_RING_CONS_ITEM(ring, cmd);
+        ext->cmd      = *cmd;
+        ext->group_id = MEMSLOT_GROUP_GUEST;
+        ext->flags    = qxl->cmdflags;
+        SPICE_RING_POP(ring, notify);
+        qxl_ring_set_dirty(qxl);
+        if (notify) {
+            qxl_send_events(qxl, QXL_INTERRUPT_DISPLAY);
+        }
+        qxl->guest_primary.commands++;
+        qxl_track_command(qxl, ext);
+        qxl_log_command(qxl, "cmd", ext);
+        return true;
+    default:
+        return false;
+    }
+}
+
+/* called from spice server thread context only */
+static int interface_req_cmd_notification(QXLInstance *sin)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    int wait = 1;
+
+    switch (qxl->mode) {
+    case QXL_MODE_COMPAT:
+    case QXL_MODE_NATIVE:
+    case QXL_MODE_UNDEFINED:
+        SPICE_RING_CONS_WAIT(&qxl->ram->cmd_ring, wait);
+        qxl_ring_set_dirty(qxl);
+        break;
+    default:
+        /* nothing */
+        break;
+    }
+    return wait;
+}
+
+/* called from spice server thread context only */
+static inline void qxl_push_free_res(PCIQXLDevice *d, int flush)
+{
+    QXLReleaseRing *ring = &d->ram->release_ring;
+    uint64_t *item;
+    int notify;
+
+#define QXL_FREE_BUNCH_SIZE 32
+
+    if (ring->prod - ring->cons + 1 == ring->num_items) {
+        /* ring full -- can't push */
+        return;
+    }
+    if (!flush && d->oom_running) {
+        /* collect everything from oom handler before pushing */
+        return;
+    }
+    if (!flush && d->num_free_res < QXL_FREE_BUNCH_SIZE) {
+        /* collect a bit more before pushing */
+        return;
+    }
+
+    SPICE_RING_PUSH(ring, notify);
+    dprint(d, 2, "free: push %d items, notify %s, ring %d/%d [%d,%d]\n",
+           d->num_free_res, notify ? "yes" : "no",
+           ring->prod - ring->cons, ring->num_items,
+           ring->prod, ring->cons);
+    if (notify) {
+        qxl_send_events(d, QXL_INTERRUPT_DISPLAY);
+    }
+    SPICE_RING_PROD_ITEM(ring, item);
+    *item = 0;
+    d->num_free_res = 0;
+    d->last_release = NULL;
+    qxl_ring_set_dirty(d);
+}
+
+/* called from spice server thread context only */
+static void interface_release_resource(QXLInstance *sin,
+                                       struct QXLReleaseInfoExt ext)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    QXLReleaseRing *ring;
+    uint64_t *item, id;
+
+    if (ext.group_id == MEMSLOT_GROUP_HOST) {
+        /* host group -> vga mode update request */
+        qemu_spice_destroy_update(&qxl->ssd, (void*)ext.info->id);
+        return;
+    }
+
+    /*
+     * ext->info points into guest-visible memory
+     * pci bar 0, $command.release_info
+     */
+    ring = &qxl->ram->release_ring;
+    SPICE_RING_PROD_ITEM(ring, item);
+    if (*item == 0) {
+        /* stick head into the ring */
+        id = ext.info->id;
+        ext.info->next = 0;
+        qxl_ram_set_dirty(qxl, &ext.info->next);
+        *item = id;
+        qxl_ring_set_dirty(qxl);
+    } else {
+        /* append item to the list */
+        qxl->last_release->next = ext.info->id;
+        qxl_ram_set_dirty(qxl, &qxl->last_release->next);
+        ext.info->next = 0;
+        qxl_ram_set_dirty(qxl, &ext.info->next);
+    }
+    qxl->last_release = ext.info;
+    qxl->num_free_res++;
+    dprint(qxl, 3, "%4d\r", qxl->num_free_res);
+    qxl_push_free_res(qxl, 0);
+}
+
+/* called from spice server thread context only */
+static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt *ext)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    QXLCursorRing *ring;
+    QXLCommand *cmd;
+    int notify;
+
+    switch (qxl->mode) {
+    case QXL_MODE_COMPAT:
+    case QXL_MODE_NATIVE:
+    case QXL_MODE_UNDEFINED:
+        ring = &qxl->ram->cursor_ring;
+        if (SPICE_RING_IS_EMPTY(ring)) {
+            return false;
+        }
+        SPICE_RING_CONS_ITEM(ring, cmd);
+        ext->cmd      = *cmd;
+        ext->group_id = MEMSLOT_GROUP_GUEST;
+        ext->flags    = qxl->cmdflags;
+        SPICE_RING_POP(ring, notify);
+        qxl_ring_set_dirty(qxl);
+        if (notify) {
+            qxl_send_events(qxl, QXL_INTERRUPT_CURSOR);
+        }
+        qxl->guest_primary.commands++;
+        qxl_track_command(qxl, ext);
+        qxl_log_command(qxl, "csr", ext);
+        if (qxl->id == 0) {
+            qxl_render_cursor(qxl, ext);
+        }
+        return true;
+    default:
+        return false;
+    }
+}
+
+/* called from spice server thread context only */
+static int interface_req_cursor_notification(QXLInstance *sin)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    int wait = 1;
+
+    switch (qxl->mode) {
+    case QXL_MODE_COMPAT:
+    case QXL_MODE_NATIVE:
+    case QXL_MODE_UNDEFINED:
+        SPICE_RING_CONS_WAIT(&qxl->ram->cursor_ring, wait);
+        qxl_ring_set_dirty(qxl);
+        break;
+    default:
+        /* nothing */
+        break;
+    }
+    return wait;
+}
+
+/* called from spice server thread context */
+static void interface_notify_update(QXLInstance *sin, uint32_t update_id)
+{
+    fprintf(stderr, "%s: abort()\n", __FUNCTION__);
+    abort();
+}
+
+/* called from spice server thread context only */
+static int interface_flush_resources(QXLInstance *sin)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    int ret;
+
+    dprint(qxl, 1, "free: guest flush (have %d)\n", qxl->num_free_res);
+    ret = qxl->num_free_res;
+    if (ret) {
+        qxl_push_free_res(qxl, 1);
+    }
+    return ret;
+}
+
+static const QXLInterface qxl_interface = {
+    .base.type               = SPICE_INTERFACE_QXL,
+    .base.description        = "qxl gpu",
+    .base.major_version      = SPICE_INTERFACE_QXL_MAJOR,
+    .base.minor_version      = SPICE_INTERFACE_QXL_MINOR,
+
+    .attache_worker          = interface_attach_worker,
+    .set_compression_level   = interface_set_compression_level,
+    .set_mm_time             = interface_set_mm_time,
+    .get_init_info           = interface_get_init_info,
+
+    /* the callbacks below are called from spice server thread context */
+    .get_command             = interface_get_command,
+    .req_cmd_notification    = interface_req_cmd_notification,
+    .release_resource        = interface_release_resource,
+    .get_cursor_command      = interface_get_cursor_command,
+    .req_cursor_notification = interface_req_cursor_notification,
+    .notify_update           = interface_notify_update,
+    .flush_resources         = interface_flush_resources,
+};
+
+static void qxl_enter_vga_mode(PCIQXLDevice *d)
+{
+    if (d->mode == QXL_MODE_VGA) {
+        return;
+    }
+    dprint(d, 1, "%s\n", __FUNCTION__);
+    qemu_spice_create_host_primary(&d->ssd);
+    d->mode = QXL_MODE_VGA;
+    memset(&d->ssd.dirty, 0, sizeof(d->ssd.dirty));
+}
+
+static void qxl_exit_vga_mode(PCIQXLDevice *d)
+{
+    if (d->mode != QXL_MODE_VGA) {
+        return;
+    }
+    dprint(d, 1, "%s\n", __FUNCTION__);
+    qxl_destroy_primary(d);
+}
+
+static void qxl_set_irq(PCIQXLDevice *d)
+{
+    uint32_t pending = le32_to_cpu(d->ram->int_pending);
+    uint32_t mask    = le32_to_cpu(d->ram->int_mask);
+    int level = !!(pending & mask);
+    qemu_set_irq(d->pci.irq[0], level);
+    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;
+
+    assert(SPICE_RING_IS_EMPTY(&ram->cmd_ring));
+    assert(SPICE_RING_IS_EMPTY(&ram->cursor_ring));
+}
+
+static void qxl_reset_state(PCIQXLDevice *d)
+{
+    QXLRam *ram = d->ram;
+    QXLRom *rom = d->rom;
+
+    assert(SPICE_RING_IS_EMPTY(&ram->cmd_ring));
+    assert(SPICE_RING_IS_EMPTY(&ram->cursor_ring));
+    d->shadow_rom.update_id = cpu_to_le32(0);
+    *rom = d->shadow_rom;
+    qxl_rom_set_dirty(d);
+    init_qxl_ram(d);
+    d->num_free_res = 0;
+    d->last_release = NULL;
+    memset(&d->ssd.dirty, 0, sizeof(d->ssd.dirty));
+}
+
+static void qxl_soft_reset(PCIQXLDevice *d)
+{
+    dprint(d, 1, "%s:\n", __FUNCTION__);
+    qxl_check_state(d);
+
+    if (d->id == 0) {
+        qxl_enter_vga_mode(d);
+    } else {
+        d->mode = QXL_MODE_UNDEFINED;
+    }
+}
+
+static void qxl_hard_reset(PCIQXLDevice *d, int loadvm)
+{
+    dprint(d, 1, "%s: start%s\n", __FUNCTION__,
+           loadvm ? " (loadvm)" : "");
+
+    qemu_mutex_unlock_iothread();
+    d->ssd.worker->reset_cursor(d->ssd.worker);
+    d->ssd.worker->reset_image_cache(d->ssd.worker);
+    qemu_mutex_lock_iothread();
+    qxl_reset_surfaces(d);
+    qxl_reset_memslots(d);
+
+    /* pre loadvm reset must not touch QXLRam.  This lives in
+     * device memory, is migrated together with RAM and thus
+     * already loaded at this point */
+    if (!loadvm) {
+        qxl_reset_state(d);
+    }
+    qemu_spice_create_host_memslot(&d->ssd);
+    qxl_soft_reset(d);
+
+    dprint(d, 1, "%s: done\n", __FUNCTION__);
+}
+
+static void qxl_reset_handler(DeviceState *dev)
+{
+    PCIQXLDevice *d = DO_UPCAST(PCIQXLDevice, pci.qdev, dev);
+    qxl_hard_reset(d, 0);
+}
+
+static void qxl_vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    VGACommonState *vga = opaque;
+    PCIQXLDevice *qxl = container_of(vga, PCIQXLDevice, vga);
+
+    if (qxl->mode != QXL_MODE_VGA) {
+        dprint(qxl, 1, "%s\n", __FUNCTION__);
+        qxl_destroy_primary(qxl);
+        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 const int regions[] = {
+        QXL_RAM_RANGE_INDEX,
+        QXL_VRAM_RANGE_INDEX,
+    };
+    uint64_t guest_start;
+    uint64_t guest_end;
+    int pci_region;
+    pcibus_t pci_start;
+    pcibus_t pci_end;
+    intptr_t virt_start;
+    QXLDevMemSlot memslot;
+    int i;
+
+    guest_start = le64_to_cpu(d->guest_slots[slot_id].slot.mem_start);
+    guest_end   = le64_to_cpu(d->guest_slots[slot_id].slot.mem_end);
+
+    dprint(d, 1, "%s: slot %d: guest phys 0x%" PRIx64 " - 0x%" PRIx64 "\n",
+           __FUNCTION__, slot_id,
+           guest_start, guest_end);
+
+    PANIC_ON(slot_id >= NUM_MEMSLOTS);
+    PANIC_ON(guest_start > guest_end);
+
+    for (i = 0; i < ARRAY_SIZE(regions); i++) {
+        pci_region = regions[i];
+        pci_start = d->pci.io_regions[pci_region].addr;
+        pci_end = pci_start + d->pci.io_regions[pci_region].size;
+        /* mapped? */
+        if (pci_start == -1) {
+            continue;
+        }
+        /* start address in range ? */
+        if (guest_start < pci_start || guest_start > pci_end) {
+            continue;
+        }
+        /* end address in range ? */
+        if (guest_end > pci_end) {
+            continue;
+        }
+        /* passed */
+        break;
+    }
+    PANIC_ON(i == ARRAY_SIZE(regions)); /* finished loop without match */
+
+    switch (pci_region) {
+    case QXL_RAM_RANGE_INDEX:
+        virt_start = (intptr_t)qemu_get_ram_ptr(d->vga.vram_offset);
+        break;
+    case QXL_VRAM_RANGE_INDEX:
+        virt_start = (intptr_t)qemu_get_ram_ptr(d->vram_offset);
+        break;
+    default:
+        /* should not happen */
+        abort();
+    }
+
+    memslot.slot_id = slot_id;
+    memslot.slot_group_id = MEMSLOT_GROUP_GUEST; /* guest group */
+    memslot.virt_start = virt_start + (guest_start - pci_start);
+    memslot.virt_end   = virt_start + (guest_end   - pci_start);
+    memslot.addr_delta = memslot.virt_start - delta;
+    memslot.generation = d->rom->slot_generation = 0;
+    qxl_rom_set_dirty(d);
+
+    dprint(d, 1, "%s: slot %d: host virt 0x%" PRIx64 " - 0x%" PRIx64 "\n",
+           __FUNCTION__, memslot.slot_id,
+           memslot.virt_start, memslot.virt_end);
+
+    d->ssd.worker->add_memslot(d->ssd.worker, &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;
+    d->guest_slots[slot_id].active = 1;
+}
+
+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);
+    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);
+    memset(&d->guest_slots, 0, sizeof(d->guest_slots));
+}
+
+static void qxl_reset_surfaces(PCIQXLDevice *d)
+{
+    dprint(d, 1, "%s:\n", __FUNCTION__);
+    d->mode = QXL_MODE_UNDEFINED;
+    qemu_mutex_unlock_iothread();
+    d->ssd.worker->destroy_surfaces(d->ssd.worker);
+    qemu_mutex_lock_iothread();
+    memset(&d->guest_surfaces.cmds, 0, sizeof(d->guest_surfaces.cmds));
+}
+
+/* called from spice server thread context only */
+void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id)
+{
+    uint64_t phys   = le64_to_cpu(pqxl);
+    uint32_t slot   = (phys >> (64 -  8)) & 0xff;
+    uint64_t offset = phys & 0xffffffffffff;
+
+    switch (group_id) {
+    case MEMSLOT_GROUP_HOST:
+        return (void*)offset;
+    case MEMSLOT_GROUP_GUEST:
+        PANIC_ON(slot > NUM_MEMSLOTS);
+        PANIC_ON(!qxl->guest_slots[slot].active);
+        PANIC_ON(offset < qxl->guest_slots[slot].delta);
+        offset -= qxl->guest_slots[slot].delta;
+        PANIC_ON(offset > qxl->guest_slots[slot].size)
+        return qxl->guest_slots[slot].ptr + offset;
+    default:
+        PANIC_ON(1);
+    }
+}
+
+static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm)
+{
+    QXLDevSurfaceCreate surface;
+    QXLSurfaceCreate *sc = &qxl->guest_primary.surface;
+
+    assert(qxl->mode != QXL_MODE_NATIVE);
+    qxl_exit_vga_mode(qxl);
+
+    dprint(qxl, 1, "%s: %dx%d\n", __FUNCTION__,
+           le32_to_cpu(sc->width), le32_to_cpu(sc->height));
+
+    surface.format     = le32_to_cpu(sc->format);
+    surface.height     = le32_to_cpu(sc->height);
+    surface.mem        = le64_to_cpu(sc->mem);
+    surface.position   = le32_to_cpu(sc->position);
+    surface.stride     = le32_to_cpu(sc->stride);
+    surface.width      = le32_to_cpu(sc->width);
+    surface.type       = le32_to_cpu(sc->type);
+    surface.flags      = le32_to_cpu(sc->flags);
+
+    surface.mouse_mode = true;
+    surface.group_id   = MEMSLOT_GROUP_GUEST;
+    if (loadvm) {
+        surface.flags |= QXL_SURF_FLAG_KEEP_DATA;
+    }
+
+    qxl->mode = QXL_MODE_NATIVE;
+    qxl->cmdflags = 0;
+    qxl->ssd.worker->create_primary_surface(qxl->ssd.worker, 0, &surface);
+
+    /* for local rendering */
+    qxl_render_resize(qxl);
+}
+
+static void qxl_destroy_primary(PCIQXLDevice *d)
+{
+    if (d->mode == QXL_MODE_UNDEFINED) {
+        return;
+    }
+
+    dprint(d, 1, "%s\n", __FUNCTION__);
+
+    d->mode = QXL_MODE_UNDEFINED;
+    d->ssd.worker->destroy_primary_surface(d->ssd.worker, 0);
+}
+
+static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm)
+{
+    pcibus_t start = d->pci.io_regions[QXL_RAM_RANGE_INDEX].addr;
+    pcibus_t end   = d->pci.io_regions[QXL_RAM_RANGE_INDEX].size + start;
+    QXLMode *mode = d->modes->modes + modenr;
+    uint64_t devmem = d->pci.io_regions[QXL_RAM_RANGE_INDEX].addr;
+    QXLMemSlot slot = {
+        .mem_start = start,
+        .mem_end = end
+    };
+    QXLSurfaceCreate surface = {
+        .width      = mode->x_res,
+        .height     = mode->y_res,
+        .stride     = -mode->x_res * 4,
+        .format     = SPICE_SURFACE_FMT_32_xRGB,
+        .flags      = loadvm ? QXL_SURF_FLAG_KEEP_DATA : 0,
+        .mouse_mode = true,
+        .mem        = devmem + d->shadow_rom.draw_area_offset,
+    };
+
+    dprint(d, 1, "%s: mode %d  [ %d x %d @ %d bpp devmem 0x%lx ]\n", __FUNCTION__,
+           modenr, mode->x_res, mode->y_res, mode->bits, devmem);
+    if (!loadvm) {
+        qxl_hard_reset(d, 0);
+    }
+
+    d->guest_slots[0].slot = slot;
+    qxl_add_memslot(d, 0, devmem);
+
+    d->guest_primary.surface = surface;
+    qxl_create_guest_primary(d, 0);
+
+    d->mode = QXL_MODE_COMPAT;
+    d->cmdflags = QXL_COMMAND_FLAG_COMPAT;
+#ifdef QXL_COMMAND_FLAG_COMPAT_16BPP /* new in spice 0.6.1 */
+    if (mode->bits == 16) {
+        d->cmdflags |= QXL_COMMAND_FLAG_COMPAT_16BPP;
+    }
+#endif
+    d->shadow_rom.mode = cpu_to_le32(modenr);
+    d->rom->mode = cpu_to_le32(modenr);
+    qxl_rom_set_dirty(d);
+}
+
+static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    PCIQXLDevice *d = opaque;
+    uint32_t io_port = addr - d->io_base;
+
+    switch (io_port) {
+    case QXL_IO_RESET:
+    case QXL_IO_SET_MODE:
+    case QXL_IO_MEMSLOT_ADD:
+    case QXL_IO_MEMSLOT_DEL:
+    case QXL_IO_CREATE_PRIMARY:
+        break;
+    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);
+        return;
+    }
+
+    switch (io_port) {
+    case QXL_IO_UPDATE_AREA:
+    {
+        QXLRect update = d->ram->update_area;
+        qemu_mutex_unlock_iothread();
+        d->ssd.worker->update_area(d->ssd.worker, d->ram->update_surface,
+                                   &update, NULL, 0, 0);
+        qemu_mutex_lock_iothread();
+        break;
+    }
+    case QXL_IO_NOTIFY_CMD:
+        d->ssd.worker->wakeup(d->ssd.worker);
+        break;
+    case QXL_IO_NOTIFY_CURSOR:
+        d->ssd.worker->wakeup(d->ssd.worker);
+        break;
+    case QXL_IO_UPDATE_IRQ:
+        qxl_set_irq(d);
+        break;
+    case QXL_IO_NOTIFY_OOM:
+        if (!SPICE_RING_IS_EMPTY(&d->ram->release_ring)) {
+            break;
+        }
+        pthread_yield();
+        if (!SPICE_RING_IS_EMPTY(&d->ram->release_ring)) {
+            break;
+        }
+        d->oom_running = 1;
+        d->ssd.worker->oom(d->ssd.worker);
+        d->oom_running = 0;
+        break;
+    case QXL_IO_SET_MODE:
+        dprint(d, 1, "QXL_SET_MODE %d\n", val);
+        qxl_set_mode(d, val, 0);
+        break;
+    case QXL_IO_LOG:
+        if (d->guestdebug) {
+            fprintf(stderr, "qxl/guest: %s", d->ram->log_buf);
+        }
+        break;
+    case QXL_IO_RESET:
+        dprint(d, 1, "QXL_IO_RESET\n");
+        qxl_hard_reset(d, 0);
+        break;
+    case QXL_IO_MEMSLOT_ADD:
+        PANIC_ON(val >= NUM_MEMSLOTS);
+        PANIC_ON(d->guest_slots[val].active);
+        d->guest_slots[val].slot = d->ram->mem_slot;
+        qxl_add_memslot(d, val, 0);
+        break;
+    case QXL_IO_MEMSLOT_DEL:
+        qxl_del_memslot(d, val);
+        break;
+    case QXL_IO_CREATE_PRIMARY:
+        PANIC_ON(val != 0);
+        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);
+        dprint(d, 1, "QXL_IO_DESTROY_PRIMARY\n");
+        qxl_destroy_primary(d);
+        break;
+    case QXL_IO_DESTROY_SURFACE_WAIT:
+        d->ssd.worker->destroy_surface_wait(d->ssd.worker, val);
+        break;
+    case QXL_IO_DESTROY_ALL_SURFACES:
+        d->ssd.worker->destroy_surfaces(d->ssd.worker);
+        break;
+    default:
+        fprintf(stderr, "%s: ioport=0x%x, abort()\n", __FUNCTION__, io_port);
+        abort();
+    }
+}
+
+static uint32_t ioport_read(void *opaque, uint32_t addr)
+{
+    PCIQXLDevice *d = opaque;
+
+    dprint(d, 1, "%s: unexpected\n", __FUNCTION__);
+    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 void pipe_read(void *opaque)
+{
+    PCIQXLDevice *d = opaque;
+    char dummy;
+    int len;
+
+    do {
+        len = read(d->pipe[0], &dummy, sizeof(dummy));
+    } while (len == sizeof(dummy));
+    qxl_set_irq(d);
+}
+
+/* called from spice server thread context only */
+static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
+{
+    uint32_t old_pending;
+    uint32_t le_events = cpu_to_le32(events);
+
+    assert(d->ssd.running);
+    old_pending = __sync_fetch_and_or(&d->ram->int_pending, le_events);
+    if ((old_pending & le_events) == le_events) {
+        return;
+    }
+    if (pthread_self() == d->main) {
+        qxl_set_irq(d);
+    } else {
+        if (write(d->pipe[1], d, 1) != 1) {
+            dprint(d, 1, "%s: write to pipe failed\n", __FUNCTION__);
+        }
+    }
+}
+
+static void init_pipe_signaling(PCIQXLDevice *d)
+{
+   if (pipe(d->pipe) < 0) {
+       dprint(d, 1, "%s: pipe creation failed\n", __FUNCTION__);
+       return;
+   }
+#ifdef CONFIG_IOTHREAD
+   fcntl(d->pipe[0], F_SETFL, O_NONBLOCK);
+#else
+   fcntl(d->pipe[0], F_SETFL, O_NONBLOCK /* | O_ASYNC */);
+#endif
+   fcntl(d->pipe[1], F_SETFL, O_NONBLOCK);
+   fcntl(d->pipe[0], F_SETOWN, getpid());
+
+   d->main = pthread_self();
+   qemu_set_fd_handler(d->pipe[0], pipe_read, NULL, d);
+}
+
+/* graphics console */
+
+static void qxl_hw_update(void *opaque)
+{
+    PCIQXLDevice *qxl = opaque;
+    VGACommonState *vga = &qxl->vga;
+
+    switch (qxl->mode) {
+    case QXL_MODE_VGA:
+        vga->update(vga);
+        break;
+    case QXL_MODE_COMPAT:
+    case QXL_MODE_NATIVE:
+        qxl_render_update(qxl);
+        break;
+    default:
+        break;
+    }
+}
+
+static void qxl_hw_invalidate(void *opaque)
+{
+    PCIQXLDevice *qxl = opaque;
+    VGACommonState *vga = &qxl->vga;
+
+    vga->invalidate(vga);
+}
+
+static void qxl_hw_screen_dump(void *opaque, const char *filename)
+{
+    PCIQXLDevice *qxl = opaque;
+    VGACommonState *vga = &qxl->vga;
+
+    switch (qxl->mode) {
+    case QXL_MODE_COMPAT:
+    case QXL_MODE_NATIVE:
+        qxl_render_update(qxl);
+        ppm_save(filename, qxl->ssd.ds->surface);
+        break;
+    case QXL_MODE_VGA:
+        vga->screen_dump(vga, filename);
+        break;
+    default:
+        break;
+    }
+}
+
+static void qxl_hw_text_update(void *opaque, console_ch_t *chardata)
+{
+    PCIQXLDevice *qxl = opaque;
+    VGACommonState *vga = &qxl->vga;
+
+    if (qxl->mode == QXL_MODE_VGA) {
+        vga->text_update(vga, chardata);
+        return;
+    }
+}
+
+static void qxl_vm_change_state_handler(void *opaque, int running, int reason)
+{
+    PCIQXLDevice *qxl = opaque;
+    qemu_spice_vm_change_state_handler(&qxl->ssd, running, reason);
+
+    if (!running && qxl->mode == QXL_MODE_NATIVE) {
+        /* dirty all vram (which holds surfaces) to make sure it is 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 addr = qxl->vram_offset;
+        qxl_set_dirty(addr, addr + qxl->vram_size);
+    }
+}
+
+/* display change listener */
+
+static void display_update(struct DisplayState *ds, int x, int y, int w, int h)
+{
+    if (qxl0->mode == QXL_MODE_VGA) {
+        qemu_spice_display_update(&qxl0->ssd, x, y, w, h);
+    }
+}
+
+static void display_resize(struct DisplayState *ds)
+{
+    if (qxl0->mode == QXL_MODE_VGA) {
+        qemu_spice_display_resize(&qxl0->ssd);
+    }
+}
+
+static void display_refresh(struct DisplayState *ds)
+{
+    if (qxl0->mode == QXL_MODE_VGA) {
+        qemu_spice_display_refresh(&qxl0->ssd);
+    }
+}
+
+static DisplayChangeListener display_listener = {
+    .dpy_update  = display_update,
+    .dpy_resize  = display_resize,
+    .dpy_refresh = display_refresh,
+};
+
+static int qxl_init_common(PCIQXLDevice *qxl)
+{
+    uint8_t* config = qxl->pci.config;
+    uint32_t pci_device_id;
+    uint32_t pci_device_rev;
+    uint32_t io_size;
+
+    qxl->mode = QXL_MODE_UNDEFINED;
+    qxl->generation = 1;
+    qxl->num_memslots = NUM_MEMSLOTS;
+    qxl->num_surfaces = NUM_SURFACES;
+
+    switch (qxl->revision) {
+    case 1: /* spice 0.4 -- qxl-1 */
+        pci_device_id  = QXL_DEVICE_ID_STABLE;
+        pci_device_rev = QXL_REVISION_STABLE_V04;
+        break;
+    case 2: /* spice 0.6 -- qxl-2 */
+        pci_device_id  = QXL_DEVICE_ID_STABLE;
+        pci_device_rev = QXL_REVISION_STABLE_V06;
+        break;
+    default: /* experimental */
+        pci_device_id  = QXL_DEVICE_ID_DEVEL;
+        pci_device_rev = 1;
+        break;
+    }
+
+    pci_config_set_vendor_id(config, REDHAT_PCI_VENDOR_ID);
+    pci_config_set_device_id(config, pci_device_id);
+    pci_set_byte(&config[PCI_REVISION_ID], pci_device_rev);
+    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);
+    init_qxl_rom(qxl);
+    init_qxl_ram(qxl);
+
+    if (qxl->vram_size < 16 * 1024 * 1024) {
+        qxl->vram_size = 16 * 1024 * 1024;
+    }
+    if (qxl->revision == 1) {
+        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);
+
+    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);
+
+    pci_register_bar(&qxl->pci, QXL_ROM_RANGE_INDEX,
+                     qxl->rom_size, PCI_BASE_ADDRESS_SPACE_MEMORY,
+                     qxl_map);
+
+    pci_register_bar(&qxl->pci, QXL_RAM_RANGE_INDEX,
+                     qxl->vga.vram_size, PCI_BASE_ADDRESS_SPACE_MEMORY,
+                     qxl_map);
+
+    pci_register_bar(&qxl->pci, QXL_VRAM_RANGE_INDEX, qxl->vram_size,
+                     PCI_BASE_ADDRESS_SPACE_MEMORY, qxl_map);
+
+    qxl->ssd.qxl.base.sif = &qxl_interface.base;
+    qxl->ssd.qxl.id = qxl->id;
+    qemu_spice_add_interface(&qxl->ssd.qxl.base);
+    qemu_add_vm_change_state_handler(qxl_vm_change_state_handler, qxl);
+
+    init_pipe_signaling(qxl);
+    qxl_reset_state(qxl);
+
+    return 0;
+}
+
+static int qxl_init_primary(PCIDevice *dev)
+{
+    PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev);
+    VGACommonState *vga = &qxl->vga;
+    ram_addr_t ram_size = msb_mask(qxl->vga.vram_size * 2 - 1);
+
+    qxl->id = 0;
+
+    if (ram_size < 32 * 1024 * 1024) {
+        ram_size = 32 * 1024 * 1024;
+    }
+    vga_common_init(vga, ram_size);
+    vga_init(vga);
+    register_ioport_write(0x3c0, 16, 1, qxl_vga_ioport_write, vga);
+    register_ioport_write(0x3b4,  2, 1, qxl_vga_ioport_write, vga);
+    register_ioport_write(0x3d4,  2, 1, qxl_vga_ioport_write, vga);
+    register_ioport_write(0x3ba,  1, 1, qxl_vga_ioport_write, vga);
+    register_ioport_write(0x3da,  1, 1, qxl_vga_ioport_write, vga);
+
+    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;
+    qxl->ssd.bufsize = (16 * 1024 * 1024);
+    qxl->ssd.buf = qemu_malloc(qxl->ssd.bufsize);
+
+    qxl0 = qxl;
+    register_displaychangelistener(vga->ds, &display_listener);
+
+    pci_config_set_class(dev->config, PCI_CLASS_DISPLAY_VGA);
+    return qxl_init_common(qxl);
+}
+
+static int qxl_init_secondary(PCIDevice *dev)
+{
+    static int device_id = 1;
+    PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev);
+    ram_addr_t ram_size = msb_mask(qxl->vga.vram_size * 2 - 1);
+
+    qxl->id = device_id++;
+
+    if (ram_size < 16 * 1024 * 1024) {
+        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);
+
+    pci_config_set_class(dev->config, PCI_CLASS_DISPLAY_OTHER);
+    return qxl_init_common(qxl);
+}
+
+static void qxl_pre_save(void *opaque)
+{
+    PCIQXLDevice* d = opaque;
+    uint8_t *ram_start = d->vga.vram_ptr;
+
+    dprint(d, 1, "%s:\n", __FUNCTION__);
+    if (d->last_release == NULL) {
+        d->last_release_offset = 0;
+    } else {
+        d->last_release_offset = (uint8_t *)d->last_release - ram_start;
+    }
+    assert(d->last_release_offset < d->vga.vram_size);
+}
+
+static int qxl_pre_load(void *opaque)
+{
+    PCIQXLDevice* d = opaque;
+
+    dprint(d, 1, "%s: start\n", __FUNCTION__);
+    qxl_hard_reset(d, 1);
+    qxl_exit_vga_mode(d);
+    dprint(d, 1, "%s: done\n", __FUNCTION__);
+    return 0;
+}
+
+static int qxl_post_load(void *opaque, int version)
+{
+    PCIQXLDevice* d = opaque;
+    uint8_t *ram_start = d->vga.vram_ptr;
+    QXLCommandExt *cmds;
+    int in, out, i, newmode;
+
+    dprint(d, 1, "%s: start\n", __FUNCTION__);
+
+    assert(d->last_release_offset < d->vga.vram_size);
+    if (d->last_release_offset == 0) {
+        d->last_release = NULL;
+    } else {
+        d->last_release = (QXLReleaseInfo *)(ram_start + d->last_release_offset);
+    }
+
+    d->modes = (QXLModes*)((uint8_t*)d->rom + d->rom->modes_offset);
+
+    dprint(d, 1, "%s: restore mode\n", __FUNCTION__);
+    newmode = d->mode;
+    d->mode = QXL_MODE_UNDEFINED;
+    switch (newmode) {
+    case QXL_MODE_UNDEFINED:
+        break;
+    case QXL_MODE_VGA:
+        qxl_enter_vga_mode(d);
+        break;
+    case QXL_MODE_NATIVE:
+        for (i = 0; i < NUM_MEMSLOTS; i++) {
+            if (!d->guest_slots[i].active) {
+                continue;
+            }
+            qxl_add_memslot(d, i, 0);
+        }
+        qxl_create_guest_primary(d, 1);
+
+        /* replay surface-create and cursor-set commands */
+        cmds = qemu_mallocz(sizeof(QXLCommandExt) * (NUM_SURFACES + 1));
+        for (in = 0, out = 0; in < NUM_SURFACES; in++) {
+            if (d->guest_surfaces.cmds[in] == 0) {
+                continue;
+            }
+            cmds[out].cmd.data = d->guest_surfaces.cmds[in];
+            cmds[out].cmd.type = QXL_CMD_SURFACE;
+            cmds[out].group_id = MEMSLOT_GROUP_GUEST;
+            out++;
+        }
+        cmds[out].cmd.data = d->guest_cursor;
+        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_free(cmds);
+
+        break;
+    case QXL_MODE_COMPAT:
+        qxl_set_mode(d, d->shadow_rom.mode, 1);
+        break;
+    }
+    dprint(d, 1, "%s: done\n", __FUNCTION__);
+
+    /* spice 0.4 compatibility -- accept but ignore */
+    qemu_free(d->worker_data);
+    d->worker_data = NULL;
+    d->worker_data_size = 0;
+
+    return 0;
+}
+
+#define QXL_SAVE_VERSION 20
+
+static bool qxl_test_worker_data(void *opaque, int version_id)
+{
+    PCIQXLDevice* d = opaque;
+
+    if (d->revision != 1) {
+        return false;
+    }
+    if (!d->worker_data_size) {
+        return false;
+    }
+    if (!d->worker_data) {
+        d->worker_data = qemu_malloc(d->worker_data_size);
+    }
+    return true;
+}
+
+static bool qxl_test_spice04(void *opaque, int version_id)
+{
+    PCIQXLDevice* d = opaque;
+    return d->revision == 1;
+}
+
+static bool qxl_test_spice06(void *opaque)
+{
+    PCIQXLDevice* d = opaque;
+    return d->revision > 1;
+}
+
+static VMStateDescription qxl_memslot = {
+    .name               = "qxl-memslot",
+    .version_id         = QXL_SAVE_VERSION,
+    .minimum_version_id = QXL_SAVE_VERSION,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT64(slot.mem_start, struct guest_slots),
+        VMSTATE_UINT64(slot.mem_end,   struct guest_slots),
+        VMSTATE_UINT32(active,         struct guest_slots),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static VMStateDescription qxl_surface = {
+    .name               = "qxl-surface",
+    .version_id         = QXL_SAVE_VERSION,
+    .minimum_version_id = QXL_SAVE_VERSION,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(width,      QXLSurfaceCreate),
+        VMSTATE_UINT32(height,     QXLSurfaceCreate),
+        VMSTATE_INT32(stride,      QXLSurfaceCreate),
+        VMSTATE_UINT32(format,     QXLSurfaceCreate),
+        VMSTATE_UINT32(position,   QXLSurfaceCreate),
+        VMSTATE_UINT32(mouse_mode, QXLSurfaceCreate),
+        VMSTATE_UINT32(flags,      QXLSurfaceCreate),
+        VMSTATE_UINT32(type,       QXLSurfaceCreate),
+        VMSTATE_UINT64(mem,        QXLSurfaceCreate),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static VMStateDescription qxl_vmstate_spice06 = {
+    .name               = "qxl/spice06",
+    .version_id         = QXL_SAVE_VERSION,
+    .minimum_version_id = QXL_SAVE_VERSION,
+    .fields = (VMStateField []) {
+        VMSTATE_INT32_EQUAL(num_memslots, PCIQXLDevice),
+        VMSTATE_STRUCT_ARRAY(guest_slots, PCIQXLDevice, NUM_MEMSLOTS, 0,
+                             qxl_memslot, struct guest_slots),
+        VMSTATE_STRUCT(guest_primary.surface, PCIQXLDevice, 0,
+                       qxl_surface, QXLSurfaceCreate),
+        VMSTATE_INT32_EQUAL(num_surfaces, PCIQXLDevice),
+        VMSTATE_ARRAY(guest_surfaces.cmds, PCIQXLDevice, NUM_SURFACES, 0,
+                      vmstate_info_uint64, uint64_t),
+        VMSTATE_UINT64(guest_cursor, PCIQXLDevice),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+static VMStateDescription qxl_vmstate = {
+    .name               = "qxl",
+    .version_id         = QXL_SAVE_VERSION,
+    .minimum_version_id = QXL_SAVE_VERSION,
+    .pre_save           = qxl_pre_save,
+    .pre_load           = qxl_pre_load,
+    .post_load          = qxl_post_load,
+    .fields = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(pci, PCIQXLDevice),
+        VMSTATE_STRUCT(vga, PCIQXLDevice, 0, vmstate_vga_common, VGACommonState),
+        VMSTATE_UINT32(shadow_rom.mode, PCIQXLDevice),
+        VMSTATE_UINT32(num_free_res, PCIQXLDevice),
+        VMSTATE_UINT32(last_release_offset, PCIQXLDevice),
+        VMSTATE_UINT32(mode, PCIQXLDevice),
+        VMSTATE_UINT32(ssd.unique, PCIQXLDevice),
+
+        /* spice 0.4 sends/expects them */
+        VMSTATE_VBUFFER_UINT32(vga.vram_ptr, PCIQXLDevice, 0, qxl_test_spice04, 0,
+                               vga.vram_size),
+        VMSTATE_UINT32_TEST(worker_data_size, PCIQXLDevice, qxl_test_spice04),
+        VMSTATE_VBUFFER_UINT32(worker_data, PCIQXLDevice, 0, qxl_test_worker_data, 0,
+                               worker_data_size),
+
+        VMSTATE_END_OF_LIST()
+    },
+    .subsections = (VMStateSubsection[]) {
+        {
+            /* additional spice 0.6 state */
+            .vmsd   = &qxl_vmstate_spice06,
+            .needed = qxl_test_spice06,
+        },{
+            /* end of list */
+        },
+    },
+};
+
+static PCIDeviceInfo qxl_info_primary = {
+    .qdev.name    = "qxl-vga",
+    .qdev.desc    = "Spice QXL GPU (primary, vga compatible)",
+    .qdev.size    = sizeof(PCIQXLDevice),
+    .qdev.reset   = qxl_reset_handler,
+    .qdev.vmsd    = &qxl_vmstate,
+    .init         = qxl_init_primary,
+    .config_write = qxl_write_config,
+    .romfile      = "vgabios-qxl.bin",
+    .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("debug", PCIQXLDevice, debug, 0),
+        DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0),
+        DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static PCIDeviceInfo qxl_info_secondary = {
+    .qdev.name    = "qxl",
+    .qdev.desc    = "Spice QXL GPU (secondary)",
+    .qdev.size    = sizeof(PCIQXLDevice),
+    .qdev.reset   = qxl_reset_handler,
+    .qdev.vmsd    = &qxl_vmstate,
+    .init         = qxl_init_secondary,
+    .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("debug", PCIQXLDevice, debug, 0),
+        DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0),
+        DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void qxl_register(void)
+{
+    pci_qdev_register(&qxl_info_primary);
+    pci_qdev_register(&qxl_info_secondary);
+}
+
+device_init(qxl_register);
diff --git a/hw/qxl.h b/hw/qxl.h
new file mode 100644
index 0000000..98e11ce
--- /dev/null
+++ b/hw/qxl.h
@@ -0,0 +1,112 @@
+#include "qemu-common.h"
+
+#include "console.h"
+#include "hw.h"
+#include "pci.h"
+#include "vga_int.h"
+
+#include "ui/qemu-spice.h"
+#include "ui/spice-display.h"
+
+enum qxl_mode {
+    QXL_MODE_UNDEFINED,
+    QXL_MODE_VGA,
+    QXL_MODE_COMPAT, /* spice 0.4.x */
+    QXL_MODE_NATIVE,
+};
+
+typedef struct PCIQXLDevice {
+    PCIDevice          pci;
+    SimpleSpiceDisplay ssd;
+    int                id;
+    uint32_t           debug;
+    uint32_t           guestdebug;
+    uint32_t           cmdlog;
+    enum qxl_mode      mode;
+    uint32_t           cmdflags;
+    int                generation;
+    uint32_t           revision;
+
+    int32_t            num_memslots;
+    int32_t            num_surfaces;
+
+    struct guest_slots {
+        QXLMemSlot     slot;
+        void           *ptr;
+        uint64_t       size;
+        uint64_t       delta;
+        uint32_t       active;
+    } guest_slots[NUM_MEMSLOTS];
+
+    struct guest_primary {
+        QXLSurfaceCreate surface;
+        uint32_t       commands;
+        uint32_t       resized;
+        int32_t        stride;
+        uint32_t       bits_pp;
+        uint32_t       bytes_pp;
+        uint8_t        *data, *flipped;
+    } guest_primary;
+
+    struct surfaces {
+        QXLPHYSICAL    cmds[NUM_SURFACES];
+        uint32_t       count;
+        uint32_t       max;
+    } guest_surfaces;
+    QXLPHYSICAL        guest_cursor;
+
+    /* thread signaling */
+    pthread_t          main;
+    int                pipe[2];
+
+    /* ram pci bar */
+    QXLRam             *ram;
+    VGACommonState     vga;
+    uint32_t           num_free_res;
+    QXLReleaseInfo     *last_release;
+    uint32_t           last_release_offset;
+    uint32_t           oom_running;
+
+    /* rom pci bar */
+    QXLRom             shadow_rom;
+    QXLRom             *rom;
+    QXLModes           *modes;
+    uint32_t           rom_size;
+    uint64_t           rom_offset;
+
+    /* vram pci bar */
+    uint32_t           vram_size;
+    uint64_t           vram_offset;
+
+    /* io bar */
+    uint32_t           io_base;
+
+    /* spice 0.4 loadvm compatibility */
+    void               *worker_data;
+    uint32_t           worker_data_size;
+} PCIQXLDevice;
+
+#define PANIC_ON(x) if ((x)) {                         \
+    printf("%s: PANIC %s failed\n", __FUNCTION__, #x); \
+    exit(-1);                                          \
+}
+
+#define dprint(_qxl, _level, _fmt, ...)                                 \
+    do {                                                                \
+        if (_qxl->debug >= _level) {                                    \
+            fprintf(stderr, "qxl-%d: ", _qxl->id);                      \
+            fprintf(stderr, _fmt, ## __VA_ARGS__);                      \
+        }                                                               \
+    } while (0)
+
+/* qxl.c */
+void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
+
+/* 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);
+
+/* qxl-render.c */
+void qxl_render_resize(PCIQXLDevice *qxl);
+void qxl_render_update(PCIQXLDevice *qxl);
+void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext);
diff --git a/hw/vga_int.h b/hw/vga_int.h
index bc1327f..1067f2c 100644
--- a/hw/vga_int.h
+++ b/hw/vga_int.h
@@ -106,7 +106,7 @@ typedef void (* vga_update_retrace_info_fn)(struct VGACommonState *s);
 typedef struct VGACommonState {
     uint8_t *vram_ptr;
     ram_addr_t vram_offset;
-    unsigned int vram_size;
+    uint32_t vram_size;
     uint32_t lfb_addr;
     uint32_t lfb_end;
     uint32_t map_addr;
diff --git a/qemu-options.hx b/qemu-options.hx
index 4d99a58..fd73210 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -751,7 +751,7 @@ Rotate graphical output 90 deg left (only PXA LCD).
 ETEXI
 
 DEF("vga", HAS_ARG, QEMU_OPTION_vga,
-    "-vga [std|cirrus|vmware|xenfb|none]\n"
+    "-vga [std|cirrus|vmware|qxl|xenfb|none]\n"
     "                select video card type\n", QEMU_ARCH_ALL)
 STEXI
 @item -vga @var{type}
@@ -772,6 +772,10 @@ this option.
 VMWare SVGA-II compatible adapter. Use it if you have sufficiently
 recent XFree86/XOrg server or Windows guest with a driver for this
 card.
+ at item qxl
+QXL paravirtual graphic card.  It is VGA compatible (including VESA
+2.0 VBE support).  Works best with qxl guest drivers installed though.
+Recommended choice when using the spice protocol.
 @item none
 Disable VGA card.
 @end table
diff --git a/sysemu.h b/sysemu.h
index b81a70e..d9b445b 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -102,7 +102,7 @@ extern int incoming_expected;
 extern int bios_size;
 
 typedef enum {
-    VGA_NONE, VGA_STD, VGA_CIRRUS, VGA_VMWARE, VGA_XENFB
+    VGA_NONE, VGA_STD, VGA_CIRRUS, VGA_VMWARE, VGA_XENFB, VGA_QXL,
 } VGAInterfaceType;
 
 extern int vga_interface_type;
@@ -110,6 +110,7 @@ extern int vga_interface_type;
 #define std_vga_enabled (vga_interface_type == VGA_STD)
 #define xenfb_enabled (vga_interface_type == VGA_XENFB)
 #define vmsvga_enabled (vga_interface_type == VGA_VMWARE)
+#define qxl_enabled (vga_interface_type == VGA_QXL)
 
 extern int graphic_width;
 extern int graphic_height;
diff --git a/ui/spice-core.c b/ui/spice-core.c
index d13bdc2..b7fa031 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -370,6 +370,21 @@ void qemu_spice_init(void)
 
 int qemu_spice_add_interface(SpiceBaseInstance *sin)
 {
+    if (!spice_server) {
+        if (QTAILQ_FIRST(&qemu_spice_opts.head) != NULL) {
+            fprintf(stderr, "Oops: spice configured but not active\n");
+            exit(1);
+        }
+        /*
+         * Create a spice server instance.
+         * It does *not* listen on the network.
+         * It handles QXL local rendering only.
+         *
+         * With a command line like '-vnc :0 -vga qxl' you'll end up here.
+         */
+        spice_server = spice_server_new();
+        spice_server_init(spice_server, &core_interface);
+    }
     return spice_server_add_interface(spice_server, sin);
 }
 
diff --git a/vl.c b/vl.c
index 2cd263e..e3f79e0 100644
--- a/vl.c
+++ b/vl.c
@@ -1411,6 +1411,8 @@ static void select_vgahw (const char *p)
         vga_interface_type = VGA_VMWARE;
     } else if (strstart(p, "xenfb", &opts)) {
         vga_interface_type = VGA_XENFB;
+    } else if (strstart(p, "qxl", &opts)) {
+        vga_interface_type = VGA_QXL;
     } else if (!strstart(p, "none", &opts)) {
     invalid_vga:
         fprintf(stderr, "Unknown vga type: %s\n", p);
@@ -2945,7 +2947,7 @@ int main(int argc, char **argv, char **envp)
         }
     }
 #ifdef CONFIG_SPICE
-    if (using_spice) {
+    if (using_spice && !qxl_enabled) {
         qemu_spice_display_init(ds);
     }
 #endif
commit 7943a2fac78b1b865093923bf1bdb08ae8664b3d
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Nov 30 11:54:33 2010 +0100

    spice: add qxl vgabios binary.
    
    Just compiled from vgabios git repo @ git.qemu.org,
    copyed over and committed.  Also added to the list
    of blobs in the Makefile.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/Makefile b/Makefile
index c80566c..6d601ee 100644
--- a/Makefile
+++ b/Makefile
@@ -205,7 +205,7 @@ common  de-ch  es     fo  fr-ca  hu     ja  mk  nl-be      pt  sl     tr
 
 ifdef INSTALL_BLOBS
 BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin \
-vgabios-stdvga.bin vgabios-vmware.bin \
+vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin \
 ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc \
 gpxe-eepro100-80861209.rom \
 pxe-e1000.bin \
diff --git a/pc-bios/vgabios-qxl.bin b/pc-bios/vgabios-qxl.bin
new file mode 100644
index 0000000..3156c6e
Binary files /dev/null and b/pc-bios/vgabios-qxl.bin differ
commit 513691b7ff20262efe9aafb85c8dd4615588ad48
Author: Michael S. Tsirkin <mst at redhat.com>
Date:   Wed Dec 8 17:46:28 2010 +0900

    pci/aer: factor out common code
    
    Same logic is used to assert interrupts
    and send msix messages, so add a static functin for this.
    
    Signed-off-by: Michael S. Tsirkin <mst at redhat.com>

diff --git a/hw/pcie_aer.c b/hw/pcie_aer.c
index f24784a..cb97a95 100644
--- a/hw/pcie_aer.c
+++ b/hw/pcie_aer.c
@@ -273,6 +273,17 @@ static uint32_t pcie_aer_status_to_cmd(uint32_t status)
     return cmd;
 }
 
+static void pcie_aer_root_notify(PCIDevice *dev)
+{
+    if (msix_enabled(dev)) {
+        msix_notify(dev, pcie_aer_root_get_vector(dev));
+    } else if (msi_enabled(dev)) {
+        msi_notify(dev, pcie_aer_root_get_vector(dev));
+    } else {
+        qemu_set_irq(dev->irq[dev->exp.aer_intx], 1);
+    }
+}
+
 /*
  * 6.2.6 Error Message Control
  * Figure 6-3
@@ -344,13 +355,7 @@ static void pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg)
         return;
     }
 
-    if (msix_enabled(dev)) {
-        msix_notify(dev, pcie_aer_root_get_vector(dev));
-    } else if (msi_enabled(dev)) {
-        msi_notify(dev, pcie_aer_root_get_vector(dev));
-    } else {
-        qemu_set_irq(dev->irq[dev->exp.aer_intx], 1);
-    }
+    pcie_aer_root_notify(dev);
 }
 
 /*
@@ -760,13 +765,7 @@ void pcie_aer_root_write_config(PCIDevice *dev,
         return;
     }
 
-    if (msix_enabled(dev)) {
-        msix_notify(dev, pcie_aer_root_get_vector(dev));
-    } else if (msi_enabled(dev)) {
-        msi_notify(dev, pcie_aer_root_get_vector(dev));
-    } else {
-        abort();
-    }
+    pcie_aer_root_notify(dev);
 }
 
 static const VMStateDescription vmstate_pcie_aer_err = {
commit 5f47c187d992d5147397ddd5323c732d3d39cb8f
Author: Michael S. Tsirkin <mst at redhat.com>
Date:   Wed Dec 8 17:46:27 2010 +0900

    pci/aer: remove dead code
    
    Remove some unused variables and return values.
    
    Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
    Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>

diff --git a/hw/pcie_aer.c b/hw/pcie_aer.c
index 04b0f45..f24784a 100644
--- a/hw/pcie_aer.c
+++ b/hw/pcie_aer.c
@@ -274,29 +274,21 @@ static uint32_t pcie_aer_status_to_cmd(uint32_t status)
 }
 
 /*
- * return value:
- * true: error message is sent up
- * false: error message is masked
- *
  * 6.2.6 Error Message Control
  * Figure 6-3
  * root port part
  */
-static bool pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg)
+static void pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg)
 {
-    bool msg_sent;
     uint16_t cmd;
     uint8_t *aer_cap;
     uint32_t root_cmd;
     uint32_t root_status, prev_status;
-    bool msi_trigger;
 
-    msg_sent = false;
     cmd = pci_get_word(dev->config + PCI_COMMAND);
     aer_cap = dev->config + dev->exp.aer_cap;
     root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND);
     prev_status = root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS);
-    msi_trigger = false;
 
     if (cmd & PCI_COMMAND_SERR) {
         /* System Error.
@@ -315,25 +307,14 @@ static bool pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg)
         if (root_status & PCI_ERR_ROOT_COR_RCV) {
             root_status |= PCI_ERR_ROOT_MULTI_COR_RCV;
         } else {
-            if (root_cmd & PCI_ERR_ROOT_CMD_COR_EN) {
-                msi_trigger = true;
-            }
             pci_set_word(aer_cap + PCI_ERR_ROOT_COR_SRC, msg->source_id);
         }
         root_status |= PCI_ERR_ROOT_COR_RCV;
         break;
     case PCI_ERR_ROOT_CMD_NONFATAL_EN:
-        if (!(root_status & PCI_ERR_ROOT_NONFATAL_RCV) &&
-            root_cmd & PCI_ERR_ROOT_CMD_NONFATAL_EN) {
-            msi_trigger = true;
-        }
         root_status |= PCI_ERR_ROOT_NONFATAL_RCV;
         break;
     case PCI_ERR_ROOT_CMD_FATAL_EN:
-        if (!(root_status & PCI_ERR_ROOT_FATAL_RCV) &&
-            root_cmd & PCI_ERR_ROOT_CMD_FATAL_EN) {
-            msi_trigger = true;
-        }
         if (!(root_status & PCI_ERR_ROOT_UNCOR_RCV)) {
             root_status |= PCI_ERR_ROOT_FIRST_FATAL;
         }
@@ -360,10 +341,9 @@ static bool pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg)
     if (!(root_cmd & msg->severity) ||
         (pcie_aer_status_to_cmd(prev_status) & root_cmd)) {
         /* Condition is not being set or was already true so nothing to do. */
-        return msg_sent;
+        return;
     }
 
-    msg_sent = true;
     if (msix_enabled(dev)) {
         msix_notify(dev, pcie_aer_root_get_vector(dev));
     } else if (msi_enabled(dev)) {
@@ -371,7 +351,6 @@ static bool pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg)
     } else {
         qemu_set_irq(dev->irq[dev->exp.aer_intx], 1);
     }
-    return msg_sent;
 }
 
 /*
commit 2b3cb353e7af7a90eec22ba9720dcef2a80c7f6f
Author: Michael S. Tsirkin <mst at redhat.com>
Date:   Wed Dec 8 17:46:26 2010 +0900

    pci/aer: fix interrupt on config write
    
    config write handling for aer seems broken:
    For example, it won't clear a level interrupt
    when command register is set to 0.
    
    Make it match the spec: level should equal
    the logical or of enabled bits, msi only
    be sent when the logical or changes.
    
    Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
    Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>

diff --git a/hw/pcie_aer.c b/hw/pcie_aer.c
index 9505c93..04b0f45 100644
--- a/hw/pcie_aer.c
+++ b/hw/pcie_aer.c
@@ -762,43 +762,31 @@ void pcie_aer_root_reset(PCIDevice *dev)
      */
 }
 
-static bool pcie_aer_root_does_trigger(uint32_t cmd, uint32_t status)
-{
-    return
-        ((cmd & PCI_ERR_ROOT_CMD_COR_EN) && (status & PCI_ERR_ROOT_COR_RCV)) ||
-        ((cmd & PCI_ERR_ROOT_CMD_NONFATAL_EN) &&
-         (status & PCI_ERR_ROOT_NONFATAL_RCV)) ||
-        ((cmd & PCI_ERR_ROOT_CMD_FATAL_EN) &&
-         (status & PCI_ERR_ROOT_FATAL_RCV));
-}
-
 void pcie_aer_root_write_config(PCIDevice *dev,
                                 uint32_t addr, uint32_t val, int len,
                                 uint32_t root_cmd_prev)
 {
     uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
-
-    /* root command register */
+    uint32_t root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS);
+    uint32_t enabled_cmd = pcie_aer_status_to_cmd(root_status);
     uint32_t root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND);
-    if (root_cmd & PCI_ERR_ROOT_CMD_EN_MASK) {
-        /* 6.2.4.1.2 Interrupt Generation */
+    /* 6.2.4.1.2 Interrupt Generation */
+    if (!msix_enabled(dev) && !msi_enabled(dev)) {
+        qemu_set_irq(dev->irq[dev->exp.aer_intx], !!(root_cmd & enabled_cmd));
+        return;
+    }
 
-        /* 0 -> 1 */
-        uint32_t root_cmd_set = ~root_cmd_prev & root_cmd;
-        uint32_t root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS);
-        bool trigger = pcie_aer_root_does_trigger(root_cmd_set, root_status);
+    if ((root_cmd_prev & enabled_cmd) || !(root_cmd & enabled_cmd)) {
+        /* Send MSI on transition from false to true. */
+        return;
+    }
 
-        if (msix_enabled(dev)) {
-            if (trigger) {
-                msix_notify(dev, pcie_aer_root_get_vector(dev));
-            }
-        } else if (msi_enabled(dev)) {
-            if (trigger) {
-                msi_notify(dev, pcie_aer_root_get_vector(dev));
-            }
-        } else {
-            qemu_set_irq(dev->irq[dev->exp.aer_intx], trigger);
-        }
+    if (msix_enabled(dev)) {
+        msix_notify(dev, pcie_aer_root_get_vector(dev));
+    } else if (msi_enabled(dev)) {
+        msi_notify(dev, pcie_aer_root_get_vector(dev));
+    } else {
+        abort();
     }
 }
 
commit c3f33667a64a6de0b92106c862247d97d81490ef
Author: Michael S. Tsirkin <mst at redhat.com>
Date:   Wed Dec 8 17:46:25 2010 +0900

    pci/aer: fix error injection
    
    Fix the injection logic upon aer message to follow 6.2.4.1.2 more
    closely: specifically only send an msi interrupt when the logical or of
    the enabled bits changed, not when a bit which was previously clear
    becomes set.
    
    Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
    Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>

diff --git a/hw/pcie_aer.c b/hw/pcie_aer.c
index dac27c3..9505c93 100644
--- a/hw/pcie_aer.c
+++ b/hw/pcie_aer.c
@@ -257,6 +257,22 @@ static unsigned int pcie_aer_root_get_vector(PCIDevice *dev)
     return (root_status & PCI_ERR_ROOT_IRQ) >> PCI_ERR_ROOT_IRQ_SHIFT;
 }
 
+/* Given a status register, get corresponding bits in the command register */
+static uint32_t pcie_aer_status_to_cmd(uint32_t status)
+{
+    uint32_t cmd = 0;
+    if (status & PCI_ERR_ROOT_COR_RCV) {
+        cmd |= PCI_ERR_ROOT_CMD_COR_EN;
+    }
+    if (status & PCI_ERR_ROOT_NONFATAL_RCV) {
+        cmd |= PCI_ERR_ROOT_CMD_NONFATAL_EN;
+    }
+    if (status & PCI_ERR_ROOT_FATAL_RCV) {
+        cmd |= PCI_ERR_ROOT_CMD_FATAL_EN;
+    }
+    return cmd;
+}
+
 /*
  * return value:
  * true: error message is sent up
@@ -272,14 +288,14 @@ static bool pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg)
     uint16_t cmd;
     uint8_t *aer_cap;
     uint32_t root_cmd;
-    uint32_t root_status;
+    uint32_t root_status, prev_status;
     bool msi_trigger;
 
     msg_sent = false;
     cmd = pci_get_word(dev->config + PCI_COMMAND);
     aer_cap = dev->config + dev->exp.aer_cap;
     root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND);
-    root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS);
+    prev_status = root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS);
     msi_trigger = false;
 
     if (cmd & PCI_COMMAND_SERR) {
@@ -337,20 +353,23 @@ static bool pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg)
     }
     pci_set_long(aer_cap + PCI_ERR_ROOT_STATUS, root_status);
 
-    if (root_cmd & msg->severity) {
-        /* 6.2.4.1.2 Interrupt Generation */
-        if (msix_enabled(dev)) {
-            if (msi_trigger) {
-                msix_notify(dev, pcie_aer_root_get_vector(dev));
-            }
-        } else if (msi_enabled(dev)) {
-            if (msi_trigger) {
-                msi_notify(dev, pcie_aer_root_get_vector(dev));
-            }
-        } else {
-            qemu_set_irq(dev->irq[dev->exp.aer_intx], 1);
-        }
-        msg_sent = true;
+    /* 6.2.4.1.2 Interrupt Generation */
+    /* All the above did was set some bits in the status register.
+     * Specifically these that match message severity.
+     * The below code relies on this fact. */
+    if (!(root_cmd & msg->severity) ||
+        (pcie_aer_status_to_cmd(prev_status) & root_cmd)) {
+        /* Condition is not being set or was already true so nothing to do. */
+        return msg_sent;
+    }
+
+    msg_sent = true;
+    if (msix_enabled(dev)) {
+        msix_notify(dev, pcie_aer_root_get_vector(dev));
+    } else if (msi_enabled(dev)) {
+        msi_notify(dev, pcie_aer_root_get_vector(dev));
+    } else {
+        qemu_set_irq(dev->irq[dev->exp.aer_intx], 1);
     }
     return msg_sent;
 }
commit 624c716cc576ec5e6bed50da3deb45aa9537cacd
Author: Michael S. Tsirkin <mst at redhat.com>
Date:   Wed Dec 8 17:46:24 2010 +0900

    Makefile: make msix/msi depend on CONFIG_PCI
    
    Possible now that pci is not depending on these.
    
    Signed-off-by: Michael S. Tsirkin <mst at redhat.com>

diff --git a/Makefile.objs b/Makefile.objs
index 04625eb..d1e63ce 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -168,7 +168,8 @@ hw-obj-$(CONFIG_VIRTIO) += virtio.o virtio-console.o
 hw-obj-y += fw_cfg.o
 # FIXME: Core PCI code and its direct dependencies are required by the
 # QMP query-pci command.
-hw-obj-y += pci.o pci_bridge.o msix.o msi.o
+hw-obj-y += pci.o pci_bridge.o
+hw-obj-$(CONFIG_PCI) += msix.o msi.o
 hw-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o
 hw-obj-$(CONFIG_PCI) += ioh3420.o xio3130_upstream.o xio3130_downstream.o
 hw-obj-y += watchdog.o
commit 4a9dd6658268a942a8ea230f950a951229355cbb
Author: Michael S. Tsirkin <mst at redhat.com>
Date:   Wed Dec 8 17:46:23 2010 +0900

    pci: untangle pci/msi dependency
    
    msi depends on pci but pci should not depend on msi.
    The only dependency we have is a recent addition
    of pci_msi_ functions, IMO they add little enough to
    open-code in the small number of users.
    
    Follow-up patches add more cleanups.
    
    Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
    Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>

diff --git a/hw/pci.c b/hw/pci.c
index ca878e8..254647b 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -25,8 +25,6 @@
 #include "pci.h"
 #include "pci_bridge.h"
 #include "pci_internals.h"
-#include "msix.h"
-#include "msi.h"
 #include "monitor.h"
 #include "net.h"
 #include "sysemu.h"
@@ -1099,23 +1097,6 @@ static void pci_set_irq(void *opaque, int irq_num, int level)
     pci_change_irq_level(pci_dev, irq_num, change);
 }
 
-bool pci_msi_enabled(PCIDevice *dev)
-{
-    return msix_enabled(dev) || msi_enabled(dev);
-}
-
-void pci_msi_notify(PCIDevice *dev, unsigned int vector)
-{
-    if (msix_enabled(dev)) {
-        msix_notify(dev, vector);
-    } else if (msi_enabled(dev)) {
-        msi_notify(dev, vector);
-    } else {
-        /* MSI/MSI-X must be enabled */
-        abort();
-    }
-}
-
 /***********************************************************/
 /* monitor info on PCI */
 
diff --git a/hw/pci.h b/hw/pci.h
index 099c251..aa3afe9 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -261,9 +261,6 @@ void do_pci_info_print(Monitor *mon, const QObject *data);
 void do_pci_info(Monitor *mon, QObject **ret_data);
 void pci_bridge_update_mappings(PCIBus *b);
 
-bool pci_msi_enabled(PCIDevice *dev);
-void pci_msi_notify(PCIDevice *dev, unsigned int vector);
-
 static inline void
 pci_set_byte(uint8_t *config, uint8_t val)
 {
diff --git a/hw/pcie.c b/hw/pcie.c
index f461c1c..d1f0086 100644
--- a/hw/pcie.c
+++ b/hw/pcie.c
@@ -167,10 +167,12 @@ static void hotplug_event_notify(PCIDevice *dev)
      * The Port may optionally send an MSI when there are hot-plug events that
      * occur while interrupt generation is disabled, and interrupt generation is
      * subsequently enabled. */
-    if (!pci_msi_enabled(dev)) {
+    if (msix_enabled(dev)) {
+        msix_notify(dev, pcie_cap_flags_get_vector(dev));
+    } else if (msi_enabled(dev)) {
+        msi_notify(dev, pcie_cap_flags_get_vector(dev));
+    } else {
         qemu_set_irq(dev->irq[dev->exp.hpev_intx], dev->exp.hpev_notified);
-    } else if (dev->exp.hpev_notified) {
-        pci_msi_notify(dev, pcie_cap_flags_get_vector(dev));
     }
 }
 
diff --git a/hw/pcie_aer.c b/hw/pcie_aer.c
index 47d6400..dac27c3 100644
--- a/hw/pcie_aer.c
+++ b/hw/pcie_aer.c
@@ -339,9 +339,13 @@ static bool pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg)
 
     if (root_cmd & msg->severity) {
         /* 6.2.4.1.2 Interrupt Generation */
-        if (pci_msi_enabled(dev)) {
+        if (msix_enabled(dev)) {
             if (msi_trigger) {
-                pci_msi_notify(dev, pcie_aer_root_get_vector(dev));
+                msix_notify(dev, pcie_aer_root_get_vector(dev));
+            }
+        } else if (msi_enabled(dev)) {
+            if (msi_trigger) {
+                msi_notify(dev, pcie_aer_root_get_vector(dev));
             }
         } else {
             qemu_set_irq(dev->irq[dev->exp.aer_intx], 1);
@@ -761,16 +765,20 @@ void pcie_aer_root_write_config(PCIDevice *dev,
         /* 6.2.4.1.2 Interrupt Generation */
 
         /* 0 -> 1 */
-        uint32_t root_cmd_set = (root_cmd_prev ^ root_cmd) & root_cmd;
+        uint32_t root_cmd_set = ~root_cmd_prev & root_cmd;
         uint32_t root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS);
+        bool trigger = pcie_aer_root_does_trigger(root_cmd_set, root_status);
 
-        if (pci_msi_enabled(dev)) {
-            if (pcie_aer_root_does_trigger(root_cmd_set, root_status)) {
-                pci_msi_notify(dev, pcie_aer_root_get_vector(dev));
+        if (msix_enabled(dev)) {
+            if (trigger) {
+                msix_notify(dev, pcie_aer_root_get_vector(dev));
+            }
+        } else if (msi_enabled(dev)) {
+            if (trigger) {
+                msi_notify(dev, pcie_aer_root_get_vector(dev));
             }
         } else {
-            int int_level = pcie_aer_root_does_trigger(root_cmd, root_status);
-            qemu_set_irq(dev->irq[dev->exp.aer_intx], int_level);
+            qemu_set_irq(dev->irq[dev->exp.aer_intx], trigger);
         }
     }
 }
commit b1aeb92666d2fde413c34578b3b42bbfe5f2a506
Author: Isaku Yamahata <yamahata at valinux.co.jp>
Date:   Fri Nov 26 21:01:41 2010 +0900

    pci: make command SERR bit writable
    
    pcie aer needs SERR bit to be writable, and the PCI spec requires
    this as well.  For compatibility, introduce compat global property
    command_serr_enable and make this bit readonly for a pre 0.14 pc
    machine.
    
    Signed-off-by: Isaku Yamahata <yamahata at valinux.co.jp>
    Signed-off-by: Michael S. Tsirkin <mst at redhat.com>

diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 7d29d43..a2fb554 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -217,6 +217,14 @@ static QEMUMachine pc_machine = {
     .desc = "Standard PC",
     .init = pc_init_pci,
     .max_cpus = 255,
+    .compat_props = (GlobalProperty[]) {
+        {
+            .driver   = "PCI",
+            .property = "command_serr_enable",
+            .value    = "off",
+        },
+        { /* end of list */ }
+    },
     .is_default = 1,
 };
 
@@ -265,6 +273,10 @@ static QEMUMachine pc_machine_v0_12 = {
             .driver   = "vmware-svga",
             .property = "rombar",
             .value    = stringify(0),
+        },{
+            .driver   = "PCI",
+            .property = "command_serr_enable",
+            .value    = "off",
         },
         { /* end of list */ }
     }
@@ -300,6 +312,10 @@ static QEMUMachine pc_machine_v0_11 = {
             .driver   = "PCI",
             .property = "rombar",
             .value    = stringify(0),
+        },{
+            .driver   = "PCI",
+            .property = "command_serr_enable",
+            .value    = "off",
         },
         { /* end of list */ }
     }
@@ -347,6 +363,10 @@ static QEMUMachine pc_machine_v0_10 = {
             .driver   = "PCI",
             .property = "rombar",
             .value    = stringify(0),
+        },{
+            .driver   = "PCI",
+            .property = "command_serr_enable",
+            .value    = "off",
         },
         { /* end of list */ }
     },
diff --git a/hw/pci.c b/hw/pci.c
index 0c15b13..ca878e8 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -57,6 +57,8 @@ struct BusInfo pci_bus_info = {
         DEFINE_PROP_UINT32("rombar",  PCIDevice, rom_bar, 1),
         DEFINE_PROP_BIT("multifunction", PCIDevice, cap_present,
                         QEMU_PCI_CAP_MULTIFUNCTION_BITNR, false),
+        DEFINE_PROP_BIT("command_serr_enable", PCIDevice, cap_present,
+                        QEMU_PCI_CAP_SERR_BITNR, true),
         DEFINE_PROP_END_OF_LIST()
     }
 };
@@ -568,6 +570,9 @@ static void pci_init_wmask(PCIDevice *dev)
     pci_set_word(dev->wmask + PCI_COMMAND,
                  PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
                  PCI_COMMAND_INTX_DISABLE);
+    if (dev->cap_present & QEMU_PCI_CAP_SERR) {
+        pci_word_test_and_set_mask(dev->wmask + PCI_COMMAND, PCI_COMMAND_SERR);
+    }
 
     memset(dev->wmask + PCI_CONFIG_HEADER_SIZE, 0xff,
            config_size - PCI_CONFIG_HEADER_SIZE);
diff --git a/hw/pci.h b/hw/pci.h
index 89f7b76..099c251 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -118,6 +118,10 @@ enum {
     /* multifunction capable device */
 #define QEMU_PCI_CAP_MULTIFUNCTION_BITNR        3
     QEMU_PCI_CAP_MULTIFUNCTION = (1 << QEMU_PCI_CAP_MULTIFUNCTION_BITNR),
+
+    /* command register SERR bit enabled */
+#define QEMU_PCI_CAP_SERR_BITNR 4
+    QEMU_PCI_CAP_SERR = (1 << QEMU_PCI_CAP_SERR_BITNR),
 };
 
 struct PCIDevice {
commit 783e7706937fe15523b609b545587a028a2bdd03
Author: Michael S. Tsirkin <mst at redhat.com>
Date:   Mon Nov 22 19:52:30 2010 +0200

    virtio-net: stop/start bh when appropriate
    
    Avoid sending out packets, and modifying
    memory, when VM is stopped.
    Add assert statements to verify this does not happen.
    
    Avoid scheduling bh when vhost-net is started.
    
    Stop bh when driver disabled bus mastering
    (we must not access memory after this).
    
    Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
    Tested-by: Jason Wang <jasowang at redhat.com>

diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index 43a2b3d..5881961 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -99,9 +99,14 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config)
     }
 }
 
-static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
+static bool virtio_net_started(VirtIONet *n, uint8_t status)
+{
+    return (status & VIRTIO_CONFIG_S_DRIVER_OK) &&
+        (n->status & VIRTIO_NET_S_LINK_UP) && n->vm_running;
+}
+
+static void virtio_net_vhost_status(VirtIONet *n, uint8_t status)
 {
-    VirtIONet *n = to_virtio_net(vdev);
     if (!n->nic->nc.peer) {
         return;
     }
@@ -112,9 +117,7 @@ static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
     if (!tap_get_vhost_net(n->nic->nc.peer)) {
         return;
     }
-    if (!!n->vhost_started == ((status & VIRTIO_CONFIG_S_DRIVER_OK) &&
-                               (n->status & VIRTIO_NET_S_LINK_UP) &&
-                               n->vm_running)) {
+    if (!!n->vhost_started == virtio_net_started(n, status)) {
         return;
     }
     if (!n->vhost_started) {
@@ -131,6 +134,32 @@ static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
     }
 }
 
+static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
+{
+    VirtIONet *n = to_virtio_net(vdev);
+
+    virtio_net_vhost_status(n, status);
+
+    if (!n->tx_waiting) {
+        return;
+    }
+
+    if (virtio_net_started(n, status) && !n->vhost_started) {
+        if (n->tx_timer) {
+            qemu_mod_timer(n->tx_timer,
+                           qemu_get_clock(vm_clock) + n->tx_timeout);
+        } else {
+            qemu_bh_schedule(n->tx_bh);
+        }
+    } else {
+        if (n->tx_timer) {
+            qemu_del_timer(n->tx_timer);
+        } else {
+            qemu_bh_cancel(n->tx_bh);
+        }
+    }
+}
+
 static void virtio_net_set_link_status(VLANClientState *nc)
 {
     VirtIONet *n = DO_UPCAST(NICState, nc, nc)->opaque;
@@ -675,11 +704,12 @@ static int32_t virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq)
 {
     VirtQueueElement elem;
     int32_t num_packets = 0;
-
     if (!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) {
         return num_packets;
     }
 
+    assert(n->vm_running);
+
     if (n->async_tx.elem.out_num) {
         virtio_queue_set_notification(n->tx_vq, 0);
         return num_packets;
@@ -738,6 +768,12 @@ static void virtio_net_handle_tx_timer(VirtIODevice *vdev, VirtQueue *vq)
 {
     VirtIONet *n = to_virtio_net(vdev);
 
+    /* This happens when device was stopped but VCPU wasn't. */
+    if (!n->vm_running) {
+        n->tx_waiting = 1;
+        return;
+    }
+
     if (n->tx_waiting) {
         virtio_queue_set_notification(vq, 1);
         qemu_del_timer(n->tx_timer);
@@ -758,14 +794,19 @@ static void virtio_net_handle_tx_bh(VirtIODevice *vdev, VirtQueue *vq)
     if (unlikely(n->tx_waiting)) {
         return;
     }
+    n->tx_waiting = 1;
+    /* This happens when device was stopped but VCPU wasn't. */
+    if (!n->vm_running) {
+        return;
+    }
     virtio_queue_set_notification(vq, 0);
     qemu_bh_schedule(n->tx_bh);
-    n->tx_waiting = 1;
 }
 
 static void virtio_net_tx_timer(void *opaque)
 {
     VirtIONet *n = opaque;
+    assert(n->vm_running);
 
     n->tx_waiting = 0;
 
@@ -782,6 +823,8 @@ static void virtio_net_tx_bh(void *opaque)
     VirtIONet *n = opaque;
     int32_t ret;
 
+    assert(n->vm_running);
+
     n->tx_waiting = 0;
 
     /* Just in case the driver is not ready on more */
@@ -926,15 +969,6 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
         }
     }
     n->mac_table.first_multi = i;
-
-    if (n->tx_waiting) {
-        if (n->tx_timer) {
-            qemu_mod_timer(n->tx_timer,
-                           qemu_get_clock(vm_clock) + n->tx_timeout);
-        } else {
-            qemu_bh_schedule(n->tx_bh);
-        }
-    }
     return 0;
 }
 
commit 954773230484f5afeb675e9ff814c97e54e69e17
Author: Michael S. Tsirkin <mst at redhat.com>
Date:   Mon Nov 22 19:52:19 2010 +0200

    virtio-net: don't dma while vm is stopped
    
    DMA into memory while VM is stopped makes it
    hard to debug migration (consequitive saves
    result in different files).
    Fixing this completely is a large effort,
    this patch does this for virtio-net.
    
    Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
    Tested-by: Jason Wang <jasowang at redhat.com>

diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index 1d61f19..43a2b3d 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -424,6 +424,9 @@ static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq)
 static int virtio_net_can_receive(VLANClientState *nc)
 {
     VirtIONet *n = DO_UPCAST(NICState, nc, nc)->opaque;
+    if (!n->vm_running) {
+        return 0;
+    }
 
     if (!virtio_queue_ready(n->rx_vq) ||
         !(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK))
commit eff06c40d330cdbea414331337ca6f5032dbf6d7
Author: Michael S. Tsirkin <mst at redhat.com>
Date:   Mon Nov 22 19:52:26 2010 +0200

    migration/savevm: no need to flush requests
    
    There's no need to flush requests after vmstop
    as vmstop does it for us automatically now.
    
    Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
    Tested-by: Jason Wang <jasowang at redhat.com>

diff --git a/migration.c b/migration.c
index 622a9d2..e5ba51c 100644
--- a/migration.c
+++ b/migration.c
@@ -370,8 +370,6 @@ void migrate_fd_put_ready(void *opaque)
         DPRINTF("done iterating\n");
         vm_stop(0);
 
-        qemu_aio_flush();
-        bdrv_flush_all();
         if ((qemu_savevm_state_complete(s->mon, s->file)) < 0) {
             if (old_vm_running) {
                 vm_start();
diff --git a/savevm.c b/savevm.c
index d38f79e..90aa237 100644
--- a/savevm.c
+++ b/savevm.c
@@ -1575,8 +1575,6 @@ static int qemu_savevm_state(Monitor *mon, QEMUFile *f)
     saved_vm_running = vm_running;
     vm_stop(0);
 
-    bdrv_flush_all();
-
     ret = qemu_savevm_state_begin(mon, f, 0, 0);
     if (ret < 0)
         goto out;
@@ -1885,8 +1883,6 @@ void do_savevm(Monitor *mon, const QDict *qdict)
         monitor_printf(mon, "No block device can accept snapshots\n");
         return;
     }
-    /* ??? Should this occur after vm_stop?  */
-    qemu_aio_flush();
 
     saved_vm_running = vm_running;
     vm_stop(0);
commit 55df6f33655ed4139c824aa3ab9a4ab0c19dca83
Author: Michael S. Tsirkin <mst at redhat.com>
Date:   Mon Nov 22 19:52:22 2010 +0200

    cpus: flush all requests on each vm stop
    
    Flush all requests once we have stopped all
    cpus and devices.
    Make sure disk is in consistent state.
    
    Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
    Tested-by: Jason Wang <jasowang at redhat.com>
    Acked-by: Marcelo Tosatti <mtosatti at redhat.com>

diff --git a/cpus.c b/cpus.c
index 91a0fb1..0309189 100644
--- a/cpus.c
+++ b/cpus.c
@@ -111,6 +111,8 @@ static void do_vm_stop(int reason)
         vm_running = 0;
         pause_all_vcpus();
         vm_state_notify(0, reason);
+        qemu_aio_flush();
+        bdrv_flush_all();
         monitor_protocol_event(QEVENT_STOP, NULL);
     }
 }
commit 3a75e74c76cef8daa7944159b016c4ee7c56e568
Author: Mike Ryan <mikeryan at isi.edu>
Date:   Wed Dec 1 11:16:47 2010 -0800

    net/sock: option to specify local address
    
    Add an option to specify the host IP to send multicast packets from,
    when using a multicast socket for networking. The option takes an IP
    address and sets the IP_MULTICAST_IF socket option, which causes the
    packets to use that IP's interface as an egress.
    
    This is useful if the host machine has several interfaces with several
    virtual networks across disparate interfaces.
    
    Signed-off-by: Mike Ryan <mikeryan at ISI.EDU>
    Signed-off-by: Michael S. Tsirkin <mst at redhat.com>

diff --git a/net.c b/net.c
index c5e6063..9ba5be2 100644
--- a/net.c
+++ b/net.c
@@ -1050,6 +1050,10 @@ static const struct {
                 .name = "mcast",
                 .type = QEMU_OPT_STRING,
                 .help = "UDP multicast address and port number",
+            }, {
+                .name = "localaddr",
+                .type = QEMU_OPT_STRING,
+                .help = "source address for multicast packets",
             },
             { /* end of list */ }
         },
diff --git a/net/socket.c b/net/socket.c
index 1c4e153..916c2a8 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -149,7 +149,7 @@ static void net_socket_send_dgram(void *opaque)
     qemu_send_packet(&s->nc, s->buf, size);
 }
 
-static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
+static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr *localaddr)
 {
     struct ip_mreq imr;
     int fd;
@@ -183,7 +183,11 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
 
     /* Add host to multicast group */
     imr.imr_multiaddr = mcastaddr->sin_addr;
-    imr.imr_interface.s_addr = htonl(INADDR_ANY);
+    if (localaddr) {
+        imr.imr_interface = *localaddr;
+    } else {
+        imr.imr_interface.s_addr = htonl(INADDR_ANY);
+    }
 
     ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
                      (const char *)&imr, sizeof(struct ip_mreq));
@@ -201,6 +205,15 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
 	goto fail;
     }
 
+    /* If a bind address is given, only send packets from that address */
+    if (localaddr != NULL) {
+        ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, localaddr, sizeof(*localaddr));
+        if (ret < 0) {
+            perror("setsockopt(IP_MULTICAST_IF)");
+            goto fail;
+        }
+    }
+
     socket_set_nonblock(fd);
     return fd;
 fail:
@@ -248,7 +261,7 @@ static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan,
 		return NULL;
 	    }
 	    /* clone dgram socket */
-	    newfd = net_socket_mcast_create(&saddr);
+	    newfd = net_socket_mcast_create(&saddr, NULL);
 	    if (newfd < 0) {
 		/* error already reported by net_socket_mcast_create() */
 		close(fd);
@@ -468,17 +481,26 @@ static int net_socket_connect_init(VLANState *vlan,
 static int net_socket_mcast_init(VLANState *vlan,
                                  const char *model,
                                  const char *name,
-                                 const char *host_str)
+                                 const char *host_str,
+                                 const char *localaddr_str)
 {
     NetSocketState *s;
     int fd;
     struct sockaddr_in saddr;
+    struct in_addr localaddr, *param_localaddr;
 
     if (parse_host_port(&saddr, host_str) < 0)
         return -1;
 
+    if (localaddr_str != NULL) {
+        if (inet_aton(localaddr_str, &localaddr) == 0)
+            return -1;
+        param_localaddr = &localaddr;
+    } else {
+        param_localaddr = NULL;
+    }
 
-    fd = net_socket_mcast_create(&saddr);
+    fd = net_socket_mcast_create(&saddr, param_localaddr);
     if (fd < 0)
 	return -1;
 
@@ -505,8 +527,9 @@ int net_init_socket(QemuOpts *opts,
 
         if (qemu_opt_get(opts, "listen") ||
             qemu_opt_get(opts, "connect") ||
-            qemu_opt_get(opts, "mcast")) {
-            error_report("listen=, connect= and mcast= is invalid with fd=");
+            qemu_opt_get(opts, "mcast") ||
+            qemu_opt_get(opts, "localaddr")) {
+            error_report("listen=, connect=, mcast= and localaddr= is invalid with fd=\n");
             return -1;
         }
 
@@ -524,8 +547,9 @@ int net_init_socket(QemuOpts *opts,
 
         if (qemu_opt_get(opts, "fd") ||
             qemu_opt_get(opts, "connect") ||
-            qemu_opt_get(opts, "mcast")) {
-            error_report("fd=, connect= and mcast= is invalid with listen=");
+            qemu_opt_get(opts, "mcast") ||
+            qemu_opt_get(opts, "localaddr")) {
+            error_report("fd=, connect=, mcast= and localaddr= is invalid with listen=\n");
             return -1;
         }
 
@@ -539,8 +563,9 @@ int net_init_socket(QemuOpts *opts,
 
         if (qemu_opt_get(opts, "fd") ||
             qemu_opt_get(opts, "listen") ||
-            qemu_opt_get(opts, "mcast")) {
-            error_report("fd=, listen= and mcast= is invalid with connect=");
+            qemu_opt_get(opts, "mcast") ||
+            qemu_opt_get(opts, "localaddr")) {
+            error_report("fd=, listen=, mcast= and localaddr= is invalid with connect=\n");
             return -1;
         }
 
@@ -550,7 +575,7 @@ int net_init_socket(QemuOpts *opts,
             return -1;
         }
     } else if (qemu_opt_get(opts, "mcast")) {
-        const char *mcast;
+        const char *mcast, *localaddr;
 
         if (qemu_opt_get(opts, "fd") ||
             qemu_opt_get(opts, "connect") ||
@@ -560,8 +585,9 @@ int net_init_socket(QemuOpts *opts,
         }
 
         mcast = qemu_opt_get(opts, "mcast");
+        localaddr = qemu_opt_get(opts, "localaddr");
 
-        if (net_socket_mcast_init(vlan, "socket", name, mcast) == -1) {
+        if (net_socket_mcast_init(vlan, "socket", name, mcast, localaddr) == -1) {
             return -1;
         }
     } else {
diff --git a/qemu-options.hx b/qemu-options.hx
index 4d99a58..accd16a 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1061,8 +1061,9 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
 #endif
     "-net socket[,vlan=n][,name=str][,fd=h][,listen=[host]:port][,connect=host:port]\n"
     "                connect the vlan 'n' to another VLAN using a socket connection\n"
-    "-net socket[,vlan=n][,name=str][,fd=h][,mcast=maddr:port]\n"
+    "-net socket[,vlan=n][,name=str][,fd=h][,mcast=maddr:port[,localaddr=addr]]\n"
     "                connect the vlan 'n' to multicast maddr and port\n"
+    "                use 'localaddr=addr' to specify the host address to send packets from\n"
 #ifdef CONFIG_VDE
     "-net vde[,vlan=n][,name=str][,sock=socketpath][,port=n][,group=groupname][,mode=octalmode]\n"
     "                connect the vlan 'n' to port 'n' of a vde switch running\n"
@@ -1256,7 +1257,7 @@ qemu linux.img -net nic,macaddr=52:54:00:12:34:57 \
                -net socket,connect=127.0.0.1:1234
 @end example
 
- at item -net socket[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}] [,mcast=@var{maddr}:@var{port}]
+ at item -net socket[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}][,mcast=@var{maddr}:@var{port}[,localaddr=@var{addr}]]
 
 Create a VLAN @var{n} shared with another QEMU virtual
 machines using a UDP multicast socket, effectively making a bus for
@@ -1296,6 +1297,12 @@ qemu linux.img -net nic,macaddr=52:54:00:12:34:56 \
 /path/to/linux ubd0=/path/to/root_fs eth0=mcast
 @end example
 
+Example (send packets from host's 1.2.3.4):
+ at example
+qemu linux.img -net nic,macaddr=52:54:00:12:34:56 \
+               -net socket,mcast=239.192.168.1:1102,localaddr=1.2.3.4
+ at end example
+
 @item -net vde[,vlan=@var{n}][,name=@var{name}][,sock=@var{socketpath}] [,port=@var{n}][,group=@var{groupname}][,mode=@var{octalmode}]
 Connect VLAN @var{n} to PORT @var{n} of a vde switch running on host and
 listening for incoming connections on @var{socketpath}. Use GROUP @var{groupname}
commit 72f24d155ceffa0eb888fd277fa09584bcd1b04c
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Tue Dec 7 15:37:34 2010 +0000

    ARM: Implement VCVT to 16 bit integer using new softfloat routines
    
    Use the softfloat conversion routines for conversion to 16 bit
    integers, because just casting to a 16 bit type truncates the
    value rather than saturating it at 16-bit MAXINT/MININT.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Reviewed-by: Nathan Froyd <froydnj at codesourcery.com>

diff --git a/target-arm/helper.c b/target-arm/helper.c
index 2925782..9ba2f4f 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -2560,7 +2560,7 @@ ftype VFP_HELPER(to##name, p)(ftype x, uint32_t shift, CPUState *env) \
         return ftype##_zero; \
     } \
     tmp = ftype##_scalbn(x, shift, &env->vfp.fp_status); \
-    return vfp_ito##p((itype)ftype##_to_##sign##int32_round_to_zero(tmp, \
+    return vfp_ito##p(ftype##_to_##itype##_round_to_zero(tmp, \
         &env->vfp.fp_status)); \
 }
 
commit cbcef455a2d29cdd19f4f0a21990cd76c0d03102
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Tue Dec 7 15:37:34 2010 +0000

    softfloat: Add float/double to 16 bit integer conversion functions
    
    The ARM architecture needs float/double to 16 bit integer conversions.
    (The 32 bit versions aren't sufficient because of the requirement
    to saturate at 16 bit MAXINT/MININT and to get the exception bits right.)
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Reviewed-by: Nathan Froyd <froydnj at codesourcery.com>

diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index 0b82797..6f5b05d 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -1355,6 +1355,55 @@ int32 float32_to_int32_round_to_zero( float32 a STATUS_PARAM )
 
 /*----------------------------------------------------------------------------
 | Returns the result of converting the single-precision floating-point value
+| `a' to the 16-bit two's complement integer format.  The conversion is
+| performed according to the IEC/IEEE Standard for Binary Floating-Point
+| Arithmetic, except that the conversion is always rounded toward zero.
+| If `a' is a NaN, the largest positive integer is returned.  Otherwise, if
+| the conversion overflows, the largest integer with the same sign as `a' is
+| returned.
+*----------------------------------------------------------------------------*/
+
+int16 float32_to_int16_round_to_zero( float32 a STATUS_PARAM )
+{
+    flag aSign;
+    int16 aExp, shiftCount;
+    bits32 aSig;
+    int32 z;
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    aSign = extractFloat32Sign( a );
+    shiftCount = aExp - 0x8E;
+    if ( 0 <= shiftCount ) {
+        if ( float32_val(a) != 0xC7000000 ) {
+            float_raise( float_flag_invalid STATUS_VAR);
+            if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) {
+                return 0x7FFF;
+            }
+        }
+        return (sbits32) 0xffff8000;
+    }
+    else if ( aExp <= 0x7E ) {
+        if ( aExp | aSig ) {
+            STATUS(float_exception_flags) |= float_flag_inexact;
+        }
+        return 0;
+    }
+    shiftCount -= 0x10;
+    aSig = ( aSig | 0x00800000 )<<8;
+    z = aSig>>( - shiftCount );
+    if ( (bits32) ( aSig<<( shiftCount & 31 ) ) ) {
+        STATUS(float_exception_flags) |= float_flag_inexact;
+    }
+    if ( aSign ) {
+        z = - z;
+    }
+    return z;
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the single-precision floating-point value
 | `a' to the 64-bit two's complement integer format.  The conversion is
 | performed according to the IEC/IEEE Standard for Binary Floating-Point
 | Arithmetic---which means in particular that the conversion is rounded
@@ -2412,6 +2461,57 @@ int32 float64_to_int32_round_to_zero( float64 a STATUS_PARAM )
 
 /*----------------------------------------------------------------------------
 | Returns the result of converting the double-precision floating-point value
+| `a' to the 16-bit two's complement integer format.  The conversion is
+| performed according to the IEC/IEEE Standard for Binary Floating-Point
+| Arithmetic, except that the conversion is always rounded toward zero.
+| If `a' is a NaN, the largest positive integer is returned.  Otherwise, if
+| the conversion overflows, the largest integer with the same sign as `a' is
+| returned.
+*----------------------------------------------------------------------------*/
+
+int16 float64_to_int16_round_to_zero( float64 a STATUS_PARAM )
+{
+    flag aSign;
+    int16 aExp, shiftCount;
+    bits64 aSig, savedASig;
+    int32 z;
+
+    aSig = extractFloat64Frac( a );
+    aExp = extractFloat64Exp( a );
+    aSign = extractFloat64Sign( a );
+    if ( 0x40E < aExp ) {
+        if ( ( aExp == 0x7FF ) && aSig ) {
+            aSign = 0;
+        }
+        goto invalid;
+    }
+    else if ( aExp < 0x3FF ) {
+        if ( aExp || aSig ) {
+            STATUS(float_exception_flags) |= float_flag_inexact;
+        }
+        return 0;
+    }
+    aSig |= LIT64( 0x0010000000000000 );
+    shiftCount = 0x433 - aExp;
+    savedASig = aSig;
+    aSig >>= shiftCount;
+    z = aSig;
+    if ( aSign ) {
+        z = - z;
+    }
+    if ( ( (int16_t)z < 0 ) ^ aSign ) {
+ invalid:
+        float_raise( float_flag_invalid STATUS_VAR);
+        return aSign ? (sbits32) 0xffff8000 : 0x7FFF;
+    }
+    if ( ( aSig<<shiftCount ) != savedASig ) {
+        STATUS(float_exception_flags) |= float_flag_inexact;
+    }
+    return z;
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the double-precision floating-point value
 | `a' to the 64-bit two's complement integer format.  The conversion is
 | performed according to the IEC/IEEE Standard for Binary Floating-Point
 | Arithmetic---which means in particular that the conversion is rounded
@@ -5632,6 +5732,24 @@ unsigned int float32_to_uint32_round_to_zero( float32 a STATUS_PARAM )
     return res;
 }
 
+unsigned int float32_to_uint16_round_to_zero( float32 a STATUS_PARAM )
+{
+    int64_t v;
+    unsigned int res;
+
+    v = float32_to_int64_round_to_zero(a STATUS_VAR);
+    if (v < 0) {
+        res = 0;
+        float_raise( float_flag_invalid STATUS_VAR);
+    } else if (v > 0xffff) {
+        res = 0xffff;
+        float_raise( float_flag_invalid STATUS_VAR);
+    } else {
+        res = v;
+    }
+    return res;
+}
+
 unsigned int float64_to_uint32( float64 a STATUS_PARAM )
 {
     int64_t v;
@@ -5668,6 +5786,24 @@ unsigned int float64_to_uint32_round_to_zero( float64 a STATUS_PARAM )
     return res;
 }
 
+unsigned int float64_to_uint16_round_to_zero( float64 a STATUS_PARAM )
+{
+    int64_t v;
+    unsigned int res;
+
+    v = float64_to_int64_round_to_zero(a STATUS_VAR);
+    if (v < 0) {
+        res = 0;
+        float_raise( float_flag_invalid STATUS_VAR);
+    } else if (v > 0xffff) {
+        res = 0xffff;
+        float_raise( float_flag_invalid STATUS_VAR);
+    } else {
+        res = v;
+    }
+    return res;
+}
+
 /* FIXME: This looks broken.  */
 uint64_t float64_to_uint64 (float64 a STATUS_PARAM)
 {
diff --git a/fpu/softfloat.h b/fpu/softfloat.h
index 2e651e2..1c1004d 100644
--- a/fpu/softfloat.h
+++ b/fpu/softfloat.h
@@ -251,6 +251,8 @@ float32 float16_to_float32( bits16, flag STATUS_PARAM );
 /*----------------------------------------------------------------------------
 | Software IEC/IEEE single-precision conversion routines.
 *----------------------------------------------------------------------------*/
+int float32_to_int16_round_to_zero( float32 STATUS_PARAM );
+unsigned int float32_to_uint16_round_to_zero( float32 STATUS_PARAM );
 int float32_to_int32( float32 STATUS_PARAM );
 int float32_to_int32_round_to_zero( float32 STATUS_PARAM );
 unsigned int float32_to_uint32( float32 STATUS_PARAM );
@@ -327,6 +329,8 @@ INLINE int float32_is_any_nan(float32 a)
 /*----------------------------------------------------------------------------
 | Software IEC/IEEE double-precision conversion routines.
 *----------------------------------------------------------------------------*/
+int float64_to_int16_round_to_zero( float64 STATUS_PARAM );
+unsigned int float64_to_uint16_round_to_zero( float64 STATUS_PARAM );
 int float64_to_int32( float64 STATUS_PARAM );
 int float64_to_int32_round_to_zero( float64 STATUS_PARAM );
 unsigned int float64_to_uint32( float64 STATUS_PARAM );
commit 26a5e69aafd0434922316e4185c45c9bddd4b9ba
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Tue Dec 7 15:37:34 2010 +0000

    ARM: Ignore top 16 bits when doing VCVT from 16 bit fixed point
    
    VCVT of 16 bit fixed point to float should ignore the top 16 bits
    of the source register. Cast to int16_t and friends rather than
    int16 -- the former is guaranteed exactly 16 bits wide where the
    latter is merely at least 16 bits wide (and so is usually 32 bits).
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Reviewed-by: Nathan Froyd <froydnj at codesourcery.com>

diff --git a/target-arm/helper.c b/target-arm/helper.c
index 4bd1cd4..2925782 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -2549,7 +2549,7 @@ float32 VFP_HELPER(fcvts, d)(float64 x, CPUState *env)
 ftype VFP_HELPER(name##to, p)(ftype x, uint32_t shift, CPUState *env) \
 { \
     ftype tmp; \
-    tmp = sign##int32_to_##ftype ((itype)vfp_##p##toi(x), \
+    tmp = sign##int32_to_##ftype ((itype##_t)vfp_##p##toi(x), \
                                   &env->vfp.fp_status); \
     return ftype##_scalbn(tmp, -(int)shift, &env->vfp.fp_status); \
 } \
commit 2d6277373d3fc18f11504cd05ea82f0fe6d67962
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Tue Dec 7 15:37:34 2010 +0000

    ARM: Return correct result for single<->double conversion of NaN
    
    The ARM ARM defines that if the input to a single<->double conversion
    is a NaN then the output is always forced to be a quiet NaN by setting
    the most significant bit of the fraction part.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Reviewed-by: Nathan Froyd <froydnj at codesourcery.com>

diff --git a/target-arm/helper.c b/target-arm/helper.c
index 6d2a8f2..4bd1cd4 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -2528,12 +2528,20 @@ float32 VFP_HELPER(tosiz, d)(float64 x, CPUState *env)
 /* floating point conversion */
 float64 VFP_HELPER(fcvtd, s)(float32 x, CPUState *env)
 {
-    return float32_to_float64(x, &env->vfp.fp_status);
+    float64 r = float32_to_float64(x, &env->vfp.fp_status);
+    /* ARM requires that S<->D conversion of any kind of NaN generates
+     * a quiet NaN by forcing the most significant frac bit to 1.
+     */
+    return float64_maybe_silence_nan(r);
 }
 
 float32 VFP_HELPER(fcvts, d)(float64 x, CPUState *env)
 {
-    return float64_to_float32(x, &env->vfp.fp_status);
+    float32 r =  float64_to_float32(x, &env->vfp.fp_status);
+    /* ARM requires that S<->D conversion of any kind of NaN generates
+     * a quiet NaN by forcing the most significant frac bit to 1.
+     */
+    return float32_maybe_silence_nan(r);
 }
 
 /* VFP3 fixed point conversion.  */
commit b408dbdec3d3220b7e2da2b0fd768048f43a2e39
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Tue Dec 7 15:37:34 2010 +0000

    softfloat: Add float*_maybe_silence_nan() functions
    
    Add functions float*_maybe_silence_nan() which ensure that a
    value is not a signaling NaN by turning it into a quiet NaN.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Reviewed-by: Nathan Froyd <froydnj at codesourcery.com>

diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h
index 8e6aceb..0746878 100644
--- a/fpu/softfloat-specialize.h
+++ b/fpu/softfloat-specialize.h
@@ -102,6 +102,25 @@ int float32_is_signaling_nan( float32 a_ )
 }
 
 /*----------------------------------------------------------------------------
+| Returns a quiet NaN if the single-precision floating point value `a' is a
+| signaling NaN; otherwise returns `a'.
+*----------------------------------------------------------------------------*/
+
+float32 float32_maybe_silence_nan( float32 a_ )
+{
+    if (float32_is_signaling_nan(a_)) {
+        uint32_t a = float32_val(a_);
+#if SNAN_BIT_IS_ONE
+        a &= ~(1 << 22);
+#else
+        a |= (1 << 22);
+#endif
+        return make_float32(a);
+    }
+    return a_;
+}
+
+/*----------------------------------------------------------------------------
 | Returns the result of converting the single-precision floating-point NaN
 | `a' to the canonical NaN format.  If `a' is a signaling NaN, the invalid
 | exception is raised.
@@ -234,6 +253,25 @@ int float64_is_signaling_nan( float64 a_ )
 }
 
 /*----------------------------------------------------------------------------
+| Returns a quiet NaN if the double-precision floating point value `a' is a
+| signaling NaN; otherwise returns `a'.
+*----------------------------------------------------------------------------*/
+
+float64 float64_maybe_silence_nan( float64 a_ )
+{
+    if (float64_is_signaling_nan(a_)) {
+        bits64 a = float64_val(a_);
+#if SNAN_BIT_IS_ONE
+        a &= ~LIT64( 0x0008000000000000 );
+#else
+        a |= LIT64( 0x0008000000000000 );
+#endif
+        return make_float64(a);
+    }
+    return a_;
+}
+
+/*----------------------------------------------------------------------------
 | Returns the result of converting the double-precision floating-point NaN
 | `a' to the canonical NaN format.  If `a' is a signaling NaN, the invalid
 | exception is raised.
diff --git a/fpu/softfloat.h b/fpu/softfloat.h
index 9bece80..2e651e2 100644
--- a/fpu/softfloat.h
+++ b/fpu/softfloat.h
@@ -287,6 +287,7 @@ int float32_compare( float32, float32 STATUS_PARAM );
 int float32_compare_quiet( float32, float32 STATUS_PARAM );
 int float32_is_nan( float32 );
 int float32_is_signaling_nan( float32 );
+float32 float32_maybe_silence_nan( float32 );
 float32 float32_scalbn( float32, int STATUS_PARAM );
 
 INLINE float32 float32_abs(float32 a)
@@ -364,6 +365,7 @@ int float64_compare( float64, float64 STATUS_PARAM );
 int float64_compare_quiet( float64, float64 STATUS_PARAM );
 int float64_is_nan( float64 a );
 int float64_is_signaling_nan( float64 );
+float64 float64_maybe_silence_nan( float64 );
 float64 float64_scalbn( float64, int STATUS_PARAM );
 
 INLINE float64 float64_abs(float64 a)
commit 09d9487fbb5c17226762e73c2b7d84170f5bd092
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Tue Dec 7 15:37:34 2010 +0000

    ARM: Return correct result for float-to-integer conversion of NaN
    
    The ARM architecture mandates that converting a NaN value to
    integer gives zero (if Invalid Operation FP exceptions are
    not being trapped). This isn't the behaviour of the SoftFloat
    library, so NaNs must be special-cased.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Reviewed-by: Nathan Froyd <froydnj at codesourcery.com>

diff --git a/target-arm/helper.c b/target-arm/helper.c
index 2a1f448..6d2a8f2 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -2463,41 +2463,65 @@ float64 VFP_HELPER(sito, d)(float32 x, CPUState *env)
 /* Float to integer conversion.  */
 float32 VFP_HELPER(toui, s)(float32 x, CPUState *env)
 {
+    if (float32_is_any_nan(x)) {
+        return float32_zero;
+    }
     return vfp_itos(float32_to_uint32(x, &env->vfp.fp_status));
 }
 
 float32 VFP_HELPER(toui, d)(float64 x, CPUState *env)
 {
+    if (float64_is_any_nan(x)) {
+        return float32_zero;
+    }
     return vfp_itos(float64_to_uint32(x, &env->vfp.fp_status));
 }
 
 float32 VFP_HELPER(tosi, s)(float32 x, CPUState *env)
 {
+    if (float32_is_any_nan(x)) {
+        return float32_zero;
+    }
     return vfp_itos(float32_to_int32(x, &env->vfp.fp_status));
 }
 
 float32 VFP_HELPER(tosi, d)(float64 x, CPUState *env)
 {
+    if (float64_is_any_nan(x)) {
+        return float32_zero;
+    }
     return vfp_itos(float64_to_int32(x, &env->vfp.fp_status));
 }
 
 float32 VFP_HELPER(touiz, s)(float32 x, CPUState *env)
 {
+    if (float32_is_any_nan(x)) {
+        return float32_zero;
+    }
     return vfp_itos(float32_to_uint32_round_to_zero(x, &env->vfp.fp_status));
 }
 
 float32 VFP_HELPER(touiz, d)(float64 x, CPUState *env)
 {
+    if (float64_is_any_nan(x)) {
+        return float32_zero;
+    }
     return vfp_itos(float64_to_uint32_round_to_zero(x, &env->vfp.fp_status));
 }
 
 float32 VFP_HELPER(tosiz, s)(float32 x, CPUState *env)
 {
+    if (float32_is_any_nan(x)) {
+        return float32_zero;
+    }
     return vfp_itos(float32_to_int32_round_to_zero(x, &env->vfp.fp_status));
 }
 
 float32 VFP_HELPER(tosiz, d)(float64 x, CPUState *env)
 {
+    if (float64_is_any_nan(x)) {
+        return float32_zero;
+    }
     return vfp_itos(float64_to_int32_round_to_zero(x, &env->vfp.fp_status));
 }
 
@@ -2524,6 +2548,9 @@ ftype VFP_HELPER(name##to, p)(ftype x, uint32_t shift, CPUState *env) \
 ftype VFP_HELPER(to##name, p)(ftype x, uint32_t shift, CPUState *env) \
 { \
     ftype tmp; \
+    if (ftype##_is_any_nan(x)) { \
+        return ftype##_zero; \
+    } \
     tmp = ftype##_scalbn(x, shift, &env->vfp.fp_status); \
     return vfp_ito##p((itype)ftype##_to_##sign##int32_round_to_zero(tmp, \
         &env->vfp.fp_status)); \
commit 21d6ebde76e9e7a89f5d2100816aac920cae109c
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Tue Dec 7 15:37:34 2010 +0000

    softfloat: Add float*_is_any_nan() functions
    
    Add float*_is_any_nan() functions which return true if the argument
    is a NaN of any kind (quiet or signalling).
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Reviewed-by: Nathan Froyd <froydnj at codesourcery.com>

diff --git a/fpu/softfloat.h b/fpu/softfloat.h
index 9528825..9bece80 100644
--- a/fpu/softfloat.h
+++ b/fpu/softfloat.h
@@ -314,6 +314,11 @@ INLINE int float32_is_zero(float32 a)
     return (float32_val(a) & 0x7fffffff) == 0;
 }
 
+INLINE int float32_is_any_nan(float32 a)
+{
+    return ((float32_val(a) & ~(1 << 31)) > 0x7f800000UL);
+}
+
 #define float32_zero make_float32(0)
 #define float32_one make_float32(0x3f800000)
 #define float32_ln2 make_float32(0x3f317218)
@@ -386,6 +391,11 @@ INLINE int float64_is_zero(float64 a)
     return (float64_val(a) & 0x7fffffffffffffffLL) == 0;
 }
 
+INLINE int float64_is_any_nan(float64 a)
+{
+    return ((float64_val(a) & ~(1ULL << 63)) > 0x7ff0000000000000ULL);
+}
+
 #define float64_zero make_float64(0)
 #define float64_one make_float64(0x3ff0000000000000LL)
 #define float64_ln2 make_float64(0x3fe62e42fefa39efLL)
commit d3587ef81db34885189178d53f99831aea95c702
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Tue Dec 7 15:37:34 2010 +0000

    ARM: Fix sense of to_integer bit in Neon VCVT float/int conversion
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Reviewed-by: Nathan Froyd <froydnj at codesourcery.com>

diff --git a/target-arm/translate.c b/target-arm/translate.c
index 0b3e4e6..d4a0666 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -5664,16 +5664,16 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                             gen_helper_rsqrte_f32(cpu_F0s, cpu_F0s, cpu_env);
                             break;
                         case 60: /* VCVT.F32.S32 */
-                            gen_vfp_tosiz(0);
+                            gen_vfp_sito(0);
                             break;
                         case 61: /* VCVT.F32.U32 */
-                            gen_vfp_touiz(0);
+                            gen_vfp_uito(0);
                             break;
                         case 62: /* VCVT.S32.F32 */
-                            gen_vfp_sito(0);
+                            gen_vfp_tosiz(0);
                             break;
                         case 63: /* VCVT.U32.F32 */
-                            gen_vfp_uito(0);
+                            gen_vfp_touiz(0);
                             break;
                         default:
                             /* Reserved: 21, 29, 39-56 */
commit f73534a56e21f0fa37c10941a2a887b3576c2f69
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Tue Dec 7 15:37:34 2010 +0000

    ARM: Fix decoding of Neon forms of VCVT between float and fixed point
    
    Fix errors in the decoding of the Neon forms of fixed-point VCVT:
     * fixed-point VCVT is op 14 and 15, not 15 and 16
     * the fbits immediate field was being misinterpreted
     * the sense of the to_fixed bit was inverted
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Reviewed-by: Nathan Froyd <froydnj at codesourcery.com>

diff --git a/target-arm/translate.c b/target-arm/translate.c
index 69a424a..0b3e4e6 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -4850,11 +4850,15 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                     }
                     neon_store_reg64(cpu_V0, rd + pass);
                 }
-            } else if (op == 15 || op == 16) {
+            } else if (op >= 14) {
                 /* VCVT fixed-point.  */
+                /* We have already masked out the must-be-1 top bit of imm6,
+                 * hence this 32-shift where the ARM ARM has 64-imm6.
+                 */
+                shift = 32 - shift;
                 for (pass = 0; pass < (q ? 4 : 2); pass++) {
                     tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, pass));
-                    if (op & 1) {
+                    if (!(op & 1)) {
                         if (u)
                             gen_vfp_ulto(0, shift);
                         else
commit 04595bf66f15cb205cb7f64eaa3a38804bf0893a
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Tue Dec 7 15:37:34 2010 +0000

    ARM: Fix decoding of VFP forms of VCVT between float and int/fixed
    
    Correct the decoding of source and destination registers
    for the VFP forms of the VCVT instructions which convert
    between floating point and integer or fixed-point.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Reviewed-by: Nathan Froyd <froydnj at codesourcery.com>

diff --git a/target-arm/translate.c b/target-arm/translate.c
index 7ee5375..69a424a 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -2870,16 +2870,18 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
                     VFP_DREG_N(rn, insn);
                 }
 
-                if (op == 15 && (rn == 15 || rn > 17)) {
+                if (op == 15 && (rn == 15 || ((rn & 0x1c) == 0x18))) {
                     /* Integer or single precision destination.  */
                     rd = VFP_SREG_D(insn);
                 } else {
                     VFP_DREG_D(rd, insn);
                 }
-
-                if (op == 15 && (rn == 16 || rn == 17)) {
-                    /* Integer source.  */
-                    rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1);
+                if (op == 15 &&
+                    (((rn & 0x1c) == 0x10) || ((rn & 0x14) == 0x14))) {
+                    /* VCVT from int is always from S reg regardless of dp bit.
+                     * VCVT with immediate frac_bits has same format as SREG_M
+                     */
+                    rm = VFP_SREG_M(insn);
                 } else {
                     VFP_DREG_M(rm, insn);
                 }
@@ -2891,6 +2893,9 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
                 } else {
                     rd = VFP_SREG_D(insn);
                 }
+                /* NB that we implicitly rely on the encoding for the frac_bits
+                 * in VCVT of fixed to float being the same as that of an SREG_M
+                 */
                 rm = VFP_SREG_M(insn);
             }
 
@@ -3179,8 +3184,8 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
                 /* Write back the result.  */
                 if (op == 15 && (rn >= 8 && rn <= 11))
                     ; /* Comparison, do nothing.  */
-                else if (op == 15 && rn > 17)
-                    /* Integer result.  */
+                else if (op == 15 && dp && ((rn & 0x1c) == 0x18))
+                    /* VCVT double to int: always integer result. */
                     gen_mov_vreg_F0(0, rd);
                 else if (op == 15 && rn == 15)
                     /* conversion */
commit 2c9adbda721c9996ec6b371cac4a00c1164b818e
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Tue Dec 7 15:37:34 2010 +0000

    ARM: fix ldrexd/strexd
    
    Correct ldrexd and strexd code to always read and write the
    high word of the 64-bit value from addr+4.
    Also make ldrexd and strexd agree that for a 64 bit value the
    address in env->exclusive_addr is that of the low word.
    
    This fixes the issues reported in
    https://bugs.launchpad.net/qemu/+bug/670883
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Reviewed-by: Nathan Froyd <froydnj at codesourcery.com>

diff --git a/linux-user/main.c b/linux-user/main.c
index 7d41d4a..0d627d6 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -589,7 +589,7 @@ static int do_strex(CPUARMState *env)
     }
     if (size == 3) {
         val = env->regs[(env->exclusive_info >> 12) & 0xf];
-        segv = put_user_u32(val, addr);
+        segv = put_user_u32(val, addr + 4);
         if (segv) {
             env->cp15.c6_data = addr + 4;
             goto done;
diff --git a/target-arm/translate.c b/target-arm/translate.c
index bf1e643..7ee5375 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -5926,8 +5926,10 @@ static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
     tcg_gen_mov_i32(cpu_exclusive_val, tmp);
     store_reg(s, rt, tmp);
     if (size == 3) {
-        tcg_gen_addi_i32(addr, addr, 4);
-        tmp = gen_ld32(addr, IS_USER(s));
+        TCGv tmp2 = new_tmp();
+        tcg_gen_addi_i32(tmp2, addr, 4);
+        tmp = gen_ld32(tmp2, IS_USER(s));
+        dead_tmp(tmp2);
         tcg_gen_mov_i32(cpu_exclusive_high, tmp);
         store_reg(s, rt2, tmp);
     }
@@ -5987,7 +5989,7 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
     if (size == 3) {
         TCGv tmp2 = new_tmp();
         tcg_gen_addi_i32(tmp2, addr, 4);
-        tmp = gen_ld32(addr, IS_USER(s));
+        tmp = gen_ld32(tmp2, IS_USER(s));
         dead_tmp(tmp2);
         tcg_gen_brcond_i32(TCG_COND_NE, tmp, cpu_exclusive_high, fail_label);
         dead_tmp(tmp);
commit 49e14940adeea797abd2be4ccda97d0349b22aae
Author: Adam Lackorzynski <adam at os.inf.tu-dresden.de>
Date:   Tue Dec 7 12:01:44 2010 +0000

    target-arm: Handle 'smc' as an undefined instruction
    
    Refine check on bkpt so that smc and undefined instruction encodings are
    handled as an undefined instruction and trap.
    
    Signed-off-by: Adam Lackorzynski <adam at os.inf.tu-dresden.de>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Reviewed-by: Nathan Froyd <froydnj at codesourcery.com>

diff --git a/target-arm/translate.c b/target-arm/translate.c
index 947de6d..bf1e643 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -6346,7 +6346,14 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
             dead_tmp(tmp2);
             store_reg(s, rd, tmp);
             break;
-        case 7: /* bkpt */
+        case 7:
+            /* SMC instruction (op1 == 3)
+               and undefined instructions (op1 == 0 || op1 == 2)
+               will trap */
+            if (op1 != 1) {
+                goto illegal_op;
+            }
+            /* bkpt */
             gen_set_condexec(s);
             gen_set_pc_im(s->pc - 4);
             gen_exception(EXCP_BKPT);
commit 4809c612bc5eabf158d7a4656a98f5601c6bf104
Author: Johan Bengtsson <teofrastius at gmail.com>
Date:   Tue Dec 7 12:01:44 2010 +0000

    target-arm: Fix mixup in decoding of saturating add and sub
    
    The thumb2 decoder contained a mixup between the bit controlling
    doubling and the bit controlling if the operation was an add or a sub.
    
    Signed-off-by: Johan Bengtsson <teofrastius at gmail.com>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Reviewed-by: Nathan Froyd <froydnj at codesourcery.com>

diff --git a/target-arm/translate.c b/target-arm/translate.c
index 183928b..947de6d 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -7713,9 +7713,9 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                 /* Saturating add/subtract.  */
                 tmp = load_reg(s, rn);
                 tmp2 = load_reg(s, rm);
-                if (op & 2)
-                    gen_helper_double_saturate(tmp, tmp);
                 if (op & 1)
+                    gen_helper_double_saturate(tmp, tmp);
+                if (op & 2)
                     gen_helper_sub_saturate(tmp, tmp2, tmp);
                 else
                     gen_helper_add_saturate(tmp, tmp, tmp2);
commit 2af9ab7737c050e063dc939973a8d669a3ab3743
Author: Johan Bengtsson <teofrastius at gmail.com>
Date:   Tue Dec 7 12:01:44 2010 +0000

    target-arm: Add support for PKHxx in thumb2
    
    The PKHxx instructions were not recognized by the thumb2 decoder. The
    solution provided in this changeset is identical to the arm-mode
    implementation.
    
    Signed-off-by: Johan Bengtsson <teofrastius at gmail.com>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Reviewed-by: Nathan Froyd <froydnj at codesourcery.com>

diff --git a/target-arm/translate.c b/target-arm/translate.c
index 99464ab..183928b 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -7601,27 +7601,54 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
             }
         }
         break;
-    case 5: /* Data processing register constant shift.  */
-        if (rn == 15) {
-            tmp = new_tmp();
-            tcg_gen_movi_i32(tmp, 0);
-        } else {
-            tmp = load_reg(s, rn);
-        }
-        tmp2 = load_reg(s, rm);
+    case 5:
+
         op = (insn >> 21) & 0xf;
-        shiftop = (insn >> 4) & 3;
-        shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c);
-        conds = (insn & (1 << 20)) != 0;
-        logic_cc = (conds && thumb2_logic_op(op));
-        gen_arm_shift_im(tmp2, shiftop, shift, logic_cc);
-        if (gen_thumb2_data_op(s, op, conds, 0, tmp, tmp2))
-            goto illegal_op;
-        dead_tmp(tmp2);
-        if (rd != 15) {
+        if (op == 6) {
+            /* Halfword pack.  */
+            tmp = load_reg(s, rn);
+            tmp2 = load_reg(s, rm);
+            shift = ((insn >> 10) & 0x1c) | ((insn >> 6) & 0x3);
+            if (insn & (1 << 5)) {
+                /* pkhtb */
+                if (shift == 0)
+                    shift = 31;
+                tcg_gen_sari_i32(tmp2, tmp2, shift);
+                tcg_gen_andi_i32(tmp, tmp, 0xffff0000);
+                tcg_gen_ext16u_i32(tmp2, tmp2);
+            } else {
+                /* pkhbt */
+                if (shift)
+                    tcg_gen_shli_i32(tmp2, tmp2, shift);
+                tcg_gen_ext16u_i32(tmp, tmp);
+                tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000);
+            }
+            tcg_gen_or_i32(tmp, tmp, tmp2);
+            dead_tmp(tmp2);
             store_reg(s, rd, tmp);
         } else {
-            dead_tmp(tmp);
+            /* Data processing register constant shift.  */
+            if (rn == 15) {
+                tmp = new_tmp();
+                tcg_gen_movi_i32(tmp, 0);
+            } else {
+                tmp = load_reg(s, rn);
+            }
+            tmp2 = load_reg(s, rm);
+
+            shiftop = (insn >> 4) & 3;
+            shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c);
+            conds = (insn & (1 << 20)) != 0;
+            logic_cc = (conds && thumb2_logic_op(op));
+            gen_arm_shift_im(tmp2, shiftop, shift, logic_cc);
+            if (gen_thumb2_data_op(s, op, conds, 0, tmp, tmp2))
+                goto illegal_op;
+            dead_tmp(tmp2);
+            if (rd != 15) {
+                store_reg(s, rd, tmp);
+            } else {
+                dead_tmp(tmp);
+            }
         }
         break;
     case 13: /* Misc data processing.  */
commit 3a019b6e6ad64e4df452a15dced6c954e45246c4
Author: Wen Congyang <wency at cn.fujitsu.com>
Date:   Thu Nov 25 09:06:05 2010 +0800

    correct migrate_set_speed's args_type
    
    The args_type of migrate_set_speed in qmp-commands.hx is wrong.
    When we set migrate speed by json, qemu will be core dumped.
    
    This bug was caused by 07de3e60b05 and hence affects master only.
    
    Signed-off-by: Wen Congyang <wency at cn.fujitsu.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/qmp-commands.hx b/qmp-commands.hx
index e5f157f..3486223 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -495,7 +495,7 @@ EQMP
 
     {
         .name       = "migrate_set_speed",
-        .args_type  = "value:f",
+        .args_type  = "value:o",
         .params     = "value",
         .help       = "set maximum speed (in bytes) for migrations",
         .user_print = monitor_user_noop,
commit 83a27d4d1c7e6179bd6e5e8bfa505f62c402e999
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Mon Nov 22 17:10:37 2010 -0200

    QMP: Simplify monitor_json_emitter()
    
    Use the ternary operator instead of an if (also fixes bad indentation).
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/monitor.c b/monitor.c
index 1e8b1fc..f1aebc1 100644
--- a/monitor.c
+++ b/monitor.c
@@ -351,10 +351,8 @@ static void monitor_json_emitter(Monitor *mon, const QObject *data)
 {
     QString *json;
 
-    if (mon->flags & MONITOR_USE_PRETTY)
-	json = qobject_to_json_pretty(data);
-    else
-	json = qobject_to_json(data);
+    json = mon->flags & MONITOR_USE_PRETTY ? qobject_to_json_pretty(data) :
+                                             qobject_to_json(data);
     assert(json != NULL);
 
     qstring_append_chr(json, '\n');
commit 6d44143054293995c5e92fbddbd1ee92846013cc
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Mon Nov 22 16:35:09 2010 -0200

    QMP: Drop dead code
    
    The first if/else clause in handler_audit() makes no sense for two
    reasons:
    
      1. this function is now called only by QMP code, so testing if
         it's a QMP call makes no sense anymore
    
      2. the else clause first asserts that there's no error in the
         monitor object, then it tries to free it!
    
    Just drop it.
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/monitor.c b/monitor.c
index 1296c40..1e8b1fc 100644
--- a/monitor.c
+++ b/monitor.c
@@ -3891,49 +3891,43 @@ void monitor_set_error(Monitor *mon, QError *qerror)
 
 static void handler_audit(Monitor *mon, const mon_cmd_t *cmd, int ret)
 {
-    if (monitor_ctrl_mode(mon)) {
-        if (ret && !monitor_has_error(mon)) {
-            /*
-             * If it returns failure, it must have passed on error.
-             *
-             * Action: Report an internal error to the client if in QMP.
-             */
-            qerror_report(QERR_UNDEFINED_ERROR);
-            MON_DEBUG("command '%s' returned failure but did not pass an error\n",
-                      cmd->name);
-        }
+    if (ret && !monitor_has_error(mon)) {
+        /*
+         * If it returns failure, it must have passed on error.
+         *
+         * Action: Report an internal error to the client if in QMP.
+         */
+        qerror_report(QERR_UNDEFINED_ERROR);
+        MON_DEBUG("command '%s' returned failure but did not pass an error\n",
+                  cmd->name);
+    }
 
 #ifdef CONFIG_DEBUG_MONITOR
-        if (!ret && monitor_has_error(mon)) {
-            /*
-             * If it returns success, it must not have passed an error.
-             *
-             * Action: Report the passed error to the client.
-             */
-            MON_DEBUG("command '%s' returned success but passed an error\n",
-                      cmd->name);
-        }
-
-        if (mon_print_count_get(mon) > 0 && strcmp(cmd->name, "info") != 0) {
-            /*
-             * Handlers should not call Monitor print functions.
-             *
-             * Action: Ignore them in QMP.
-             *
-             * (XXX: we don't check any 'info' or 'query' command here
-             * because the user print function _is_ called by do_info(), hence
-             * we will trigger this check. This problem will go away when we
-             * make 'query' commands real and kill do_info())
-             */
-            MON_DEBUG("command '%s' called print functions %d time(s)\n",
-                      cmd->name, mon_print_count_get(mon));
-        }
-#endif
-    } else {
-        assert(!monitor_has_error(mon));
-        QDECREF(mon->error);
-        mon->error = NULL;
+    if (!ret && monitor_has_error(mon)) {
+        /*
+         * If it returns success, it must not have passed an error.
+         *
+         * Action: Report the passed error to the client.
+         */
+        MON_DEBUG("command '%s' returned success but passed an error\n",
+                  cmd->name);
+    }
+
+    if (mon_print_count_get(mon) > 0 && strcmp(cmd->name, "info") != 0) {
+        /*
+         * Handlers should not call Monitor print functions.
+         *
+         * Action: Ignore them in QMP.
+         *
+         * (XXX: we don't check any 'info' or 'query' command here
+         * because the user print function _is_ called by do_info(), hence
+         * we will trigger this check. This problem will go away when we
+         * make 'query' commands real and kill do_info())
+         */
+        MON_DEBUG("command '%s' called print functions %d time(s)\n",
+                  cmd->name, mon_print_count_get(mon));
     }
+#endif
 }
 
 static void handle_user_command(Monitor *mon, const char *cmdline)
commit c01e68853148764d32c3a27ab4b39cb553c567fc
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Mon Nov 22 16:22:47 2010 -0200

    QMP: Fix default response regression
    
    Commit 030db6e89d dropped do_info() usage from QMP and introduced
    qmp_call_query_cmd(). However, the new function doesn't emit QMP's
    default OK response when the handler doesn't return data.
    
    Fix that by also calling monitor_protocol_emitter() when
    ret_data == NULL, so that the default response is emitted.
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/monitor.c b/monitor.c
index ec31eac..1296c40 100644
--- a/monitor.c
+++ b/monitor.c
@@ -4464,10 +4464,8 @@ static void qmp_call_query_cmd(Monitor *mon, const mon_cmd_t *cmd)
         }
     } else {
         cmd->mhandler.info_new(mon, &ret_data);
-        if (ret_data) {
-            monitor_protocol_emitter(mon, ret_data);
-            qobject_decref(ret_data);
-        }
+        monitor_protocol_emitter(mon, ret_data);
+        qobject_decref(ret_data);
     }
 }
 
commit 38671423466875ecd848710cc1d7019448a6b145
Author: Hidetoshi Seto <seto.hidetoshi at jp.fujitsu.com>
Date:   Wed Nov 24 11:38:10 2010 +0900

    virtio-9p: fix build on !CONFIG_UTIMENSAT
    
    This patch introduce a fallback mechanism for old systems that do not
    support utimensat().  This fix build failure with following warnings:
    
    hw/virtio-9p-local.c: In function 'local_utimensat':
    hw/virtio-9p-local.c:479: warning: implicit declaration of function 'utimensat'
    hw/virtio-9p-local.c:479: warning: nested extern declaration of 'utimensat'
    
    and:
    
    hw/virtio-9p.c: In function 'v9fs_setattr_post_chmod':
    hw/virtio-9p.c:1410: error: 'UTIME_NOW' undeclared (first use in this function)
    hw/virtio-9p.c:1410: error: (Each undeclared identifier is reported only once
    hw/virtio-9p.c:1410: error: for each function it appears in.)
    hw/virtio-9p.c:1413: error: 'UTIME_OMIT' undeclared (first use in this function)
    hw/virtio-9p.c: In function 'v9fs_wstat_post_chmod':
    hw/virtio-9p.c:2905: error: 'UTIME_OMIT' undeclared (first use in this function)
    
    [NOTE: At this time virtio-9p is only user of utimensat(), and is available
           only when host is linux and CONFIG_VIRTFS is defined.  So there are
           no similar warning for win32.  Please provide a wrapper for win32 in
           oslib-win32.c if new user really requires it.]
    
    v5:
      - Allow fallback on runtime
      - Move qemu_utimensat() to oslib-posix.c
      - Rebased on latest qemu.git
    v4:
      - Use tv_now.tv_usec
    v3:
      - Use better alternative handling for UTIME_NOW/OMIT
      - Move qemu_utimensat() to cutils.c
    V2:
      - Introduce qemu_utimensat()
    
    Acked-by: Chris Wright <chrisw at sous-sol.org>
    Acked-by: M. Mohan Kumar <mohan at in.ibm.com>
    Acked-by: Jes Sorensen <Jes.Sorensen at redhat.com>
    Signed-off-by: Hidetoshi Seto <seto.hidetoshi at jp.fujitsu.com>
    Signed-off-by: Venkateswararao Jujjuri <jvrao at linux.vnet.ibm.com>

diff --git a/hw/virtio-9p-local.c b/hw/virtio-9p-local.c
index 656bfb3..a8e7525 100644
--- a/hw/virtio-9p-local.c
+++ b/hw/virtio-9p-local.c
@@ -480,9 +480,9 @@ static int local_chown(FsContext *fs_ctx, const char *path, FsCred *credp)
 }
 
 static int local_utimensat(FsContext *s, const char *path,
-		       const struct timespec *buf)
+                           const struct timespec *buf)
 {
-    return utimensat(AT_FDCWD, rpath(s, path), buf, AT_SYMLINK_NOFOLLOW);
+    return qemu_utimensat(AT_FDCWD, rpath(s, path), buf, AT_SYMLINK_NOFOLLOW);
 }
 
 static int local_remove(FsContext *ctx, const char *path)
diff --git a/oslib-posix.c b/oslib-posix.c
index 6e9b0c3..7bc5f7c 100644
--- a/oslib-posix.c
+++ b/oslib-posix.c
@@ -107,3 +107,51 @@ int qemu_pipe(int pipefd[2])
 
     return ret;
 }
+
+int qemu_utimensat(int dirfd, const char *path, const struct timespec *times,
+                   int flags)
+{
+    struct timeval tv[2], tv_now;
+    struct stat st;
+    int i;
+#ifdef CONFIG_UTIMENSAT
+    int ret;
+
+    ret = utimensat(dirfd, path, times, flags);
+    if (ret != -1 || errno != ENOSYS) {
+        return ret;
+    }
+#endif
+    /* Fallback: use utimes() instead of utimensat() */
+
+    /* happy if special cases */
+    if (times[0].tv_nsec == UTIME_OMIT && times[1].tv_nsec == UTIME_OMIT) {
+        return 0;
+    }
+    if (times[0].tv_nsec == UTIME_NOW && times[1].tv_nsec == UTIME_NOW) {
+        return utimes(path, NULL);
+    }
+
+    /* prepare for hard cases */
+    if (times[0].tv_nsec == UTIME_NOW || times[1].tv_nsec == UTIME_NOW) {
+        gettimeofday(&tv_now, NULL);
+    }
+    if (times[0].tv_nsec == UTIME_OMIT || times[1].tv_nsec == UTIME_OMIT) {
+        stat(path, &st);
+    }
+
+    for (i = 0; i < 2; i++) {
+        if (times[i].tv_nsec == UTIME_NOW) {
+            tv[i].tv_sec = tv_now.tv_sec;
+            tv[i].tv_usec = tv_now.tv_usec;
+        } else if (times[i].tv_nsec == UTIME_OMIT) {
+            tv[i].tv_sec = (i == 0) ? st.st_atime : st.st_mtime;
+            tv[i].tv_usec = 0;
+        } else {
+            tv[i].tv_sec = times[i].tv_sec;
+            tv[i].tv_usec = times[i].tv_nsec / 1000;
+        }
+    }
+
+    return utimes(path, &tv[0]);
+}
diff --git a/qemu-os-posix.h b/qemu-os-posix.h
index 353f878..81fd9ab 100644
--- a/qemu-os-posix.h
+++ b/qemu-os-posix.h
@@ -39,4 +39,16 @@ void os_setup_post(void);
 typedef struct timeval qemu_timeval;
 #define qemu_gettimeofday(tp) gettimeofday(tp, NULL)
 
+#ifndef CONFIG_UTIMENSAT
+#ifndef UTIME_NOW
+# define UTIME_NOW     ((1l << 30) - 1l)
+#endif
+#ifndef UTIME_OMIT
+# define UTIME_OMIT    ((1l << 30) - 2l)
+#endif
+#endif
+typedef struct timespec qemu_timespec;
+int qemu_utimensat(int dirfd, const char *path, const qemu_timespec *times,
+    int flags);
+
 #endif
commit 0562c67432991d1cee442615d70fd39e638bec71
Author: Kusanagi Kouichi <slash at ac.auone-net.jp>
Date:   Sat Oct 30 11:52:39 2010 +0900

    virtio-9p: Check the return value of llistxattr.
    
    If llistxattr returned 0, qemu aborts.
    
    Signed-off-by: Kusanagi Kouichi <slash at ac.auone-net.jp>
    Signed-off-by: Venkateswararao Jujjuri <jvrao at linux.vnet.ibm.com>

diff --git a/hw/virtio-9p-xattr.c b/hw/virtio-9p-xattr.c
index 175f372..1aab081 100644
--- a/hw/virtio-9p-xattr.c
+++ b/hw/virtio-9p-xattr.c
@@ -73,6 +73,9 @@ ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
 
     /* Get the actual len */
     xattr_len = llistxattr(rpath(ctx, path), value, 0);
+    if (xattr_len <= 0) {
+        return xattr_len;
+    }
 
     /* Now fetch the xattr and find the actual size */
     orig_value = qemu_malloc(xattr_len);
commit d04e2826f5509092c8f0c6c3db7fa3232d912f7e
Author: Harsh Prateek Bora <harsh at linux.vnet.ibm.com>
Date:   Sun Oct 24 20:54:26 2010 +0530

    hw/virtio9p: Use appropriate debug print functions in TLINK path
    
    Running fsstress with debug enabled causes assertion failure
    because of inappropriate usage of debug print functions.
    With this patch, fsstress passes without assertion failure.
    
    Signed-off-by: Harsh Prateek Bora <harsh at linux.vnet.ibm.com>
    Signed-off-by: Venkateswararao Jujjuri <jvrao at linux.vnet.ibm.com>

diff --git a/hw/virtio-9p-debug.c b/hw/virtio-9p-debug.c
index cff5b07..6b18842 100644
--- a/hw/virtio-9p-debug.c
+++ b/hw/virtio-9p-debug.c
@@ -552,8 +552,8 @@ void pprint_pdu(V9fsPDU *pdu)
         break;
     case P9_TLINK:
         fprintf(llogfile, "TLINK: (");
-        pprint_int32(pdu, 0, &offset, "fid");
-        pprint_str(pdu, 0, &offset, ", oldpath");
+        pprint_int32(pdu, 0, &offset, "dfid");
+        pprint_int32(pdu, 0, &offset, ", fid");
         pprint_str(pdu, 0, &offset, ", newpath");
         break;
     case P9_RLINK:
commit 49594973fb38283e8c469892fe5eac2942d9bd25
Author: Venkateswararao Jujjuri (JV) <jvrao at linux.vnet.ibm.com>
Date:   Fri Oct 22 10:08:45 2010 -0700

    [virtio-9p] Add datasync to server side TFSYNC/RFSYNC for dotl
    
    SYNOPSIS
        size[4] Tfsync tag[2] fid[4] datasync[4]
    
        size[4] Rfsync tag[2]
    
    DESCRIPTION
    
        The Tfsync transaction transfers ("flushes") all modified in-core data of
        file identified by fid to the disk device (or other  permanent  storage
        device)  where that  file  resides.
    
        If datasync flag is specified data will be fleshed but does not flush
        modified metadata unless  that  metadata  is  needed  in order to allow a
        subsequent data retrieval to be correctly handled.
    
    Signed-off-by: Venkateswararao Jujjuri <jvrao at linux.vnet.ibm.com>

diff --git a/hw/file-op-9p.h b/hw/file-op-9p.h
index 21d60b5..c7731c2 100644
--- a/hw/file-op-9p.h
+++ b/hw/file-op-9p.h
@@ -86,7 +86,7 @@ typedef struct FileOperations
     int (*fstat)(FsContext *, int, struct stat *);
     int (*rename)(FsContext *, const char *, const char *);
     int (*truncate)(FsContext *, const char *, off_t);
-    int (*fsync)(FsContext *, int);
+    int (*fsync)(FsContext *, int, int);
     int (*statfs)(FsContext *s, const char *path, struct statfs *stbuf);
     ssize_t (*lgetxattr)(FsContext *, const char *,
                          const char *, void *, size_t);
diff --git a/hw/virtio-9p-local.c b/hw/virtio-9p-local.c
index 0d52020..656bfb3 100644
--- a/hw/virtio-9p-local.c
+++ b/hw/virtio-9p-local.c
@@ -490,9 +490,13 @@ static int local_remove(FsContext *ctx, const char *path)
     return remove(rpath(ctx, path));
 }
 
-static int local_fsync(FsContext *ctx, int fd)
+static int local_fsync(FsContext *ctx, int fd, int datasync)
 {
-    return fsync(fd);
+    if (datasync) {
+        return qemu_fdatasync(fd);
+    } else {
+        return fsync(fd);
+    }
 }
 
 static int local_statfs(FsContext *s, const char *path, struct statfs *stbuf)
diff --git a/hw/virtio-9p.c b/hw/virtio-9p.c
index daade77..7c59988 100644
--- a/hw/virtio-9p.c
+++ b/hw/virtio-9p.c
@@ -248,9 +248,9 @@ static int v9fs_do_remove(V9fsState *s, V9fsString *path)
     return s->ops->remove(&s->ctx, path->data);
 }
 
-static int v9fs_do_fsync(V9fsState *s, int fd)
+static int v9fs_do_fsync(V9fsState *s, int fd, int datasync)
 {
-    return s->ops->fsync(&s->ctx, fd);
+    return s->ops->fsync(&s->ctx, fd, datasync);
 }
 
 static int v9fs_do_statfs(V9fsState *s, V9fsString *path, struct statfs *stbuf)
@@ -1868,16 +1868,17 @@ static void v9fs_fsync(V9fsState *s, V9fsPDU *pdu)
     int32_t fid;
     size_t offset = 7;
     V9fsFidState *fidp;
+    int datasync;
     int err;
 
-    pdu_unmarshal(pdu, offset, "d", &fid);
+    pdu_unmarshal(pdu, offset, "dd", &fid, &datasync);
     fidp = lookup_fid(s, fid);
     if (fidp == NULL) {
         err = -ENOENT;
         v9fs_post_do_fsync(s, pdu, err);
         return;
     }
-    err = v9fs_do_fsync(s, fidp->fs.fd);
+    err = v9fs_do_fsync(s, fidp->fs.fd, datasync);
     v9fs_post_do_fsync(s, pdu, err);
 }
 
@@ -3001,7 +3002,7 @@ static void v9fs_wstat(V9fsState *s, V9fsPDU *pdu)
 
     /* do we need to sync the file? */
     if (donttouch_stat(&vs->v9stat)) {
-        err = v9fs_do_fsync(s, vs->fidp->fs.fd);
+        err = v9fs_do_fsync(s, vs->fidp->fs.fd, 0);
         v9fs_wstat_post_fsync(s, vs, err);
         return;
     }


More information about the Spice-commits mailing list