[Spice-commits] 547 commits - .gitmodules MAINTAINERS Makefile Makefile.hw Makefile.objs Makefile.target Makefile.user arch_init.c arch_init.h async.c audio/audio.c audio/wavaudio.c audio/wavcapture.c balloon.c balloon.h block.c block.h block/curl.c block/nbd.c block/qcow2-cluster.c block/qcow2.c block/qcow2.h block/qed-table.c block/qed.c block/raw-posix.c block/raw.c block/rbd.c block/vmdk.c block/vvfat.c block_int.h blockdev.c bswap.h check-qjson.c cmd.c compiler.h configure console.c console.h cpu-all.h cpu-exec.c cpus.c cpus.h darwin-user/machload.c default-configs/alpha-softmmu.mak default-configs/mips-softmmu.mak default-configs/mips64-softmmu.mak default-configs/mips64el-softmmu.mak default-configs/mipsel-softmmu.mak default-configs/xtensa-softmmu.mak default-configs/xtensaeb-softmmu.mak device_tree.c device_tree.h dma-helpers.c dma.h docs/qdev-device-use.txt docs/tracing.txt dyngen-exec.h elf.h error.c exec-all.h exec.c fpu/softfloat.c fsdev/file-op-9p.h fsdev/qemu-fsdev.c fsdev/qemu-fsdev.h gdbstub.c hmp-commands.hx hmp.c hmp.h host-utils.h hw/9pfs hw/ac97.c hw/adb.c hw/adb.h hw/adlib.c hw/alpha_dp264.c hw/alpha_pci.c hw/alpha_sys.h hw/alpha_typhoon.c hw/an5206.c hw/arm-misc.h hw/armv7m.c hw/axis_dev88.c hw/bonito.c hw/cirrus_vga.c hw/collie.c hw/cs4231a.c hw/cuda.c hw/dec_pci.c hw/devices.h hw/dummy_m68k.c hw/e1000.c hw/es1370.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/flash.h hw/fmopl.c hw/g364fb.c hw/grackle_pci.c hw/gt64xxx.c hw/gumstix.c hw/gus.c hw/heathrow_pic.c hw/hid.c hw/hpet.c hw/i8254.c hw/i8259.c hw/ide hw/integratorcp.c hw/irq.c hw/irq.h hw/isa-bus.c hw/isa.h hw/kvmclock.c hw/leon3.c hw/lm32_boards.c hw/loader.c hw/lsi53c895a.c hw/mainstone.c hw/mcf5208.c hw/milkymist-ac97.c hw/milkymist-hpdmc.c hw/milkymist-hw.h hw/milkymist-memcard.c hw/milkymist-minimac2.c hw/milkymist-pfpu.c hw/milkymist-softusb.c hw/milkymist-sysctl.c hw/milkymist-tmu2.c hw/milkymist-uart.c hw/milkymist-vgafb.c hw/milkymist.c hw/mips.h hw/mips_fulong2e.c hw/mips_jazz.c hw/mips_malta.c hw/mips_mipssim.c hw/mips_r4k.c hw/mipsnet.c hw/mst_fpga.c hw/musicpal.c hw/ne2000.c hw/nseries.c hw/omap.h hw/omap1.c hw/omap2.c hw/omap_gpmc.c hw/omap_intc.c hw/omap_lcdc.c hw/omap_sx1.c hw/omap_uart.c hw/openpic.c hw/openpic.h hw/palm.c hw/pc.c hw/pc.h hw/pc_piix.c hw/pci.c hw/pci.h hw/pci_bridge.c hw/pci_host.c hw/pci_host.h hw/pci_internals.h hw/pci_regs.h hw/pckbd.c hw/pcnet-pci.c hw/petalogix_ml605_mmu.c hw/petalogix_s3adsp1800_mmu.c hw/pflash_cfi01.c hw/pflash_cfi02.c hw/piix4.c hw/piix_pci.c hw/ppc.c hw/ppc.h hw/ppc405.h hw/ppc405_boards.c hw/ppc405_uc.c hw/ppc440.c hw/ppc440.h hw/ppc440_bamboo.c hw/ppc4xx_devs.c hw/ppc4xx_pci.c hw/ppc_booke.c hw/ppc_mac.h hw/ppc_newworld.c hw/ppc_oldworld.c hw/ppc_prep.c hw/ppce500_mpc8544ds.c hw/ppce500_pci.c hw/ppce500_spin.c hw/prep_pci.c hw/pxa.h hw/pxa2xx.c hw/qdev-properties.c hw/qdev.c hw/qxl-logger.c hw/qxl.c hw/r2d.c hw/rtl8139. c hw/sb16.c hw/scsi-bus.c hw/scsi-defs.h hw/scsi-disk.c hw/scsi-generic.c hw/scsi.h hw/sd.c hw/serial.c hw/sh_intc.c hw/sm501.c hw/smc91c111.c hw/soc_dma.h hw/spapr.c hw/spapr.h hw/spapr_hcall.c hw/spapr_llan.c hw/spapr_rtas.c hw/spapr_vio.c hw/spapr_vio.h hw/spapr_vscsi.c hw/spapr_vty.c hw/spitz.c hw/stellaris.c hw/stellaris_enet.c hw/sun4u.c hw/sysbus.c hw/sysbus.h hw/tosa.c hw/tusb6010.c hw/unin_pci.c hw/usb-bus.c hw/usb-ccid.c hw/usb-desc.h hw/usb-ehci.c hw/usb-hub.c hw/usb-msd.c hw/usb-musb.c hw/usb-ohci.c hw/usb-uhci.c hw/usb.c hw/usb.h hw/vga-isa.c hw/vga.c hw/virtex_ml507.c hw/virtio-balloon.c hw/virtio-blk.c hw/virtio.c hw/virtio.h hw/vt82c686.c hw/watchdog.c hw/xen_backend.c hw/xen_backend.h hw/xen_console.c hw/xen_disk.c hw/xen_nic.c hw/xenfb.c hw/xics.c hw/xtensa_dc232b.c hw/xtensa_pic.c hw/xtensa_sample.c hw/z2.c iohandler.c kvm-all.c libcacard/Makefile linux-aio.c linux-headers/asm-powerpc linux-headers/asm-x86 linux-headers/linux linux-user/elfload.c linux-use r/main.c linux-user/qemu.h linux-user/signal.c linux-user/syscall.c memory.c memory.h migration.c mips-dis.c monitor.c nbd.c nbd.h osdep.h oslib-posix.c pc-bios/README pc-bios/mpc8544ds.dtb pc-bios/mpc8544ds.dts pc-bios/openbios-ppc pc-bios/openbios-sparc32 pc-bios/openbios-sparc64 pc-bios/palcode-clipper posix-aio-compat.c ppc64.ld qapi-schema.json qapi/qapi-dealloc-visitor.c qapi/qapi-types-core.h qapi/qmp-input-visitor.c qapi/qmp-output-visitor.c qemu-barrier.h qemu-char.c qemu-common.h qemu-io.c qemu-nbd.c qemu-options.hx qemu-thread-posix.c qemu-thread-win32.c qemu-timer.c qemu-tool.c qerror.c qerror.h qmp-commands.hx qmp.c roms/openbios roms/qemu-palcode rwhandler.c rwhandler.h savevm.c scripts/qapi-commands.py scripts/qapi-types.py scripts/qapi-visit.py scripts/qapi.py scripts/tracetool slirp/libslirp.h slirp/mbuf.h slirp/tcp_input.c slirp/tcp_subr.c softmmu_defs.h softmmu_exec.h softmmu_header.h softmmu_template.h spice-qemu-char.c sysemu.h target-alpha/cpu.h target- alpha/helper.h target-alpha/op_helper.c target-alpha/translate.c target-arm/helper.c target-arm/op_helper.c target-cris/op_helper.c target-i386/cpu.h target-i386/kvm.c target-i386/machine.c target-i386/op_helper.c target-i386/ops_sse.h target-i386/translate.c target-lm32/helper.c target-lm32/op_helper.c target-m68k/op_helper.c target-microblaze/op_helper.c target-mips/op_helper.c target-ppc/cpu.h target-ppc/helper.c target-ppc/kvm.c target-ppc/kvm_ppc.c target-ppc/kvm_ppc.h target-ppc/op_helper.c target-ppc/translate.c target-ppc/translate_init.c target-s390x/op_helper.c target-sh4/op_helper.c target-sparc/cpu.h target-sparc/helper.c target-sparc/op_helper.c target-unicore32/translate.c target-xtensa/cpu.h target-xtensa/gdb-config-dc232b.c target-xtensa/gdb-config-sample-xtensa-core.c target-xtensa/helper.c target-xtensa/helpers.h target-xtensa/machine.c target-xtensa/op_helper.c target-xtensa/translate.c tcg/arm tcg/hppa tcg/i386 tcg/ia64 tcg/mips tcg/ppc tcg/ppc64 tcg/s390 tcg/sparc tcg/tcg-op.h tcg/tcg.c tcg/tcg.h test-qmp-commands.c test-visitor.c tests/test-i386.c tests/xtensa trace-events trace/simple.c ui/keymaps.c ui/sdl.c ui/spice-core.c ui/spice-display.c ui/spice-display.h ui/vnc-tls.c usb-linux.c vl.c xen-all.c xen-mapcache.c xtensa-semi.c

Gerd Hoffmann kraxel at kemper.freedesktop.org
Fri Oct 14 06:23:20 PDT 2011


 .gitmodules                                   |    6 
 MAINTAINERS                                   |   29 
 Makefile                                      |   67 
 Makefile.hw                                   |    1 
 Makefile.objs                                 |   22 
 Makefile.target                               |   29 
 Makefile.user                                 |    4 
 arch_init.c                                   |    7 
 arch_init.h                                   |    1 
 async.c                                       |   24 
 audio/audio.c                                 |    2 
 audio/wavaudio.c                              |   46 
 audio/wavcapture.c                            |   79 
 balloon.c                                     |   10 
 balloon.h                                     |    1 
 block.c                                       |  200 +-
 block.h                                       |   89 
 block/curl.c                                  |   94 -
 block/nbd.c                                   |    5 
 block/qcow2-cluster.c                         |   27 
 block/qcow2.c                                 |   26 
 block/qcow2.h                                 |    1 
 block/qed-table.c                             |    6 
 block/qed.c                                   |    4 
 block/raw-posix.c                             |   21 
 block/raw.c                                   |   13 
 block/rbd.c                                   |  178 +
 block/vmdk.c                                  |  360 +++
 block/vvfat.c                                 |    2 
 block_int.h                                   |   54 
 blockdev.c                                    |   15 
 bswap.h                                       |    3 
 check-qjson.c                                 |    3 
 cmd.c                                         |    2 
 compiler.h                                    |   17 
 configure                                     |   64 
 console.c                                     |   17 
 console.h                                     |    5 
 cpu-all.h                                     |    1 
 cpu-exec.c                                    |   14 
 cpus.c                                        |   25 
 cpus.h                                        |    1 
 darwin-user/machload.c                        |    4 
 default-configs/alpha-softmmu.mak             |    2 
 default-configs/mips-softmmu.mak              |    1 
 default-configs/mips64-softmmu.mak            |    1 
 default-configs/mips64el-softmmu.mak          |    1 
 default-configs/mipsel-softmmu.mak            |    1 
 default-configs/xtensa-softmmu.mak            |    1 
 default-configs/xtensaeb-softmmu.mak          |    1 
 device_tree.c                                 |   92 
 device_tree.h                                 |    2 
 dma-helpers.c                                 |   58 
 dma.h                                         |   10 
 docs/qdev-device-use.txt                      |    2 
 docs/tracing.txt                              |   29 
 dyngen-exec.h                                 |   12 
 elf.h                                         |    2 
 error.c                                       |    4 
 exec-all.h                                    |   14 
 exec.c                                        |    5 
 fpu/softfloat.c                               |    5 
 fsdev/file-op-9p.h                            |   54 
 fsdev/qemu-fsdev.c                            |    1 
 fsdev/qemu-fsdev.h                            |    1 
 gdbstub.c                                     |  148 +
 hmp-commands.hx                               |   15 
 hmp.c                                         |  116 +
 hmp.h                                         |   31 
 host-utils.h                                  |    2 
 hw/9pfs/codir.c                               |   73 
 hw/9pfs/cofile.c                              |  123 +
 hw/9pfs/cofs.c                                |  195 +-
 hw/9pfs/coxattr.c                             |   41 
 hw/9pfs/virtio-9p-coth.c                      |    4 
 hw/9pfs/virtio-9p-coth.h                      |   72 
 hw/9pfs/virtio-9p-debug.c                     |    2 
 hw/9pfs/virtio-9p-device.c                    |   12 
 hw/9pfs/virtio-9p-handle.c                    |  611 ++++++
 hw/9pfs/virtio-9p-local.c                     |  213 +-
 hw/9pfs/virtio-9p.c                           | 1164 ++++++++----
 hw/9pfs/virtio-9p.h                           |   76 
 hw/ac97.c                                     |    1 
 hw/adb.c                                      |    2 
 hw/adb.h                                      |   67 
 hw/adlib.c                                    |    5 
 hw/alpha_dp264.c                              |  177 +
 hw/alpha_pci.c                                |  134 +
 hw/alpha_sys.h                                |   24 
 hw/alpha_typhoon.c                            |  820 ++++++++
 hw/an5206.c                                   |   12 
 hw/arm-misc.h                                 |    5 
 hw/armv7m.c                                   |   22 
 hw/axis_dev88.c                               |   16 
 hw/bonito.c                                   |   24 
 hw/cirrus_vga.c                               |    6 
 hw/collie.c                                   |    7 
 hw/cs4231a.c                                  |   38 
 hw/cuda.c                                     |   29 
 hw/dec_pci.c                                  |   13 
 hw/devices.h                                  |    6 
 hw/dummy_m68k.c                               |    7 
 hw/e1000.c                                    |    5 
 hw/es1370.c                                   |    1 
 hw/esp.c                                      |   70 
 hw/etraxfs_dma.c                              |   55 
 hw/etraxfs_eth.c                              |   30 
 hw/etraxfs_pic.c                              |   30 
 hw/etraxfs_ser.c                              |   33 
 hw/etraxfs_timer.c                            |   31 
 hw/fdc.c                                      |  101 -
 hw/flash.h                                    |   13 
 hw/fmopl.c                                    |    2 
 hw/g364fb.c                                   |   16 
 hw/grackle_pci.c                              |   24 
 hw/gt64xxx.c                                  |   13 
 hw/gumstix.c                                  |   13 
 hw/gus.c                                      |   11 
 hw/heathrow_pic.c                             |    2 
 hw/hid.c                                      |    2 
 hw/hpet.c                                     |    8 
 hw/i8254.c                                    |   16 
 hw/i8259.c                                    |   65 
 hw/ide/ahci.c                                 |   54 
 hw/ide/ahci.h                                 |   10 
 hw/ide/atapi.c                                |   58 
 hw/ide/cmd646.c                               |    1 
 hw/ide/core.c                                 |  199 +-
 hw/ide/ich.c                                  |   28 
 hw/ide/internal.h                             |  177 +
 hw/ide/isa.c                                  |    1 
 hw/ide/macio.c                                |    3 
 hw/ide/microdrive.c                           |    1 
 hw/ide/mmio.c                                 |    1 
 hw/ide/pci.c                                  |    3 
 hw/ide/piix.c                                 |    7 
 hw/ide/via.c                                  |    1 
 hw/integratorcp.c                             |   44 
 hw/irq.c                                      |   14 
 hw/irq.h                                      |    5 
 hw/isa-bus.c                                  |   14 
 hw/isa.h                                      |    7 
 hw/kvmclock.c                                 |    5 
 hw/leon3.c                                    |   15 
 hw/lm32_boards.c                              |   23 
 hw/loader.c                                   |    4 
 hw/lsi53c895a.c                               |   11 
 hw/mainstone.c                                |   22 
 hw/mcf5208.c                                  |   72 
 hw/milkymist-ac97.c                           |   32 
 hw/milkymist-hpdmc.c                          |   32 
 hw/milkymist-hw.h                             |    5 
 hw/milkymist-memcard.c                        |   32 
 hw/milkymist-minimac2.c                       |   43 
 hw/milkymist-pfpu.c                           |   33 
 hw/milkymist-softusb.c                        |   48 
 hw/milkymist-sysctl.c                         |   32 
 hw/milkymist-tmu2.c                           |   32 
 hw/milkymist-uart.c                           |  104 -
 hw/milkymist-vgafb.c                          |   33 
 hw/milkymist.c                                |   27 
 hw/mips.h                                     |    3 
 hw/mips_fulong2e.c                            |   27 
 hw/mips_jazz.c                                |  119 -
 hw/mips_malta.c                               |  134 -
 hw/mips_mipssim.c                             |   33 
 hw/mips_r4k.c                                 |   54 
 hw/mipsnet.c                                  |  106 -
 hw/mst_fpga.c                                 |    4 
 hw/musicpal.c                                 |  269 +-
 hw/ne2000.c                                   |    3 
 hw/nseries.c                                  |    4 
 hw/omap.h                                     |   45 
 hw/omap1.c                                    |  971 +++++-----
 hw/omap2.c                                    |   98 -
 hw/omap_gpmc.c                                |    9 
 hw/omap_intc.c                                |  175 +
 hw/omap_lcdc.c                                |    7 
 hw/omap_sx1.c                                 |   12 
 hw/omap_uart.c                                |   27 
 hw/openpic.c                                  |  496 ++---
 hw/openpic.h                                  |    4 
 hw/palm.c                                     |    4 
 hw/pc.c                                       |    8 
 hw/pc.h                                       |   12 
 hw/pc_piix.c                                  |   38 
 hw/pci.c                                      |   95 -
 hw/pci.h                                      |    7 
 hw/pci_bridge.c                               |   85 
 hw/pci_host.c                                 |   86 
 hw/pci_host.h                                 |   16 
 hw/pci_internals.h                            |   19 
 hw/pci_regs.h                                 |    1 
 hw/pckbd.c                                    |   59 
 hw/pcnet-pci.c                                |    2 
 hw/petalogix_ml605_mmu.c                      |   11 
 hw/petalogix_s3adsp1800_mmu.c                 |    5 
 hw/pflash_cfi01.c                             |   79 
 hw/pflash_cfi02.c                             |   96 -
 hw/piix4.c                                    |    2 
 hw/piix_pci.c                                 |   15 
 hw/ppc.c                                      |  138 -
 hw/ppc.h                                      |   37 
 hw/ppc405.h                                   |   22 
 hw/ppc405_boards.c                            |   62 
 hw/ppc405_uc.c                                |   42 
 hw/ppc440.c                                   |   16 
 hw/ppc440.h                                   |    6 
 hw/ppc440_bamboo.c                            |   21 
 hw/ppc4xx_devs.c                              |    2 
 hw/ppc4xx_pci.c                               |   10 
 hw/ppc_booke.c                                |  254 ++
 hw/ppc_mac.h                                  |   42 
 hw/ppc_newworld.c                             |    5 
 hw/ppc_oldworld.c                             |    5 
 hw/ppc_prep.c                                 |    4 
 hw/ppce500_mpc8544ds.c                        |  202 +-
 hw/ppce500_pci.c                              |   21 
 hw/ppce500_spin.c                             |  215 ++
 hw/prep_pci.c                                 |   12 
 hw/pxa.h                                      |    7 
 hw/pxa2xx.c                                   |   42 
 hw/qdev-properties.c                          |    8 
 hw/qdev.c                                     |    6 
 hw/qxl-logger.c                               |    2 
 hw/qxl.c                                      |   33 
 hw/r2d.c                                      |    7 
 hw/rtl8139.c                                  |    2 
 hw/sb16.c                                     |    8 
 hw/scsi-bus.c                                 |   42 
 hw/scsi-defs.h                                |    8 
 hw/scsi-disk.c                                |  314 ++-
 hw/scsi-generic.c                             |    7 
 hw/scsi.h                                     |    5 
 hw/sd.c                                       |   14 
 hw/serial.c                                   |  162 -
 hw/sh_intc.c                                  |    9 
 hw/sm501.c                                    |   15 
 hw/smc91c111.c                                |   29 
 hw/soc_dma.h                                  |    8 
 hw/spapr.c                                    |   77 
 hw/spapr.h                                    |    7 
 hw/spapr_hcall.c                              |  220 ++
 hw/spapr_llan.c                               |   11 
 hw/spapr_rtas.c                               |   24 
 hw/spapr_vio.c                                |   10 
 hw/spapr_vio.h                                |   17 
 hw/spapr_vscsi.c                              |   13 
 hw/spapr_vty.c                                |   10 
 hw/spitz.c                                    |   14 
 hw/stellaris.c                                |    5 
 hw/stellaris_enet.c                           |   29 
 hw/sun4u.c                                    |   17 
 hw/sysbus.c                                   |   29 
 hw/sysbus.h                                   |    8 
 hw/tosa.c                                     |   14 
 hw/tusb6010.c                                 |   11 
 hw/unin_pci.c                                 |  100 -
 hw/usb-bus.c                                  |  110 -
 hw/usb-ccid.c                                 |  248 --
 hw/usb-desc.h                                 |    2 
 hw/usb-ehci.c                                 |   67 
 hw/usb-hub.c                                  |   12 
 hw/usb-msd.c                                  |    2 
 hw/usb-musb.c                                 |   26 
 hw/usb-ohci.c                                 |    7 
 hw/usb-uhci.c                                 |   13 
 hw/usb.c                                      |   37 
 hw/usb.h                                      |   11 
 hw/vga-isa.c                                  |    1 
 hw/vga.c                                      |    8 
 hw/virtex_ml507.c                             |   20 
 hw/virtio-balloon.c                           |    2 
 hw/virtio-blk.c                               |   22 
 hw/virtio.c                                   |   28 
 hw/virtio.h                                   |   11 
 hw/vt82c686.c                                 |   14 
 hw/watchdog.c                                 |    2 
 hw/xen_backend.c                              |   40 
 hw/xen_backend.h                              |    3 
 hw/xen_console.c                              |    4 
 hw/xen_disk.c                                 |    3 
 hw/xen_nic.c                                  |    3 
 hw/xenfb.c                                    |   29 
 hw/xics.c                                     |   19 
 hw/xtensa_dc232b.c                            |  116 +
 hw/xtensa_pic.c                               |  134 +
 hw/xtensa_sample.c                            |  107 +
 hw/z2.c                                       |    6 
 iohandler.c                                   |    7 
 kvm-all.c                                     |    2 
 libcacard/Makefile                            |    4 
 linux-aio.c                                   |   12 
 linux-headers/asm-powerpc/kvm.h               |   57 
 linux-headers/asm-x86/kvm_para.h              |   14 
 linux-headers/linux/kvm.h                     |   75 
 linux-headers/linux/kvm_para.h                |    1 
 linux-user/elfload.c                          |   56 
 linux-user/main.c                             |  674 ++++---
 linux-user/qemu.h                             |    6 
 linux-user/signal.c                           |    5 
 linux-user/syscall.c                          |   68 
 memory.c                                      |  167 +
 memory.h                                      |    3 
 migration.c                                   |   14 
 mips-dis.c                                    |    2 
 monitor.c                                     |  300 ---
 nbd.c                                         |   45 
 nbd.h                                         |   24 
 osdep.h                                       |    7 
 oslib-posix.c                                 |   14 
 pc-bios/README                                |    9 
 pc-bios/mpc8544ds.dtb                         |binary
 pc-bios/mpc8544ds.dts                         |   12 
 pc-bios/openbios-ppc                          |binary
 pc-bios/openbios-sparc32                      |binary
 pc-bios/openbios-sparc64                      |binary
 pc-bios/palcode-clipper                       |binary
 posix-aio-compat.c                            |   38 
 ppc64.ld                                      |    4 
 qapi-schema.json                              |  273 ++
 qapi/qapi-dealloc-visitor.c                   |   34 
 qapi/qapi-types-core.h                        |    3 
 qapi/qmp-input-visitor.c                      |    4 
 qapi/qmp-output-visitor.c                     |   20 
 qemu-barrier.h                                |   34 
 qemu-char.c                                   |   49 
 qemu-common.h                                 |    3 
 qemu-io.c                                     |    3 
 qemu-nbd.c                                    |   15 
 qemu-options.hx                               |   14 
 qemu-thread-posix.c                           |    2 
 qemu-thread-win32.c                           |    2 
 qemu-timer.c                                  |    9 
 qemu-tool.c                                   |    4 
 qerror.c                                      |   37 
 qerror.h                                      |    5 
 qmp-commands.hx                               |   78 
 qmp.c                                         |   92 
 roms/openbios                                 |    1 
 roms/qemu-palcode                             |    1 
 rwhandler.c                                   |   87 
 rwhandler.h                                   |   27 
 savevm.c                                      |   12 
 scripts/qapi-commands.py                      |   98 -
 scripts/qapi-types.py                         |   12 
 scripts/qapi-visit.py                         |    4 
 scripts/qapi.py                               |    4 
 scripts/tracetool                             |   20 
 slirp/libslirp.h                              |    2 
 slirp/mbuf.h                                  |    5 
 slirp/tcp_input.c                             |   31 
 slirp/tcp_subr.c                              |    2 
 softmmu_defs.h                                |    8 
 softmmu_exec.h                                |   12 
 softmmu_header.h                              |    9 
 softmmu_template.h                            |   13 
 spice-qemu-char.c                             |    2 
 sysemu.h                                      |   24 
 target-alpha/cpu.h                            |    4 
 target-alpha/helper.h                         |    5 
 target-alpha/op_helper.c                      |   32 
 target-alpha/translate.c                      |   77 
 target-arm/helper.c                           |    2 
 target-arm/op_helper.c                        |    7 
 target-cris/op_helper.c                       |    7 
 target-i386/cpu.h                             |    9 
 target-i386/kvm.c                             |   20 
 target-i386/machine.c                         |    1 
 target-i386/op_helper.c                       |   13 
 target-i386/ops_sse.h                         |   36 
 target-i386/translate.c                       |   79 
 target-lm32/helper.c                          |    1 
 target-lm32/op_helper.c                       |    7 
 target-m68k/op_helper.c                       |    7 
 target-microblaze/op_helper.c                 |    7 
 target-mips/op_helper.c                       |    7 
 target-ppc/cpu.h                              |   43 
 target-ppc/helper.c                           |   95 -
 target-ppc/kvm.c                              |  211 ++
 target-ppc/kvm_ppc.c                          |   67 
 target-ppc/kvm_ppc.h                          |   44 
 target-ppc/op_helper.c                        |    7 
 target-ppc/translate.c                        |   28 
 target-ppc/translate_init.c                   |   65 
 target-s390x/op_helper.c                      |    7 
 target-sh4/op_helper.c                        |    7 
 target-sparc/cpu.h                            |    7 
 target-sparc/helper.c                         |   84 
 target-sparc/op_helper.c                      |   13 
 target-unicore32/translate.c                  |   16 
 target-xtensa/cpu.h                           |  425 ++++
 target-xtensa/gdb-config-dc232b.c             |  261 ++
 target-xtensa/gdb-config-sample-xtensa-core.c |  375 ++++
 target-xtensa/helper.c                        |  763 ++++++++
 target-xtensa/helpers.h                       |   32 
 target-xtensa/machine.c                       |   38 
 target-xtensa/op_helper.c                     |  676 +++++++
 target-xtensa/translate.c                     | 2414 ++++++++++++++++++++++++++
 tcg/arm/tcg-target.c                          |   15 
 tcg/arm/tcg-target.h                          |    1 
 tcg/hppa/tcg-target.h                         |    4 
 tcg/i386/tcg-target.c                         |   28 
 tcg/i386/tcg-target.h                         |    9 
 tcg/ia64/tcg-target.c                         |   24 
 tcg/ia64/tcg-target.h                         |    2 
 tcg/mips/tcg-target.h                         |    1 
 tcg/ppc/tcg-target.h                          |    1 
 tcg/ppc64/tcg-target.c                        |    4 
 tcg/ppc64/tcg-target.h                        |    1 
 tcg/s390/tcg-target.c                         |    9 
 tcg/s390/tcg-target.h                         |    6 
 tcg/sparc/tcg-target.c                        |    6 
 tcg/sparc/tcg-target.h                        |    6 
 tcg/tcg-op.h                                  |    4 
 tcg/tcg.c                                     |   18 
 tcg/tcg.h                                     |   17 
 test-qmp-commands.c                           |   29 
 test-visitor.c                                |   48 
 tests/test-i386.c                             |    2 
 tests/xtensa/Makefile                         |   74 
 tests/xtensa/crt.S                            |   24 
 tests/xtensa/linker.ld                        |  112 +
 tests/xtensa/macros.inc                       |   68 
 tests/xtensa/test_b.S                         |  221 ++
 tests/xtensa/test_bi.S                        |  103 +
 tests/xtensa/test_boolean.S                   |   23 
 tests/xtensa/test_bz.S                        |   57 
 tests/xtensa/test_clamps.S                    |   42 
 tests/xtensa/test_fail.S                      |    9 
 tests/xtensa/test_interrupt.S                 |  194 ++
 tests/xtensa/test_loop.S                      |   77 
 tests/xtensa/test_max.S                       |   81 
 tests/xtensa/test_min.S                       |   81 
 tests/xtensa/test_mmu.S                       |  318 +++
 tests/xtensa/test_mul16.S                     |   83 
 tests/xtensa/test_mul32.S                     |   20 
 tests/xtensa/test_nsa.S                       |   59 
 tests/xtensa/test_pipeline.S                  |  157 +
 tests/xtensa/test_quo.S                       |  147 +
 tests/xtensa/test_rem.S                       |  147 +
 tests/xtensa/test_rst0.S                      |  148 +
 tests/xtensa/test_sar.S                       |  111 +
 tests/xtensa/test_sext.S                      |   69 
 tests/xtensa/test_shift.S                     |  206 ++
 tests/xtensa/test_timer.S                     |  115 +
 tests/xtensa/test_windowed.S                  |  302 +++
 tests/xtensa/vectors.S                        |   39 
 trace-events                                  |  120 +
 trace/simple.c                                |   76 
 ui/keymaps.c                                  |    2 
 ui/sdl.c                                      |    6 
 ui/spice-core.c                               |   25 
 ui/spice-display.c                            |    8 
 ui/spice-display.h                            |    4 
 ui/vnc-tls.c                                  |   68 
 usb-linux.c                                   |  450 ++--
 vl.c                                          |  153 +
 xen-all.c                                     |   14 
 xen-mapcache.c                                |   29 
 xtensa-semi.c                                 |  224 ++
 461 files changed, 21822 insertions(+), 6125 deletions(-)

New commits:
commit ebffe2afceb1a17b5d134b5debf553955fe5ea1a
Merge: 057643f... 5bc465e...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon Oct 10 08:21:46 2011 -0500

    Merge remote-tracking branch 'qmp/queue/qmp' into staging

diff --cc monitor.c
index da13471,c226879..31b212a
--- a/monitor.c
+++ b/monitor.c
@@@ -62,8 -61,11 +62,10 @@@
  #ifdef CONFIG_TRACE_SIMPLE
  #include "trace/simple.h"
  #endif
 -#include "trace/control.h"
  #include "ui/qemu-spice.h"
  #include "memory.h"
+ #include "qmp-commands.h"
+ #include "hmp.h"
  
  //#define DEBUG
  //#define DEBUG_COMPLETION
commit 057643f6c4751651ab640edb9b445cb3816edffc
Merge: 9f047b8... ca8a277...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon Oct 10 08:09:02 2011 -0500

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

commit 9f047b8948f43dddb0ee2a391939999fab13eaf4
Merge: 8acbc9b... bfc2455...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon Oct 10 08:07:51 2011 -0500

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

commit 8acbc9b21d757a6be4f8492e547b8159703a0547
Author: malc <av1474 at comtv.ru>
Date:   Sun Oct 9 19:04:16 2011 +0400

    Restore consistent formatting
    Signed-off-by: malc <av1474 at comtv.ru>

diff --git a/hw/cs4231a.c b/hw/cs4231a.c
index e16665e..a7e03a3 100644
--- a/hw/cs4231a.c
+++ b/hw/cs4231a.c
@@ -346,7 +346,7 @@ static void cs_reset_voices (CSState *s, uint32_t val)
     }
 }
 
-static uint64_t cs_read(void *opaque, target_phys_addr_t addr, unsigned size)
+static uint64_t cs_read (void *opaque, target_phys_addr_t addr, unsigned size)
 {
     CSState *s = opaque;
     uint32_t saddr, iaddr, ret;
@@ -383,8 +383,8 @@ static uint64_t cs_read(void *opaque, target_phys_addr_t addr, unsigned size)
     return ret;
 }
 
-static void cs_write(void *opaque, target_phys_addr_t addr,
-                     uint64_t val64, unsigned size)
+static void cs_write (void *opaque, target_phys_addr_t addr,
+                      uint64_t val64, unsigned size)
 {
     CSState *s = opaque;
     uint32_t saddr, iaddr, val;
@@ -647,8 +647,8 @@ static int cs4231a_initfn (ISADevice *dev)
 
     isa_init_irq (dev, &s->pic, s->irq);
 
-    memory_region_init_io(&s->ioports, &cs_ioport_ops, s, "cs4231a", 4);
-    isa_register_ioport(dev, &s->ioports, s->port);
+    memory_region_init_io (&s->ioports, &cs_ioport_ops, s, "cs4231a", 4);
+    isa_register_ioport (dev, &s->ioports, s->port);
 
     DMA_register_channel (s->dma, cs_dma_read, s);
 
diff --git a/hw/gus.c b/hw/gus.c
index 37e543a..a65192d 100644
--- a/hw/gus.c
+++ b/hw/gus.c
@@ -234,7 +234,7 @@ static const VMStateDescription vmstate_gus = {
 
 static int gus_initfn (ISADevice *dev)
 {
-    GUSState *s = DO_UPCAST(GUSState, dev, dev);
+    GUSState *s = DO_UPCAST (GUSState, dev, dev);
     struct audsettings as;
 
     AUD_register_card ("gus", &s->card);
@@ -264,24 +264,23 @@ 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);
+    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);
+    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);
-
+    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);
+    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/sb16.c b/hw/sb16.c
index a76df1b..aca52e0 100644
--- a/hw/sb16.c
+++ b/hw/sb16.c
@@ -1368,20 +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]);
+        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]);
+        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);
+    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);
+    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);
commit df2921d326d0903ff684759ac8508f87396b7018
Merge: 306f66b... 02d6516...
Author: Avi Kivity <avi at redhat.com>
Date:   Sun Oct 9 13:11:50 2011 +0200

    Merge remote-tracking branch 'upstream' into memory/batch
    
    * upstream: (87 commits)
      target-alpha: Fix compilation errors for 32 bit hosts
      target-alpha: Add high-resolution access to wall clock and an alarm.
      target-alpha: Implement HALT IPR.
      target-alpha: Implement WAIT IPR.
      target-alpha: Add CLIPPER emulation.
      target-alpha: Add custom PALcode image for CLIPPER emulation.
      target-alpha: Honor icount for RPCC instruction.
      tcg/s390: Remove unused tcg_out_addi()
      tcg/ia64: Remove unused tcg_out_addi()
      ARM: fix segfault
      ppc64: Fix linker script
      pseries: Implement set-time-of-day RTAS function
      pseries: Refactor spapr irq allocation
      PPC: Clean up BookE timer code
      PPC: booke timers
      KVM: PPC: Use HIOR setting for -M pseries with PR KVM
      KVM: Update kernel headers
      KVM: Update kernel headers
      PPC: Fix heathrow PIC to use little endian MMIO
      PPC: Fix via-cuda memory registration
      ...
    
    Conflicts:
    	hw/milkymist-uart.c
    	hw/ppce500_mpc8544ds.c
    
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --cc hw/milkymist-uart.c
index 128cd8c,d836462..5404ca9
--- a/hw/milkymist-uart.c
+++ b/hw/milkymist-uart.c
@@@ -33,20 -36,48 +36,50 @@@ enum 
      R_MAX
  };
  
+ enum {
+     STAT_THRE   = (1<<0),
+     STAT_RX_EVT = (1<<1),
+     STAT_TX_EVT = (1<<2),
+ };
+ 
+ enum {
+     CTRL_RX_IRQ_EN = (1<<0),
+     CTRL_TX_IRQ_EN = (1<<1),
+     CTRL_THRU_EN   = (1<<2),
+ };
+ 
+ enum {
+     DBG_BREAK_EN = (1<<0),
+ };
+ 
  struct MilkymistUartState {
      SysBusDevice busdev;
 +    MemoryRegion regs_region;
      CharDriverState *chr;
- 
-     qemu_irq rx_irq;
-     qemu_irq tx_irq;
+     qemu_irq irq;
  
      uint32_t regs[R_MAX];
  };
  typedef struct MilkymistUartState MilkymistUartState;
  
+ static void uart_update_irq(MilkymistUartState *s)
+ {
+     int rx_event = s->regs[R_STAT] & STAT_RX_EVT;
+     int tx_event = s->regs[R_STAT] & STAT_TX_EVT;
+     int rx_irq_en = s->regs[R_CTRL] & CTRL_RX_IRQ_EN;
+     int tx_irq_en = s->regs[R_CTRL] & CTRL_TX_IRQ_EN;
+ 
+     if ((rx_irq_en && rx_event) || (tx_irq_en && tx_event)) {
+         trace_milkymist_uart_raise_irq();
+         qemu_irq_raise(s->irq);
+     } else {
+         trace_milkymist_uart_lower_irq();
+         qemu_irq_lower(s->irq);
+     }
+ }
+ 
 -static uint32_t uart_read(void *opaque, target_phys_addr_t addr)
 +static uint64_t uart_read(void *opaque, target_phys_addr_t addr,
 +                          unsigned size)
  {
      MilkymistUartState *s = opaque;
      uint32_t r = 0;
@@@ -95,16 -136,20 +139,18 @@@ static void uart_write(void *opaque, ta
                  TARGET_FMT_plx, addr << 2);
          break;
      }
+ 
+     uart_update_irq(s);
  }
  
 -static CPUReadMemoryFunc * const uart_read_fn[] = {
 -    NULL,
 -    NULL,
 -    &uart_read,
 -};
 -
 -static CPUWriteMemoryFunc * const uart_write_fn[] = {
 -    NULL,
 -    NULL,
 -    &uart_write,
 +static const MemoryRegionOps uart_mmio_ops = {
 +    .read = uart_read,
 +    .write = uart_write,
 +    .valid = {
 +        .min_access_size = 4,
 +        .max_access_size = 4,
 +    },
 +    .endianness = DEVICE_NATIVE_ENDIAN,
  };
  
  static void uart_rx(void *opaque, const uint8_t *buf, int size)
@@@ -138,13 -191,13 +192,12 @@@ static void milkymist_uart_reset(Device
  static int milkymist_uart_init(SysBusDevice *dev)
  {
      MilkymistUartState *s = FROM_SYSBUS(typeof(*s), dev);
 -    int uart_regs;
  
-     sysbus_init_irq(dev, &s->rx_irq);
-     sysbus_init_irq(dev, &s->tx_irq);
+     sysbus_init_irq(dev, &s->irq);
  
 -    uart_regs = cpu_register_io_memory(uart_read_fn, uart_write_fn, s,
 -            DEVICE_NATIVE_ENDIAN);
 -    sysbus_init_mmio(dev, R_MAX * 4, uart_regs);
 +    memory_region_init_io(&s->regs_region, &uart_mmio_ops, s,
 +            "milkymist-uart", R_MAX * 4);
 +    sysbus_init_mmio_region(dev, &s->regs_region);
  
      s->chr = qdev_init_chardev(&dev->qdev);
      if (s->chr) {
diff --cc hw/openpic.c
index 88e997e,43b8f27..22fc275
--- a/hw/openpic.c
+++ b/hw/openpic.c
@@@ -1541,140 -1570,121 +1574,136 @@@ static uint32_t mpic_src_msi_read (voi
      return retval;
  }
  
 -static CPUWriteMemoryFunc * const mpic_glb_write[] = {
 -    &openpic_buggy_write,
 -    &openpic_buggy_write,
 -    &openpic_gbl_write,
 -};
 -
 -static CPUReadMemoryFunc * const mpic_glb_read[] = {
 -    &openpic_buggy_read,
 -    &openpic_buggy_read,
 -    &openpic_gbl_read,
 -};
 -
 -static CPUWriteMemoryFunc * const mpic_tmr_write[] = {
 -    &openpic_buggy_write,
 -    &openpic_buggy_write,
 -    &mpic_timer_write,
 +static const MemoryRegionOps mpic_glb_ops = {
 +    .old_mmio = {
 +        .write = { openpic_buggy_write,
 +                   openpic_buggy_write,
 +                   openpic_gbl_write,
 +        },
 +        .read  = { openpic_buggy_read,
 +                   openpic_buggy_read,
 +                   openpic_gbl_read,
 +        },
 +    },
 +    .endianness = DEVICE_BIG_ENDIAN,
  };
  
 -static CPUReadMemoryFunc * const mpic_tmr_read[] = {
 -    &openpic_buggy_read,
 -    &openpic_buggy_read,
 -    &mpic_timer_read,
 +static const MemoryRegionOps mpic_tmr_ops = {
 +    .old_mmio = {
 +        .write = { openpic_buggy_write,
 +                   openpic_buggy_write,
 +                   mpic_timer_write,
 +        },
 +        .read  = { openpic_buggy_read,
 +                   openpic_buggy_read,
 +                   mpic_timer_read,
 +        },
 +    },
 +    .endianness = DEVICE_BIG_ENDIAN,
  };
  
 -static CPUWriteMemoryFunc * const mpic_cpu_write[] = {
 -    &openpic_buggy_write,
 -    &openpic_buggy_write,
 -    &openpic_cpu_write,
 +static const MemoryRegionOps mpic_cpu_ops = {
 +    .old_mmio = {
 +        .write = { openpic_buggy_write,
 +                   openpic_buggy_write,
 +                   openpic_cpu_write,
 +        },
 +        .read  = { openpic_buggy_read,
 +                   openpic_buggy_read,
 +                   openpic_cpu_read,
 +        },
 +    },
 +    .endianness = DEVICE_BIG_ENDIAN,
  };
  
 -static CPUReadMemoryFunc * const mpic_cpu_read[] = {
 -    &openpic_buggy_read,
 -    &openpic_buggy_read,
 -    &openpic_cpu_read,
 +static const MemoryRegionOps mpic_ext_ops = {
 +    .old_mmio = {
 +        .write = { openpic_buggy_write,
 +                   openpic_buggy_write,
 +                   mpic_src_ext_write,
 +        },
 +        .read  = { openpic_buggy_read,
 +                   openpic_buggy_read,
 +                   mpic_src_ext_read,
 +        },
 +    },
 +    .endianness = DEVICE_BIG_ENDIAN,
  };
  
 -static CPUWriteMemoryFunc * const mpic_ext_write[] = {
 -    &openpic_buggy_write,
 -    &openpic_buggy_write,
 -    &mpic_src_ext_write,
 +static const MemoryRegionOps mpic_int_ops = {
 +    .old_mmio = {
 +        .write = { openpic_buggy_write,
 +                   openpic_buggy_write,
 +                   mpic_src_int_write,
 +        },
 +        .read  = { openpic_buggy_read,
 +                   openpic_buggy_read,
 +                   mpic_src_int_read,
 +        },
 +    },
 +    .endianness = DEVICE_BIG_ENDIAN,
  };
  
 -static CPUReadMemoryFunc * const mpic_ext_read[] = {
 -    &openpic_buggy_read,
 -    &openpic_buggy_read,
 -    &mpic_src_ext_read,
 +static const MemoryRegionOps mpic_msg_ops = {
 +    .old_mmio = {
 +        .write = { openpic_buggy_write,
 +                   openpic_buggy_write,
 +                   mpic_src_msg_write,
 +        },
 +        .read  = { openpic_buggy_read,
 +                   openpic_buggy_read,
 +                   mpic_src_msg_read,
 +        },
 +    },
 +    .endianness = DEVICE_BIG_ENDIAN,
  };
  
 -static CPUWriteMemoryFunc * const mpic_int_write[] = {
 -    &openpic_buggy_write,
 -    &openpic_buggy_write,
 -    &mpic_src_int_write,
 +static const MemoryRegionOps mpic_msi_ops = {
 +    .old_mmio = {
 +        .write = { openpic_buggy_write,
 +                   openpic_buggy_write,
 +                   mpic_src_msi_write,
 +        },
 +        .read  = { openpic_buggy_read,
 +                   openpic_buggy_read,
 +                   mpic_src_msi_read,
 +        },
 +    },
 +    .endianness = DEVICE_BIG_ENDIAN,
  };
  
 -static CPUReadMemoryFunc * const mpic_int_read[] = {
 -    &openpic_buggy_read,
 -    &openpic_buggy_read,
 -    &mpic_src_int_read,
 -};
 -
 -static CPUWriteMemoryFunc * const mpic_msg_write[] = {
 -    &openpic_buggy_write,
 -    &openpic_buggy_write,
 -    &mpic_src_msg_write,
 -};
 -
 -static CPUReadMemoryFunc * const mpic_msg_read[] = {
 -    &openpic_buggy_read,
 -    &openpic_buggy_read,
 -    &mpic_src_msg_read,
 -};
 -static CPUWriteMemoryFunc * const mpic_msi_write[] = {
 -    &openpic_buggy_write,
 -    &openpic_buggy_write,
 -    &mpic_src_msi_write,
 -};
 -
 -static CPUReadMemoryFunc * const mpic_msi_read[] = {
 -    &openpic_buggy_read,
 -    &openpic_buggy_read,
 -    &mpic_src_msi_read,
 -};
 -
 -qemu_irq *mpic_init (target_phys_addr_t base, int nb_cpus,
 -                        qemu_irq **irqs, qemu_irq irq_out)
 +qemu_irq *mpic_init (MemoryRegion *address_space, target_phys_addr_t base,
 +                     int nb_cpus, qemu_irq **irqs, qemu_irq irq_out)
  {
 -    openpic_t *mpp;
 -    int i;
 +    openpic_t    *mpp;
 +    int           i;
      struct {
 -        CPUReadMemoryFunc * const *read;
 -        CPUWriteMemoryFunc * const *write;
 -        target_phys_addr_t start_addr;
 -        ram_addr_t size;
 +        const char             *name;
 +        MemoryRegionOps const  *ops;
 +        target_phys_addr_t      start_addr;
 +        ram_addr_t              size;
      } const list[] = {
 -        {mpic_glb_read, mpic_glb_write, MPIC_GLB_REG_START, MPIC_GLB_REG_SIZE},
 -        {mpic_tmr_read, mpic_tmr_write, MPIC_TMR_REG_START, MPIC_TMR_REG_SIZE},
 -        {mpic_ext_read, mpic_ext_write, MPIC_EXT_REG_START, MPIC_EXT_REG_SIZE},
 -        {mpic_int_read, mpic_int_write, MPIC_INT_REG_START, MPIC_INT_REG_SIZE},
 -        {mpic_msg_read, mpic_msg_write, MPIC_MSG_REG_START, MPIC_MSG_REG_SIZE},
 -        {mpic_msi_read, mpic_msi_write, MPIC_MSI_REG_START, MPIC_MSI_REG_SIZE},
 -        {mpic_cpu_read, mpic_cpu_write, MPIC_CPU_REG_START, MPIC_CPU_REG_SIZE},
 +        {"glb", &mpic_glb_ops, MPIC_GLB_REG_START, MPIC_GLB_REG_SIZE},
 +        {"tmr", &mpic_tmr_ops, MPIC_TMR_REG_START, MPIC_TMR_REG_SIZE},
 +        {"ext", &mpic_ext_ops, MPIC_EXT_REG_START, MPIC_EXT_REG_SIZE},
 +        {"int", &mpic_int_ops, MPIC_INT_REG_START, MPIC_INT_REG_SIZE},
 +        {"msg", &mpic_msg_ops, MPIC_MSG_REG_START, MPIC_MSG_REG_SIZE},
 +        {"msi", &mpic_msi_ops, MPIC_MSI_REG_START, MPIC_MSI_REG_SIZE},
 +        {"cpu", &mpic_cpu_ops, MPIC_CPU_REG_START, MPIC_CPU_REG_SIZE},
      };
  
-     /* XXX: for now, only one CPU is supported */
-     if (nb_cpus != 1)
-         return NULL;
- 
      mpp = g_malloc0(sizeof(openpic_t));
  
 +    memory_region_init(&mpp->mem, "mpic", 0x40000);
 +    memory_region_add_subregion(address_space, base, &mpp->mem);
 +
      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,
 -                                           DEVICE_BIG_ENDIAN);
 -        if (mem_index < 0) {
 -            goto free;
 -        }
 -        cpu_register_physical_memory(base + list[i].start_addr,
 -                                     list[i].size, mem_index);
 +        memory_region_init_io(&mpp->sub_io_mem[i], list[i].ops, mpp,
 +                              list[i].name, list[i].size);
 +
 +        memory_region_add_subregion(&mpp->mem, list[i].start_addr,
 +                                    &mpp->sub_io_mem[i]);
      }
  
      mpp->nb_cpus = nb_cpus;
diff --cc hw/ppce500_mpc8544ds.c
index 28acf0b,f00367e..5bf8eab
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@@ -226,9 -227,8 +228,9 @@@ static void mpc8544ds_init(ram_addr_t r
                           const char *initrd_filename,
                           const char *cpu_model)
  {
 +    MemoryRegion *address_space_mem = get_system_memory();
      PCIBus *pci_bus;
-     CPUState *env;
+     CPUState *env = NULL;
      uint64_t elf_entry;
      uint64_t elf_lowaddr;
      target_phys_addr_t entry=0;
@@@ -269,10 -293,11 +295,12 @@@
                                   "mpc8544ds.ram", ram_size));
  
      /* MPIC */
-     irqs = g_malloc0(sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
-     irqs[OPENPIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPCE500_INPUT_INT];
-     irqs[OPENPIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPCE500_INPUT_CINT];
-     mpic = mpic_init(address_space_mem, MPC8544_MPIC_REGS_BASE, 1, &irqs, NULL);
 -    mpic = mpic_init(MPC8544_MPIC_REGS_BASE, smp_cpus, irqs, NULL);
++    mpic = mpic_init(address_space_mem, MPC8544_MPIC_REGS_BASE,
++                     smp_cpus, irqs, NULL);
+ 
+     if (!mpic) {
+         cpu_abort(env, "MPIC failed to initialize\n");
+     }
  
      /* Serial */
      if (serial_hds[0]) {
commit 02d6516c8ba00bdd6d96b622f000cb28c3449f43
Author: Stefan Weil <sw at weilnetz.de>
Date:   Sun Oct 9 08:50:50 2011 +0200

    target-alpha: Fix compilation errors for 32 bit hosts
    
    On i386, these errors were reported:
    
    qemu/hw/alpha_dp264.c: In function ‘clipper_init’:
    qemu/hw/alpha_dp264.c:158: error: integer constant is too large for ‘unsigned long’ type
    
    qemu/hw/alpha_typhoon.c: In function ‘typhoon_init’:
    qemu/hw/alpha_typhoon.c:737: error: integer constant is too large for ‘long’ type
    qemu/hw/alpha_typhoon.c:741: error: integer constant is too large for ‘long’ type
    qemu/hw/alpha_typhoon.c:745: error: integer constant is too large for ‘long’ type
    qemu/hw/alpha_typhoon.c:749: error: integer constant is too large for ‘long’ type
    qemu/hw/alpha_typhoon.c:757: error: integer constant is too large for ‘long’ type
    qemu/hw/alpha_typhoon.c:767: error: integer constant is too large for ‘long’ type
    qemu/hw/alpha_typhoon.c:772: error: integer constant is too large for ‘long’ type
    
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/alpha_dp264.c b/hw/alpha_dp264.c
index 7c36b21..fcc20e9 100644
--- a/hw/alpha_dp264.c
+++ b/hw/alpha_dp264.c
@@ -155,7 +155,7 @@ static void clipper_init(ram_addr_t ram_size,
             load_image_targphys(initrd_filename, initrd_base,
                                 ram_size - initrd_base);
 
-            stq_phys(param_offset + 0x100, initrd_base + 0xfffffc0000000000UL);
+            stq_phys(param_offset + 0x100, initrd_base + 0xfffffc0000000000ULL);
             stq_phys(param_offset + 0x108, initrd_size);
         }
     }
diff --git a/hw/alpha_typhoon.c b/hw/alpha_typhoon.c
index c769fcc..c7608bb 100644
--- a/hw/alpha_typhoon.c
+++ b/hw/alpha_typhoon.c
@@ -734,19 +734,23 @@ PCIBus *typhoon_init(ram_addr_t ram_size, qemu_irq *p_rtc_irq,
 
     /* Pchip0 CSRs, 0x801.8000.0000, 256MB.  */
     memory_region_init_io(&s->pchip.region, &pchip_ops, s, "pchip0", 256*MB);
-    memory_region_add_subregion(addr_space, 0x80180000000, &s->pchip.region);
+    memory_region_add_subregion(addr_space, 0x80180000000ULL,
+                                &s->pchip.region);
 
     /* Cchip CSRs, 0x801.A000.0000, 256MB.  */
     memory_region_init_io(&s->cchip.region, &cchip_ops, s, "cchip0", 256*MB);
-    memory_region_add_subregion(addr_space, 0x801a0000000, &s->cchip.region);
+    memory_region_add_subregion(addr_space, 0x801a0000000ULL,
+                                &s->cchip.region);
 
     /* Dchip CSRs, 0x801.B000.0000, 256MB.  */
     memory_region_init_io(&s->dchip_region, &dchip_ops, s, "dchip0", 256*MB);
-    memory_region_add_subregion(addr_space, 0x801b0000000, &s->dchip_region);
+    memory_region_add_subregion(addr_space, 0x801b0000000ULL,
+                                &s->dchip_region);
 
     /* Pchip0 PCI memory, 0x800.0000.0000, 4GB.  */
     memory_region_init(&s->pchip.reg_mem, "pci0-mem", 4*GB);
-    memory_region_add_subregion(addr_space, 0x80000000000, &s->pchip.reg_mem);
+    memory_region_add_subregion(addr_space, 0x80000000000ULL,
+                                &s->pchip.reg_mem);
 
     /* Pchip0 PCI I/O, 0x801.FC00.0000, 32MB.  */
     /* ??? Ideally we drop the "system" i/o space on the floor and give the
@@ -754,7 +758,8 @@ PCIBus *typhoon_init(ram_addr_t ram_size, qemu_irq *p_rtc_irq,
        We can't do that until the MEM and IO paths in memory.c are unified.  */
     memory_region_init_io(&s->pchip.reg_io, &alpha_pci_bw_io_ops, NULL,
                           "pci0-io", 32*MB);
-    memory_region_add_subregion(addr_space, 0x801fc000000, &s->pchip.reg_io);
+    memory_region_add_subregion(addr_space, 0x801fc000000ULL,
+                                &s->pchip.reg_io);
 
     b = pci_register_bus(&s->host.busdev.qdev, "pci",
                          typhoon_set_irq, sys_map_irq, s,
@@ -764,12 +769,14 @@ PCIBus *typhoon_init(ram_addr_t ram_size, qemu_irq *p_rtc_irq,
     /* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB.  */
     memory_region_init_io(&s->pchip.reg_iack, &alpha_pci_iack_ops, b,
                           "pci0-iack", 64*MB);
-    memory_region_add_subregion(addr_space, 0x801f8000000, &s->pchip.reg_iack);
+    memory_region_add_subregion(addr_space, 0x801f8000000ULL,
+                                &s->pchip.reg_iack);
 
     /* Pchip0 PCI configuration, 0x801.FE00.0000, 16MB.  */
     memory_region_init_io(&s->pchip.reg_conf, &alpha_pci_conf1_ops, b,
                           "pci0-conf", 16*MB);
-    memory_region_add_subregion(addr_space, 0x801fe000000, &s->pchip.reg_conf);
+    memory_region_add_subregion(addr_space, 0x801fe000000ULL,
+                                &s->pchip.reg_conf);
 
     /* For the record, these are the mappings for the second PCI bus.
        We can get away with not implementing them because we indicate
commit 9a7242f7867e1f1e70013aa70d148c65a1980aec
Merge: 53e6217... c781cf9...
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sat Oct 8 16:03:58 2011 +0000

    Merge branch 'axp-system-7' of git://repo.or.cz/qemu/rth
    
    * 'axp-system-7' of git://repo.or.cz/qemu/rth:
      target-alpha: Add high-resolution access to wall clock and an alarm.
      target-alpha: Implement HALT IPR.
      target-alpha: Implement WAIT IPR.
      target-alpha: Add CLIPPER emulation.
      target-alpha: Add custom PALcode image for CLIPPER emulation.
      target-alpha: Honor icount for RPCC instruction.

commit c781cf96e298b9134b05ed1e7ca981a929e08e77
Author: Richard Henderson <rth at twiddle.net>
Date:   Thu Apr 28 10:40:08 2011 -0700

    target-alpha: Add high-resolution access to wall clock and an alarm.
    
    The alarm is a fully general one-shot time comparator, which will be
    usable under Linux as a hrtimer source.  It's much more flexible than
    the RTC source available on real hardware.
    
    The wall clock allows the guest access to the host timekeeping.  Much
    like the KVM wall clock source for other guests.
    
    Both are accessed via the PALcode Cserve entry point.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/hw/alpha_typhoon.c b/hw/alpha_typhoon.c
index 4c97219..c769fcc 100644
--- a/hw/alpha_typhoon.c
+++ b/hw/alpha_typhoon.c
@@ -681,6 +681,16 @@ static void typhoon_set_timer_irq(void *opaque, int irq, int level)
     }
 }
 
+static void typhoon_alarm_timer(void *opaque)
+{
+    TyphoonState *s = (TyphoonState *)((uintptr_t)opaque & ~3);
+    int cpu = (uintptr_t)opaque & 3;
+
+    /* Set the ITI bit for this cpu.  */
+    s->cchip.misc |= 1 << (cpu + 4);
+    cpu_interrupt(s->cchip.cpu[cpu], CPU_INTERRUPT_TIMER);
+}
+
 PCIBus *typhoon_init(ram_addr_t ram_size, qemu_irq *p_rtc_irq,
                      CPUState *cpus[4], pci_map_irq_fn sys_map_irq)
 {
@@ -692,6 +702,7 @@ PCIBus *typhoon_init(ram_addr_t ram_size, qemu_irq *p_rtc_irq,
     PCIHostState *p;
     TyphoonState *s;
     PCIBus *b;
+    int i;
 
     dev = qdev_create(NULL, "typhoon-pcihost");
     qdev_init_nofail(dev);
@@ -700,7 +711,15 @@ PCIBus *typhoon_init(ram_addr_t ram_size, qemu_irq *p_rtc_irq,
     s = container_of(p, TyphoonState, host);
 
     /* Remember the CPUs so that we can deliver interrupts to them.  */
-    memcpy(s->cchip.cpu, cpus, 4 * sizeof(CPUState *));
+    for (i = 0; i < 4; i++) {
+        CPUState *env = cpus[i];
+        s->cchip.cpu[i] = env;
+        if (env) {
+            env->alarm_timer = qemu_new_timer_ns(rtc_clock,
+                                                 typhoon_alarm_timer,
+                                                 (void *)((uintptr_t)s + i));
+        }
+    }
 
     *p_rtc_irq = *qemu_allocate_irqs(typhoon_set_timer_irq, s, 1);
 
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index c2e7bb3..9d61d45 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -265,6 +265,10 @@ struct CPUAlphaState {
     uint64_t scratch[24];
 #endif
 
+    /* This alarm doesn't exist in real hardware; we wish it did.  */
+    struct QEMUTimer *alarm_timer;
+    uint64_t alarm_expire;
+
 #if TARGET_LONG_BITS > HOST_LONG_BITS
     /* temporary fixed-point registers
      * used to emulate 64 bits target on 32 bits hosts
diff --git a/target-alpha/helper.h b/target-alpha/helper.h
index c352c24..b693cee 100644
--- a/target-alpha/helper.h
+++ b/target-alpha/helper.h
@@ -113,7 +113,11 @@ DEF_HELPER_2(stq_c_phys, i64, i64, i64)
 
 DEF_HELPER_FLAGS_0(tbia, TCG_CALL_CONST, void)
 DEF_HELPER_FLAGS_1(tbis, TCG_CALL_CONST, void, i64)
+
 DEF_HELPER_1(halt, void, i64);
+
+DEF_HELPER_FLAGS_0(get_time, TCG_CALL_CONST, i64)
+DEF_HELPER_FLAGS_1(set_alarm, TCG_CALL_CONST, void, i64)
 #endif
 
 #include "def-helper.h"
diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c
index 1896ab8..cc102db 100644
--- a/target-alpha/op_helper.c
+++ b/target-alpha/op_helper.c
@@ -1228,6 +1228,21 @@ void helper_halt(uint64_t restart)
         qemu_system_shutdown_request();
     }
 }
+
+uint64_t helper_get_time(void)
+{
+    return qemu_get_clock_ns(rtc_clock);
+}
+
+void helper_set_alarm(uint64_t expire)
+{
+    if (expire) {
+        env->alarm_expire = expire;
+        qemu_mod_timer(env->alarm_timer, expire);
+    } else {
+        qemu_del_timer(env->alarm_timer);
+    }
+}
 #endif
 
 /*****************************************************************************/
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index 0acbd68..a961159 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -1590,18 +1590,34 @@ static int cpu_pr_data(int pr)
         return offsetof(CPUAlphaState, shadow[pr - 32]);
     case 40 ... 63:
         return offsetof(CPUAlphaState, scratch[pr - 40]);
+
+    case 251:
+        return offsetof(CPUAlphaState, alarm_expire);
     }
     return 0;
 }
 
-static void gen_mfpr(int ra, int regno)
+static ExitStatus gen_mfpr(int ra, int regno)
 {
     int data = cpu_pr_data(regno);
 
     /* In our emulated PALcode, these processor registers have no
        side effects from reading.  */
     if (ra == 31) {
-        return;
+        return NO_EXIT;
+    }
+
+    if (regno == 250) {
+        /* WALL_TIME */
+        if (use_icount) {
+            gen_io_start();
+            gen_helper_get_time(cpu_ir[ra]);
+            gen_io_end();
+            return EXIT_PC_STALE;
+        } else {
+            gen_helper_get_time(cpu_ir[ra]);
+            return NO_EXIT;
+        }
     }
 
     /* The basic registers are data only, and unknown registers
@@ -1615,6 +1631,7 @@ static void gen_mfpr(int ra, int regno)
     } else {
         tcg_gen_ld_i64(cpu_ir[ra], cpu_env, data);
     }
+    return NO_EXIT;
 }
 
 static ExitStatus gen_mtpr(DisasContext *ctx, int rb, int regno)
@@ -1650,6 +1667,11 @@ static ExitStatus gen_mtpr(DisasContext *ctx, int rb, int regno)
         gen_helper_halt(tmp);
         return EXIT_PC_STALE;
 
+    case 251:
+        /* ALARM */
+        gen_helper_set_alarm(tmp);
+        break;
+
     default:
         /* The basic registers are data only, and unknown registers
            are read-zero, write-ignore.  */
@@ -2772,8 +2794,7 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
         /* HW_MFPR (PALcode) */
 #ifndef CONFIG_USER_ONLY
         if (ctx->tb->flags & TB_FLAGS_PAL_MODE) {
-            gen_mfpr(ra, insn & 0xffff);
-            break;
+            return gen_mfpr(ra, insn & 0xffff);
         }
 #endif
         goto invalid_opc;
commit 034ebc2753e7d16879a91e4407c4e0706f63604e
Author: Richard Henderson <rth at twiddle.net>
Date:   Wed Apr 27 09:22:52 2011 -0700

    target-alpha: Implement HALT IPR.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/target-alpha/helper.h b/target-alpha/helper.h
index 2dec57e..c352c24 100644
--- a/target-alpha/helper.h
+++ b/target-alpha/helper.h
@@ -113,6 +113,7 @@ DEF_HELPER_2(stq_c_phys, i64, i64, i64)
 
 DEF_HELPER_FLAGS_0(tbia, TCG_CALL_CONST, void)
 DEF_HELPER_FLAGS_1(tbis, TCG_CALL_CONST, void, i64)
+DEF_HELPER_1(halt, void, i64);
 #endif
 
 #include "def-helper.h"
diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c
index d8945dc..1896ab8 100644
--- a/target-alpha/op_helper.c
+++ b/target-alpha/op_helper.c
@@ -22,6 +22,7 @@
 #include "host-utils.h"
 #include "softfloat.h"
 #include "helper.h"
+#include "sysemu.h"
 #include "qemu-timer.h"
 
 #define FP_STATUS (env->fp_status)
@@ -1218,6 +1219,15 @@ void helper_tbis(uint64_t p)
 {
     tlb_flush_page(env, p);
 }
+
+void helper_halt(uint64_t restart)
+{
+    if (restart) {
+        qemu_system_reset_request();
+    } else {
+        qemu_system_shutdown_request();
+    }
+}
 #endif
 
 /*****************************************************************************/
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index c1ef465..0acbd68 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -1645,6 +1645,11 @@ static ExitStatus gen_mtpr(DisasContext *ctx, int rb, int regno)
         tcg_gen_st32_i64(tmp, cpu_env, offsetof(CPUState, halted));
         return gen_excp(ctx, EXCP_HLT, 0);
 
+    case 252:
+        /* HALT */
+        gen_helper_halt(tmp);
+        return EXIT_PC_STALE;
+
     default:
         /* The basic registers are data only, and unknown registers
            are read-zero, write-ignore.  */
commit bc24270e6471fb916a3816de9e63c31474392739
Author: Richard Henderson <rth at twiddle.net>
Date:   Thu Apr 21 18:58:09 2011 -0700

    target-alpha: Implement WAIT IPR.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index fb2e9e5..c1ef465 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -1617,9 +1617,10 @@ static void gen_mfpr(int ra, int regno)
     }
 }
 
-static void gen_mtpr(int rb, int regno)
+static ExitStatus gen_mtpr(DisasContext *ctx, int rb, int regno)
 {
     TCGv tmp;
+    int data;
 
     if (rb == 31) {
         tmp = tcg_const_i64(0);
@@ -1627,19 +1628,27 @@ static void gen_mtpr(int rb, int regno)
         tmp = cpu_ir[rb];
     }
 
-    /* These two register numbers perform a TLB cache flush.  Thankfully we
-       can only do this inside PALmode, which means that the current basic
-       block cannot be affected by the change in mappings.  */
-    if (regno == 255) {
+    switch (regno) {
+    case 255:
         /* TBIA */
         gen_helper_tbia();
-    } else if (regno == 254) {
+        break;
+
+    case 254:
         /* TBIS */
         gen_helper_tbis(tmp);
-    } else {
+        break;
+
+    case 253:
+        /* WAIT */
+        tmp = tcg_const_i64(1);
+        tcg_gen_st32_i64(tmp, cpu_env, offsetof(CPUState, halted));
+        return gen_excp(ctx, EXCP_HLT, 0);
+
+    default:
         /* The basic registers are data only, and unknown registers
            are read-zero, write-ignore.  */
-        int data = cpu_pr_data(regno);
+        data = cpu_pr_data(regno);
         if (data != 0) {
             if (data & PR_BYTE) {
                 tcg_gen_st8_i64(tmp, cpu_env, data & ~PR_BYTE);
@@ -1649,11 +1658,14 @@ static void gen_mtpr(int rb, int regno)
                 tcg_gen_st_i64(tmp, cpu_env, data);
             }
         }
+        break;
     }
 
     if (rb == 31) {
         tcg_temp_free(tmp);
     }
+
+    return NO_EXIT;
 }
 #endif /* !USER_ONLY*/
 
@@ -3061,8 +3073,7 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
         /* HW_MTPR (PALcode) */
 #ifndef CONFIG_USER_ONLY
         if (ctx->tb->flags & TB_FLAGS_PAL_MODE) {
-            gen_mtpr(rb, insn & 0xffff);
-            break;
+            return gen_mtpr(ctx, rb, insn & 0xffff);
         }
 #endif
         goto invalid_opc;
commit 80bb2ff770e3e6ff2922a7b60978394571ec64cb
Author: Richard Henderson <rth at twiddle.net>
Date:   Thu Aug 25 11:38:59 2011 -1000

    target-alpha: Add CLIPPER emulation.
    
    This is a DP264 variant, SMP capable, no unusual hardware present.
    
    The emulation does not currently include any PCI IOMMU code.
    Hopefully the generic support for that can be merged to HEAD soon.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/Makefile.target b/Makefile.target
index 1e9815c..1aa6fce 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -367,6 +367,7 @@ obj-s390x-y = s390-virtio-bus.o s390-virtio.o
 
 obj-alpha-y = i8259.o mc146818rtc.o
 obj-alpha-y += vga.o cirrus_vga.o
+obj-alpha-y += alpha_pci.o alpha_dp264.o alpha_typhoon.o
 
 obj-xtensa-y += xtensa_pic.o
 obj-xtensa-y += xtensa_sample.o
diff --git a/default-configs/alpha-softmmu.mak b/default-configs/alpha-softmmu.mak
index abadcff..be86d0c 100644
--- a/default-configs/alpha-softmmu.mak
+++ b/default-configs/alpha-softmmu.mak
@@ -3,7 +3,9 @@
 include pci.mak
 CONFIG_SERIAL=y
 CONFIG_I8254=y
+CONFIG_PCKBD=y
 CONFIG_VGA_PCI=y
 CONFIG_IDE_CORE=y
 CONFIG_IDE_QDEV=y
 CONFIG_VMWARE_VGA=y
+CONFIG_IDE_CMD646=y
diff --git a/hw/alpha_dp264.c b/hw/alpha_dp264.c
new file mode 100644
index 0000000..7c36b21
--- /dev/null
+++ b/hw/alpha_dp264.c
@@ -0,0 +1,177 @@
+/*
+ * QEMU Alpha DP264/CLIPPER hardware system emulator.
+ *
+ * Choose CLIPPER IRQ mappings over, say, DP264, MONET, or WEBBRICK
+ * variants because CLIPPER doesn't have an SMC669 SuperIO controler
+ * that we need to emulate as well.
+ */
+
+#include "hw.h"
+#include "elf.h"
+#include "loader.h"
+#include "boards.h"
+#include "alpha_sys.h"
+#include "sysemu.h"
+#include "mc146818rtc.h"
+#include "ide.h"
+
+#define MAX_IDE_BUS 2
+
+static uint64_t cpu_alpha_superpage_to_phys(void *opaque, uint64_t addr)
+{
+    if (((addr >> 41) & 3) == 2) {
+        addr &= 0xffffffffffull;
+    }
+    return addr;
+}
+
+/* Note that there are at least 3 viewpoints of IRQ numbers on Alpha systems.
+    (0) The dev_irq_n lines into the cpu, which we totally ignore,
+    (1) The DRIR lines in the typhoon chipset,
+    (2) The "vector" aka mangled interrupt number reported by SRM PALcode,
+    (3) The interrupt number assigned by the kernel.
+   The following function is concerned with (1) only.  */
+
+static int clipper_pci_map_irq(PCIDevice *d, int irq_num)
+{
+    int slot = d->devfn >> 3;
+
+    assert(irq_num >= 0 && irq_num <= 3);
+
+    return (slot + 1) * 4 + irq_num;
+}
+
+static void clipper_init(ram_addr_t ram_size,
+                         const char *boot_device,
+                         const char *kernel_filename,
+                         const char *kernel_cmdline,
+                         const char *initrd_filename,
+                         const char *cpu_model)
+{
+    CPUState *cpus[4];
+    PCIBus *pci_bus;
+    qemu_irq rtc_irq;
+    long size, i;
+    const char *palcode_filename;
+    uint64_t palcode_entry, palcode_low, palcode_high;
+    uint64_t kernel_entry, kernel_low, kernel_high;
+
+    /* Create up to 4 cpus.  */
+    memset(cpus, 0, sizeof(cpus));
+    for (i = 0; i < smp_cpus; ++i) {
+        cpus[i] = cpu_init(cpu_model ? cpu_model : "ev67");
+    }
+
+    cpus[0]->trap_arg0 = ram_size;
+    cpus[0]->trap_arg1 = 0;
+    cpus[0]->trap_arg2 = smp_cpus;
+
+    /* Init the chipset.  */
+    pci_bus = typhoon_init(ram_size, &rtc_irq, cpus, clipper_pci_map_irq);
+
+    rtc_init(1980, rtc_irq);
+    pit_init(0x40, 0);
+    isa_create_simple("i8042");
+
+    /* VGA setup.  Don't bother loading the bios.  */
+    alpha_pci_vga_setup(pci_bus);
+
+    /* Serial code setup.  */
+    for (i = 0; i < MAX_SERIAL_PORTS; ++i) {
+        if (serial_hds[i]) {
+            serial_isa_init(i, serial_hds[i]);
+        }
+    }
+
+    /* Network setup.  e1000 is good enough, failing Tulip support.  */
+    for (i = 0; i < nb_nics; i++) {
+        pci_nic_init_nofail(&nd_table[i], "e1000", NULL);
+    }
+
+    /* IDE disk setup.  */
+    {
+        DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+        ide_drive_get(hd, MAX_IDE_BUS);
+
+        pci_cmd646_ide_init(pci_bus, hd, 0);
+    }
+
+    /* Load PALcode.  Given that this is not "real" cpu palcode,
+       but one explicitly written for the emulation, we might as
+       well load it directly from and ELF image.  */
+    palcode_filename = (bios_name ? bios_name : "palcode-clipper");
+    palcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, palcode_filename);
+    if (palcode_filename == NULL) {
+        hw_error("no palcode provided\n");
+        exit(1);
+    }
+    size = load_elf(palcode_filename, cpu_alpha_superpage_to_phys,
+                    NULL, &palcode_entry, &palcode_low, &palcode_high,
+                    0, EM_ALPHA, 0);
+    if (size < 0) {
+        hw_error("could not load palcode '%s'\n", palcode_filename);
+        exit(1);
+    }
+
+    /* Start all cpus at the PALcode RESET entry point.  */
+    for (i = 0; i < smp_cpus; ++i) {
+        cpus[i]->pal_mode = 1;
+        cpus[i]->pc = palcode_entry;
+        cpus[i]->palbr = palcode_entry;
+    }
+
+    /* Load a kernel.  */
+    if (kernel_filename) {
+        uint64_t param_offset;
+
+        size = load_elf(kernel_filename, cpu_alpha_superpage_to_phys,
+                        NULL, &kernel_entry, &kernel_low, &kernel_high,
+                        0, EM_ALPHA, 0);
+        if (size < 0) {
+            hw_error("could not load kernel '%s'\n", kernel_filename);
+            exit(1);
+        }
+
+        cpus[0]->trap_arg1 = kernel_entry;
+
+        param_offset = kernel_low - 0x6000;
+
+        if (kernel_cmdline) {
+            pstrcpy_targphys("cmdline", param_offset, 0x100, kernel_cmdline);
+        }
+
+        if (initrd_filename) {
+            long initrd_base, initrd_size;
+
+            initrd_size = get_image_size(initrd_filename);
+            if (initrd_size < 0) {
+                hw_error("could not load initial ram disk '%s'\n",
+                         initrd_filename);
+                exit(1);
+            }
+
+            /* Put the initrd image as high in memory as possible.  */
+            initrd_base = (ram_size - initrd_size) & TARGET_PAGE_MASK;
+            load_image_targphys(initrd_filename, initrd_base,
+                                ram_size - initrd_base);
+
+            stq_phys(param_offset + 0x100, initrd_base + 0xfffffc0000000000UL);
+            stq_phys(param_offset + 0x108, initrd_size);
+        }
+    }
+}
+
+static QEMUMachine clipper_machine = {
+    .name = "clipper",
+    .desc = "Alpha DP264/CLIPPER",
+    .init = clipper_init,
+    .max_cpus = 4,
+    .is_default = 1,
+};
+
+static void clipper_machine_init(void)
+{
+    qemu_register_machine(&clipper_machine);
+}
+
+machine_init(clipper_machine_init);
diff --git a/hw/alpha_pci.c b/hw/alpha_pci.c
new file mode 100644
index 0000000..e975702
--- /dev/null
+++ b/hw/alpha_pci.c
@@ -0,0 +1,134 @@
+/*
+ * QEMU Alpha PCI support functions.
+ *
+ * Some of this isn't very Alpha specific at all.
+ *
+ * ??? Sparse memory access not implemented.
+ */
+
+#include "config.h"
+#include "alpha_sys.h"
+#include "qemu-log.h"
+#include "sysemu.h"
+#include "vmware_vga.h"
+
+
+/* PCI IO reads/writes, to byte-word addressable memory.  */
+/* ??? Doesn't handle multiple PCI busses.  */
+
+static uint64_t bw_io_read(void *opaque, target_phys_addr_t addr, unsigned size)
+{
+    switch (size) {
+    case 1:
+        return cpu_inb(addr);
+    case 2:
+        return cpu_inw(addr);
+    case 4:
+        return cpu_inl(addr);
+    }
+    abort();
+}
+
+static void bw_io_write(void *opaque, target_phys_addr_t addr,
+                        uint64_t val, unsigned size)
+{
+    switch (size) {
+    case 1:
+        cpu_outb(addr, val);
+        break;
+    case 2:
+        cpu_outw(addr, val);
+        break;
+    case 4:
+        cpu_outl(addr, val);
+        break;
+    default:
+        abort();
+    }
+}
+
+const MemoryRegionOps alpha_pci_bw_io_ops = {
+    .read = bw_io_read,
+    .write = bw_io_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 4,
+    },
+};
+
+/* PCI config space reads/writes, to byte-word addressable memory.  */
+static uint64_t bw_conf1_read(void *opaque, target_phys_addr_t addr,
+                              unsigned size)
+{
+    PCIBus *b = opaque;
+    return pci_data_read(b, addr, size);
+}
+
+static void bw_conf1_write(void *opaque, target_phys_addr_t addr,
+                           uint64_t val, unsigned size)
+{
+    PCIBus *b = opaque;
+    pci_data_write(b, addr, val, size);
+}
+
+const MemoryRegionOps alpha_pci_conf1_ops = {
+    .read = bw_conf1_read,
+    .write = bw_conf1_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 4,
+    },
+};
+
+/* PCI/EISA Interrupt Acknowledge Cycle.  */
+
+static uint64_t iack_read(void *opaque, target_phys_addr_t addr, unsigned size)
+{
+    return pic_read_irq(isa_pic);
+}
+
+static void special_write(void *opaque, target_phys_addr_t addr,
+                          uint64_t val, unsigned size)
+{
+    qemu_log("pci: special write cycle");
+}
+
+const MemoryRegionOps alpha_pci_iack_ops = {
+    .read = iack_read,
+    .write = special_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+void alpha_pci_vga_setup(PCIBus *pci_bus)
+{
+    switch (vga_interface_type) {
+#ifdef CONFIG_SPICE
+    case VGA_QXL:
+        pci_create_simple(pci_bus, -1, "qxl-vga");
+        return;
+#endif
+    case VGA_CIRRUS:
+        pci_cirrus_vga_init(pci_bus);
+        return;
+    case VGA_VMWARE:
+        if (pci_vmsvga_init(pci_bus)) {
+            return;
+        }
+        break;
+    }
+    /* If VGA is enabled at all, and one of the above didn't work, then
+       fallback to Standard VGA.  */
+    if (vga_interface_type != VGA_NONE) {
+        pci_vga_init(pci_bus);
+    }
+}
diff --git a/hw/alpha_sys.h b/hw/alpha_sys.h
new file mode 100644
index 0000000..13f0177
--- /dev/null
+++ b/hw/alpha_sys.h
@@ -0,0 +1,24 @@
+/* Alpha cores and system support chips.  */
+
+#ifndef HW_ALPHA_H
+#define HW_ALPHA_H 1
+
+#include "pci.h"
+#include "pci_host.h"
+#include "ide.h"
+#include "net.h"
+#include "pc.h"
+#include "usb-ohci.h"
+#include "irq.h"
+
+
+PCIBus *typhoon_init(ram_addr_t, qemu_irq *, CPUState *[4], pci_map_irq_fn);
+
+/* alpha_pci.c.  */
+extern const MemoryRegionOps alpha_pci_bw_io_ops;
+extern const MemoryRegionOps alpha_pci_conf1_ops;
+extern const MemoryRegionOps alpha_pci_iack_ops;
+
+void alpha_pci_vga_setup(PCIBus *pci_bus);
+
+#endif
diff --git a/hw/alpha_typhoon.c b/hw/alpha_typhoon.c
new file mode 100644
index 0000000..4c97219
--- /dev/null
+++ b/hw/alpha_typhoon.c
@@ -0,0 +1,794 @@
+/*
+ * DEC 21272 (TSUNAMI/TYPHOON) chipset emulation.
+ *
+ * Written by Richard Henderson.
+ *
+ * This work is licensed under the GNU GPL license version 2 or later.
+ */
+
+#include "cpu.h"
+#include "exec-all.h"
+#include "hw.h"
+#include "devices.h"
+#include "sysemu.h"
+#include "alpha_sys.h"
+#include "exec-memory.h"
+
+
+typedef struct TyphoonCchip {
+    MemoryRegion region;
+    uint64_t misc;
+    uint64_t drir;
+    uint64_t dim[4];
+    uint32_t iic[4];
+    CPUState *cpu[4];
+} TyphoonCchip;
+
+typedef struct TyphoonWindow {
+    uint32_t base_addr;
+    uint32_t mask;
+    uint32_t translated_base_pfn;
+} TyphoonWindow;
+ 
+typedef struct TyphoonPchip {
+    MemoryRegion region;
+    MemoryRegion reg_iack;
+    MemoryRegion reg_mem;
+    MemoryRegion reg_io;
+    MemoryRegion reg_conf;
+    uint64_t ctl;
+    TyphoonWindow win[4];
+} TyphoonPchip;
+
+typedef struct TyphoonState {
+    PCIHostState host;
+    TyphoonCchip cchip;
+    TyphoonPchip pchip;
+    MemoryRegion dchip_region;
+    MemoryRegion ram_region;
+
+    /* QEMU emulation state.  */
+    uint32_t latch_tmp;
+} TyphoonState;
+
+/* Called when one of DRIR or DIM changes.  */
+static void cpu_irq_change(CPUState *env, uint64_t req)
+{
+    /* If there are any non-masked interrupts, tell the cpu.  */
+    if (env) {
+        if (req) {
+            cpu_interrupt(env, CPU_INTERRUPT_HARD);
+        } else {
+            cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+        }
+    }
+}
+
+static uint64_t cchip_read(void *opaque, target_phys_addr_t addr, unsigned size)
+{
+    CPUState *env = cpu_single_env;
+    TyphoonState *s = opaque;
+    uint64_t ret = 0;
+
+    if (addr & 4) {
+        return s->latch_tmp;
+    }
+
+    switch (addr) {
+    case 0x0000:
+        /* CSC: Cchip System Configuration Register.  */
+        /* All sorts of data here; probably the only thing relevant is
+           PIP<14> Pchip 1 Present = 0.  */
+        break;
+
+    case 0x0040:
+        /* MTR: Memory Timing Register.  */
+        /* All sorts of stuff related to real DRAM.  */
+        break;
+
+    case 0x0080:
+        /* MISC: Miscellaneous Register.  */
+        ret = s->cchip.misc | (env->cpu_index & 3);
+        break;
+
+    case 0x00c0:
+        /* MPD: Memory Presence Detect Register.  */
+        break;
+
+    case 0x0100: /* AAR0 */
+    case 0x0140: /* AAR1 */
+    case 0x0180: /* AAR2 */
+    case 0x01c0: /* AAR3 */
+        /* AAR: Array Address Register.  */
+        /* All sorts of information about DRAM.  */
+        break;
+
+    case 0x0200:
+        /* DIM0: Device Interrupt Mask Register, CPU0.  */
+        ret = s->cchip.dim[0];
+        break;
+    case 0x0240:
+        /* DIM1: Device Interrupt Mask Register, CPU1.  */
+        ret = s->cchip.dim[1];
+        break;
+    case 0x0280:
+        /* DIR0: Device Interrupt Request Register, CPU0.  */
+        ret = s->cchip.dim[0] & s->cchip.drir;
+        break;
+    case 0x02c0:
+        /* DIR1: Device Interrupt Request Register, CPU1.  */
+        ret = s->cchip.dim[1] & s->cchip.drir;
+        break;
+    case 0x0300:
+        /* DRIR: Device Raw Interrupt Request Register.  */
+        ret = s->cchip.drir;
+        break;
+
+    case 0x0340:
+        /* PRBEN: Probe Enable Register.  */
+        break;
+
+    case 0x0380:
+        /* IIC0: Interval Ignore Count Register, CPU0.  */
+        ret = s->cchip.iic[0];
+        break;
+    case 0x03c0:
+        /* IIC1: Interval Ignore Count Register, CPU1.  */
+        ret = s->cchip.iic[1];
+        break;
+
+    case 0x0400: /* MPR0 */
+    case 0x0440: /* MPR1 */
+    case 0x0480: /* MPR2 */
+    case 0x04c0: /* MPR3 */
+        /* MPR: Memory Programming Register.  */
+        break;
+
+    case 0x0580:
+        /* TTR: TIGbus Timing Register.  */
+        /* All sorts of stuff related to interrupt delivery timings.  */
+        break;
+    case 0x05c0:
+        /* TDR: TIGbug Device Timing Register.  */
+        break;
+
+    case 0x0600:
+        /* DIM2: Device Interrupt Mask Register, CPU2.  */
+        ret = s->cchip.dim[2];
+        break;
+    case 0x0640:
+        /* DIM3: Device Interrupt Mask Register, CPU3.  */
+        ret = s->cchip.dim[3];
+        break;
+    case 0x0680:
+        /* DIR2: Device Interrupt Request Register, CPU2.  */
+        ret = s->cchip.dim[2] & s->cchip.drir;
+        break;
+    case 0x06c0:
+        /* DIR3: Device Interrupt Request Register, CPU3.  */
+        ret = s->cchip.dim[3] & s->cchip.drir;
+        break;
+
+    case 0x0700:
+        /* IIC2: Interval Ignore Count Register, CPU2.  */
+        ret = s->cchip.iic[2];
+        break;
+    case 0x0740:
+        /* IIC3: Interval Ignore Count Register, CPU3.  */
+        ret = s->cchip.iic[3];
+        break;
+
+    case 0x0780:
+        /* PWR: Power Management Control.   */
+        break;
+    
+    case 0x0c00: /* CMONCTLA */
+    case 0x0c40: /* CMONCTLB */
+    case 0x0c80: /* CMONCNT01 */
+    case 0x0cc0: /* CMONCNT23 */
+        break;
+
+    default:
+        cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, size);
+        return -1;
+    }
+
+    s->latch_tmp = ret >> 32;
+    return ret;
+}
+
+static uint64_t dchip_read(void *opaque, target_phys_addr_t addr, unsigned size)
+{
+    /* Skip this.  It's all related to DRAM timing and setup.  */
+    return 0;
+}
+
+static uint64_t pchip_read(void *opaque, target_phys_addr_t addr, unsigned size)
+{
+    TyphoonState *s = opaque;
+    uint64_t ret = 0;
+
+    if (addr & 4) {
+        return s->latch_tmp;
+    }
+
+    switch (addr) {
+    case 0x0000:
+        /* WSBA0: Window Space Base Address Register.  */
+        ret = s->pchip.win[0].base_addr;
+        break;
+    case 0x0040:
+        /* WSBA1 */
+        ret = s->pchip.win[1].base_addr;
+        break;
+    case 0x0080:
+        /* WSBA2 */
+        ret = s->pchip.win[2].base_addr;
+        break;
+    case 0x00c0:
+        /* WSBA3 */
+        ret = s->pchip.win[3].base_addr;
+        break;
+
+    case 0x0100:
+        /* WSM0: Window Space Mask Register.  */
+        ret = s->pchip.win[0].mask;
+        break;
+    case 0x0140:
+        /* WSM1 */
+        ret = s->pchip.win[1].mask;
+        break;
+    case 0x0180:
+        /* WSM2 */
+        ret = s->pchip.win[2].mask;
+        break;
+    case 0x01c0:
+        /* WSM3 */
+        ret = s->pchip.win[3].mask;
+        break;
+
+    case 0x0200:
+        /* TBA0: Translated Base Address Register.  */
+        ret = (uint64_t)s->pchip.win[0].translated_base_pfn << 10;
+        break;
+    case 0x0240:
+        /* TBA1 */
+        ret = (uint64_t)s->pchip.win[1].translated_base_pfn << 10;
+        break;
+    case 0x0280:
+        /* TBA2 */
+        ret = (uint64_t)s->pchip.win[2].translated_base_pfn << 10;
+        break;
+    case 0x02c0:
+        /* TBA3 */
+        ret = (uint64_t)s->pchip.win[3].translated_base_pfn << 10;
+        break;
+
+    case 0x0300:
+        /* PCTL: Pchip Control Register.  */
+        ret = s->pchip.ctl;
+        break;
+    case 0x0340:
+        /* PLAT: Pchip Master Latency Register.  */
+        break;
+    case 0x03c0:
+        /* PERROR: Pchip Error Register.  */
+        break;
+    case 0x0400:
+        /* PERRMASK: Pchip Error Mask Register.  */
+        break;
+    case 0x0440:
+        /* PERRSET: Pchip Error Set Register.  */
+        break;
+    case 0x0480:
+        /* TLBIV: Translation Buffer Invalidate Virtual Register (WO).  */
+        break;
+    case 0x04c0:
+        /* TLBIA: Translation Buffer Invalidate All Register (WO).  */
+        break;
+    case 0x0500: /* PMONCTL */
+    case 0x0540: /* PMONCNT */
+    case 0x0800: /* SPRST */
+        break;
+
+    default:
+        cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, size);
+        return -1;
+    }
+
+    s->latch_tmp = ret >> 32;
+    return ret;
+}
+
+static void cchip_write(void *opaque, target_phys_addr_t addr,
+                        uint64_t v32, unsigned size)
+{
+    TyphoonState *s = opaque;
+    uint64_t val, oldval, newval;
+
+    if (addr & 4) {
+        val = v32 << 32 | s->latch_tmp;
+        addr ^= 4;
+    } else {
+        s->latch_tmp = v32;
+        return;
+    }
+
+    switch (addr) {
+    case 0x0000:
+        /* CSC: Cchip System Configuration Register.  */
+        /* All sorts of data here; nothing relevant RW.  */
+        break;
+
+    case 0x0040:
+        /* MTR: Memory Timing Register.  */
+        /* All sorts of stuff related to real DRAM.  */
+        break;
+
+    case 0x0080:
+        /* MISC: Miscellaneous Register.  */
+        newval = oldval = s->cchip.misc;
+        newval &= ~(val & 0x10000ff0);     /* W1C fields */
+        if (val & 0x100000) {
+            newval &= ~0xff0000ull;        /* ACL clears ABT and ABW */
+        } else {
+            newval |= val & 0x00f00000;    /* ABT field is W1S */
+            if ((newval & 0xf0000) == 0) {
+                newval |= val & 0xf0000;   /* ABW field is W1S iff zero */
+            }
+        }
+        newval |= (val & 0xf000) >> 4;     /* IPREQ field sets IPINTR.  */
+
+        newval &= ~0xf0000000000ull;       /* WO and RW fields */
+        newval |= val & 0xf0000000000ull;
+        s->cchip.misc = newval;
+
+        /* Pass on changes to IPI and ITI state.  */
+        if ((newval ^ oldval) & 0xff0) {
+            int i;
+            for (i = 0; i < 4; ++i) {
+                CPUState *env = s->cchip.cpu[i];
+                if (env) {
+                    /* IPI can be either cleared or set by the write.  */
+                    if (newval & (1 << (i + 8))) {
+                        cpu_interrupt(env, CPU_INTERRUPT_SMP);
+                    } else {
+                        cpu_reset_interrupt(env, CPU_INTERRUPT_SMP);
+                    }
+
+                    /* ITI can only be cleared by the write.  */
+                    if ((newval & (1 << (i + 4))) == 0) {
+                        cpu_reset_interrupt(env, CPU_INTERRUPT_TIMER);
+                    }
+                }
+            }
+        }
+        break;
+
+    case 0x00c0:
+        /* MPD: Memory Presence Detect Register.  */
+        break;
+
+    case 0x0100: /* AAR0 */
+    case 0x0140: /* AAR1 */
+    case 0x0180: /* AAR2 */
+    case 0x01c0: /* AAR3 */
+        /* AAR: Array Address Register.  */
+        /* All sorts of information about DRAM.  */
+        break;
+
+    case 0x0200: /* DIM0 */
+        /* DIM: Device Interrupt Mask Register, CPU0.  */
+        s->cchip.dim[0] = val;
+        cpu_irq_change(s->cchip.cpu[0], val & s->cchip.drir);
+        break;
+    case 0x0240: /* DIM1 */
+        /* DIM: Device Interrupt Mask Register, CPU1.  */
+        s->cchip.dim[0] = val;
+        cpu_irq_change(s->cchip.cpu[1], val & s->cchip.drir);
+        break;
+
+    case 0x0280: /* DIR0 (RO) */
+    case 0x02c0: /* DIR1 (RO) */
+    case 0x0300: /* DRIR (RO) */
+        break;
+
+    case 0x0340:
+        /* PRBEN: Probe Enable Register.  */
+        break;
+
+    case 0x0380: /* IIC0 */
+        s->cchip.iic[0] = val & 0xffffff;
+        break;
+    case 0x03c0: /* IIC1 */
+        s->cchip.iic[1] = val & 0xffffff;
+        break;
+
+    case 0x0400: /* MPR0 */
+    case 0x0440: /* MPR1 */
+    case 0x0480: /* MPR2 */
+    case 0x04c0: /* MPR3 */
+        /* MPR: Memory Programming Register.  */
+        break;
+
+    case 0x0580:
+        /* TTR: TIGbus Timing Register.  */
+        /* All sorts of stuff related to interrupt delivery timings.  */
+        break;
+    case 0x05c0:
+        /* TDR: TIGbug Device Timing Register.  */
+        break;
+
+    case 0x0600:
+        /* DIM2: Device Interrupt Mask Register, CPU2.  */
+        s->cchip.dim[2] = val;
+        cpu_irq_change(s->cchip.cpu[2], val & s->cchip.drir);
+        break;
+    case 0x0640:
+        /* DIM3: Device Interrupt Mask Register, CPU3.  */
+        s->cchip.dim[3] = val;
+        cpu_irq_change(s->cchip.cpu[3], val & s->cchip.drir);
+        break;
+
+    case 0x0680: /* DIR2 (RO) */
+    case 0x06c0: /* DIR3 (RO) */
+        break;
+
+    case 0x0700: /* IIC2 */
+        s->cchip.iic[2] = val & 0xffffff;
+        break;
+    case 0x0740: /* IIC3 */
+        s->cchip.iic[3] = val & 0xffffff;
+        break;
+
+    case 0x0780:
+        /* PWR: Power Management Control.   */
+        break;
+    
+    case 0x0c00: /* CMONCTLA */
+    case 0x0c40: /* CMONCTLB */
+    case 0x0c80: /* CMONCNT01 */
+    case 0x0cc0: /* CMONCNT23 */
+        break;
+
+    default:
+        cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, size);
+        return;
+    }
+}
+
+static void dchip_write(void *opaque, target_phys_addr_t addr,
+                        uint64_t val, unsigned size)
+{
+    /* Skip this.  It's all related to DRAM timing and setup.  */
+}
+
+static void pchip_write(void *opaque, target_phys_addr_t addr,
+                        uint64_t v32, unsigned size)
+{
+    TyphoonState *s = opaque;
+    uint64_t val, oldval;
+
+    if (addr & 4) {
+        val = v32 << 32 | s->latch_tmp;
+        addr ^= 4;
+    } else {
+        s->latch_tmp = v32;
+        return;
+    }
+
+    switch (addr) {
+    case 0x0000:
+        /* WSBA0: Window Space Base Address Register.  */
+        s->pchip.win[0].base_addr = val;
+        break;
+    case 0x0040:
+        /* WSBA1 */
+        s->pchip.win[1].base_addr = val;
+        break;
+    case 0x0080:
+        /* WSBA2 */
+        s->pchip.win[2].base_addr = val;
+        break;
+    case 0x00c0:
+        /* WSBA3 */
+        s->pchip.win[3].base_addr = val;
+        break;
+
+    case 0x0100:
+        /* WSM0: Window Space Mask Register.  */
+        s->pchip.win[0].mask = val;
+        break;
+    case 0x0140:
+        /* WSM1 */
+        s->pchip.win[1].mask = val;
+        break;
+    case 0x0180:
+        /* WSM2 */
+        s->pchip.win[2].mask = val;
+        break;
+    case 0x01c0:
+        /* WSM3 */
+        s->pchip.win[3].mask = val;
+        break;
+
+    case 0x0200:
+        /* TBA0: Translated Base Address Register.  */
+        s->pchip.win[0].translated_base_pfn = val >> 10;
+        break;
+    case 0x0240:
+        /* TBA1 */
+        s->pchip.win[1].translated_base_pfn = val >> 10;
+        break;
+    case 0x0280:
+        /* TBA2 */
+        s->pchip.win[2].translated_base_pfn = val >> 10;
+        break;
+    case 0x02c0:
+        /* TBA3 */
+        s->pchip.win[3].translated_base_pfn = val >> 10;
+        break;
+
+    case 0x0300:
+        /* PCTL: Pchip Control Register.  */
+        oldval = s->pchip.ctl;
+        oldval &= ~0x00001cff0fc7ffull;       /* RW fields */
+        oldval |= val & 0x00001cff0fc7ffull;
+
+        s->pchip.ctl = oldval;
+        break;
+
+    case 0x0340:
+        /* PLAT: Pchip Master Latency Register.  */
+        break;
+    case 0x03c0:
+        /* PERROR: Pchip Error Register.  */
+        break;
+    case 0x0400:
+        /* PERRMASK: Pchip Error Mask Register.  */
+        break;
+    case 0x0440:
+        /* PERRSET: Pchip Error Set Register.  */
+        break;
+
+    case 0x0480:
+        /* TLBIV: Translation Buffer Invalidate Virtual Register.  */
+        break;
+
+    case 0x04c0:
+        /* TLBIA: Translation Buffer Invalidate All Register (WO).  */
+        break;
+
+    case 0x0500:
+        /* PMONCTL */
+    case 0x0540:
+        /* PMONCNT */
+    case 0x0800:
+        /* SPRST */
+        break;
+
+    default:
+        cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, size);
+        return;
+    }
+}
+
+static const MemoryRegionOps cchip_ops = {
+    .read = cchip_read,
+    .write = cchip_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,  /* ??? Should be 8.  */
+        .max_access_size = 8,
+    },
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static const MemoryRegionOps dchip_ops = {
+    .read = dchip_read,
+    .write = dchip_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,  /* ??? Should be 8.  */
+        .max_access_size = 8,
+    },
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 8,
+    },
+};
+
+static const MemoryRegionOps pchip_ops = {
+    .read = pchip_read,
+    .write = pchip_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,  /* ??? Should be 8.  */
+        .max_access_size = 8,
+    },
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static void typhoon_set_irq(void *opaque, int irq, int level)
+{
+    TyphoonState *s = opaque;
+    uint64_t drir;
+    int i;
+
+    /* Set/Reset the bit in CCHIP.DRIR based on IRQ+LEVEL.  */
+    drir = s->cchip.drir;
+    if (level) {
+        drir |= 1ull << irq;
+    } else {
+        drir &= ~(1ull << irq);
+    }
+    s->cchip.drir = drir;
+
+    for (i = 0; i < 4; ++i) {
+        cpu_irq_change(s->cchip.cpu[i], s->cchip.dim[i] & drir);
+    }
+}
+
+static void typhoon_set_isa_irq(void *opaque, int irq, int level)
+{
+    typhoon_set_irq(opaque, 55, level);
+}
+
+static void typhoon_set_timer_irq(void *opaque, int irq, int level)
+{
+    TyphoonState *s = opaque;
+    int i;
+
+    /* Thankfully, the mc146818rtc code doesn't track the IRQ state,
+       and so we don't have to worry about missing interrupts just
+       because we never actually ACK the interrupt.  Just ignore any
+       case of the interrupt level going low.  */
+    if (level == 0) {
+        return;
+    }
+
+    /* Deliver the interrupt to each CPU, considering each CPU's IIC.  */
+    for (i = 0; i < 4; ++i) {
+        CPUState *env = s->cchip.cpu[i];
+        if (env) {
+            uint32_t iic = s->cchip.iic[i];
+
+            /* ??? The verbage in Section 10.2.2.10 isn't 100% clear.
+               Bit 24 is the OverFlow bit, RO, and set when the count
+               decrements past 0.  When is OF cleared?  My guess is that
+               OF is actually cleared when the IIC is written, and that
+               the ICNT field always decrements.  At least, that's an
+               interpretation that makes sense, and "allows the CPU to
+               determine exactly how mant interval timer ticks were
+               skipped".  At least within the next 4M ticks...  */
+
+            iic = ((iic - 1) & 0x1ffffff) | (iic & 0x1000000);
+            s->cchip.iic[i] = iic;
+
+            if (iic & 0x1000000) {
+                /* Set the ITI bit for this cpu.  */
+                s->cchip.misc |= 1 << (i + 4);
+                /* And signal the interrupt.  */
+                cpu_interrupt(env, CPU_INTERRUPT_TIMER);
+            }
+        }
+    }
+}
+
+PCIBus *typhoon_init(ram_addr_t ram_size, qemu_irq *p_rtc_irq,
+                     CPUState *cpus[4], pci_map_irq_fn sys_map_irq)
+{
+    const uint64_t MB = 1024 * 1024;
+    const uint64_t GB = 1024 * MB;
+    MemoryRegion *addr_space = get_system_memory();
+    MemoryRegion *addr_space_io = get_system_io();
+    DeviceState *dev;
+    PCIHostState *p;
+    TyphoonState *s;
+    PCIBus *b;
+
+    dev = qdev_create(NULL, "typhoon-pcihost");
+    qdev_init_nofail(dev);
+
+    p = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev));
+    s = container_of(p, TyphoonState, host);
+
+    /* Remember the CPUs so that we can deliver interrupts to them.  */
+    memcpy(s->cchip.cpu, cpus, 4 * sizeof(CPUState *));
+
+    *p_rtc_irq = *qemu_allocate_irqs(typhoon_set_timer_irq, s, 1);
+
+    /* Main memory region, 0x00.0000.0000.  Real hardware supports 32GB,
+       but the address space hole reserved at this point is 8TB.  */
+    memory_region_init_ram(&s->ram_region, NULL, "ram", ram_size);
+    memory_region_add_subregion(addr_space, 0, &s->ram_region);
+
+    /* TIGbus, 0x801.0000.0000, 1GB.  */
+    /* ??? The TIGbus is used for delivering interrupts, and access to
+       the flash ROM.  I'm not sure that we need to implement it at all.  */
+
+    /* Pchip0 CSRs, 0x801.8000.0000, 256MB.  */
+    memory_region_init_io(&s->pchip.region, &pchip_ops, s, "pchip0", 256*MB);
+    memory_region_add_subregion(addr_space, 0x80180000000, &s->pchip.region);
+
+    /* Cchip CSRs, 0x801.A000.0000, 256MB.  */
+    memory_region_init_io(&s->cchip.region, &cchip_ops, s, "cchip0", 256*MB);
+    memory_region_add_subregion(addr_space, 0x801a0000000, &s->cchip.region);
+
+    /* Dchip CSRs, 0x801.B000.0000, 256MB.  */
+    memory_region_init_io(&s->dchip_region, &dchip_ops, s, "dchip0", 256*MB);
+    memory_region_add_subregion(addr_space, 0x801b0000000, &s->dchip_region);
+
+    /* Pchip0 PCI memory, 0x800.0000.0000, 4GB.  */
+    memory_region_init(&s->pchip.reg_mem, "pci0-mem", 4*GB);
+    memory_region_add_subregion(addr_space, 0x80000000000, &s->pchip.reg_mem);
+
+    /* Pchip0 PCI I/O, 0x801.FC00.0000, 32MB.  */
+    /* ??? Ideally we drop the "system" i/o space on the floor and give the
+       PCI subsystem the full address space reserved by the chipset.
+       We can't do that until the MEM and IO paths in memory.c are unified.  */
+    memory_region_init_io(&s->pchip.reg_io, &alpha_pci_bw_io_ops, NULL,
+                          "pci0-io", 32*MB);
+    memory_region_add_subregion(addr_space, 0x801fc000000, &s->pchip.reg_io);
+
+    b = pci_register_bus(&s->host.busdev.qdev, "pci",
+                         typhoon_set_irq, sys_map_irq, s,
+                         &s->pchip.reg_mem, addr_space_io, 0, 64);
+    s->host.bus = b;
+
+    /* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB.  */
+    memory_region_init_io(&s->pchip.reg_iack, &alpha_pci_iack_ops, b,
+                          "pci0-iack", 64*MB);
+    memory_region_add_subregion(addr_space, 0x801f8000000, &s->pchip.reg_iack);
+
+    /* Pchip0 PCI configuration, 0x801.FE00.0000, 16MB.  */
+    memory_region_init_io(&s->pchip.reg_conf, &alpha_pci_conf1_ops, b,
+                          "pci0-conf", 16*MB);
+    memory_region_add_subregion(addr_space, 0x801fe000000, &s->pchip.reg_conf);
+
+    /* For the record, these are the mappings for the second PCI bus.
+       We can get away with not implementing them because we indicate
+       via the Cchip.CSC<PIP> bit that Pchip1 is not present.  */
+    /* Pchip1 PCI memory, 0x802.0000.0000, 4GB.  */
+    /* Pchip1 CSRs, 0x802.8000.0000, 256MB.  */
+    /* Pchip1 PCI special/interrupt acknowledge, 0x802.F800.0000, 64MB.  */
+    /* Pchip1 PCI I/O, 0x802.FC00.0000, 32MB.  */
+    /* Pchip1 PCI configuration, 0x802.FE00.0000, 16MB.  */
+
+    /* Init the ISA bus.  */
+    /* ??? Technically there should be a cy82c693ub pci-isa bridge.  */
+    {
+        qemu_irq isa_pci_irq, *isa_irqs;
+
+        isa_bus_new(NULL, addr_space_io);
+        isa_pci_irq = *qemu_allocate_irqs(typhoon_set_isa_irq, s, 1);
+        isa_irqs = i8259_init(isa_pci_irq);
+        isa_bus_irqs(isa_irqs);
+    }
+
+    return b;
+}
+
+static int typhoon_pcihost_init(SysBusDevice *dev)
+{
+    return 0;
+}
+
+static SysBusDeviceInfo typhoon_pcihost_info = {
+    .init = typhoon_pcihost_init,
+    .qdev.name = "typhoon-pcihost",
+    .qdev.size = sizeof(TyphoonState),
+    .qdev.no_user = 1
+};
+
+static void typhoon_register(void)
+{
+    sysbus_register_withprop(&typhoon_pcihost_info);
+}
+device_init(typhoon_register);
commit 753d11f2238663990191ba8285bfe9301f7e4020
Author: Richard Henderson <rth at twiddle.net>
Date:   Fri Jun 24 11:58:37 2011 -0700

    target-alpha: Add custom PALcode image for CLIPPER emulation.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/.gitmodules b/.gitmodules
index c3faa38..2a43dbc 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -13,3 +13,6 @@
 [submodule "roms/openbios"]
 	path = roms/openbios
 	url = git://git.qemu.org/openbios.git
+[submodule "roms/qemu-palcode"]
+	path = roms/qemu-palcode
+	url = git://repo.or.cz/qemu-palcode.git
diff --git a/Makefile b/Makefile
index 6ed3194..8b6c19a 100644
--- a/Makefile
+++ b/Makefile
@@ -251,7 +251,8 @@ bamboo.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \
 mpc8544ds.dtb \
 multiboot.bin linuxboot.bin \
 s390-zipl.rom \
-spapr-rtas.bin slof.bin
+spapr-rtas.bin slof.bin \
+palcode-clipper
 else
 BLOBS=
 endif
diff --git a/configure b/configure
index 29cdd75..9b4fe34 100755
--- a/configure
+++ b/configure
@@ -3618,7 +3618,13 @@ FILES="$FILES tests/cris/Makefile tests/cris/.gdbinit"
 FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps"
 FILES="$FILES pc-bios/spapr-rtas/Makefile"
 FILES="$FILES roms/seabios/Makefile roms/vgabios/Makefile"
-for bios_file in $source_path/pc-bios/*.bin $source_path/pc-bios/*.rom $source_path/pc-bios/*.dtb $source_path/pc-bios/openbios-*; do
+for bios_file in \
+    $source_path/pc-bios/*.bin \
+    $source_path/pc-bios/*.rom \
+    $source_path/pc-bios/*.dtb \
+    $source_path/pc-bios/openbios-* \
+    $source_path/pc-bios/palcode-*
+do
     FILES="$FILES pc-bios/`basename $bios_file`"
 done
 mkdir -p $DIRS
diff --git a/pc-bios/README b/pc-bios/README
index 02651fe..4d1d816 100644
--- a/pc-bios/README
+++ b/pc-bios/README
@@ -32,3 +32,6 @@
 - The S390 zipl loader is an addition to the official IBM s390-tools
   package. That fork is maintained in its own git repository at:
   git://repo.or.cz/s390-tools.git
+
+- The sources for the Alpha palcode image is available from:
+  git://repo.or.cz/qemu-palcode.git
diff --git a/pc-bios/palcode-clipper b/pc-bios/palcode-clipper
new file mode 100755
index 0000000..a92372c
Binary files /dev/null and b/pc-bios/palcode-clipper differ
diff --git a/roms/qemu-palcode b/roms/qemu-palcode
new file mode 160000
index 0000000..7abb12f
--- /dev/null
+++ b/roms/qemu-palcode
@@ -0,0 +1 @@
+Subproject commit 7abb12f60eb3069019e9497e193733d77d8f0722
commit a9406ea127b0561cf95e5a4e8ce0c5e06c21e644
Author: Richard Henderson <rth at twiddle.net>
Date:   Thu Sep 22 08:11:18 2011 -0700

    target-alpha: Honor icount for RPCC instruction.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>

diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index 1e224a2..fb2e9e5 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -2721,8 +2721,16 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
             break;
         case 0xC000:
             /* RPCC */
-            if (ra != 31)
-                gen_helper_load_pcc(cpu_ir[ra]);
+            if (ra != 31) {
+                if (use_icount) {
+                    gen_io_start();
+                    gen_helper_load_pcc(cpu_ir[ra]);
+                    gen_io_end();
+                    ret = EXIT_PC_STALE;
+                } else {
+                    gen_helper_load_pcc(cpu_ir[ra]);
+                }
+            }
             break;
         case 0xE000:
             /* RC */
commit 53e621704c9734d68fcae52d89ff00680df53044
Merge: 2116850... 779277c...
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sat Oct 8 15:40:08 2011 +0000

    Merge branch 'for-upstream' of git://git.serverraum.org/git/mw/qemu-lm32
    
    * 'for-upstream' of git://git.serverraum.org/git/mw/qemu-lm32:
      milkymist: new interrupt map
      milkymist_uart: support new core version
      lm32: add missing qemu_init_vcpu() call

commit 211685040f4e579f83a3ed8b3aa7a3f363ad384f
Merge: dc439de... 59370aa...
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sat Oct 8 15:38:14 2011 +0000

    Merge branch 'tracing' of git://repo.or.cz/qemu/stefanha
    
    * 'tracing' of git://repo.or.cz/qemu/stefanha:
      trace: add arguments to bdrv_co_io_em() trace event
      trace: trace monitor qmp dispatch/completion
      trace: trace bdrv_open_common()
      hmp: re-enable trace-file command

commit dc439de7f96dc1a17e137273366123df24837876
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Sat Oct 1 13:56:29 2011 +0100

    tcg/s390: Remove unused tcg_out_addi()
    
    Remove the unused function tcg_out_addi() from the s390 TCG backend;
    this brings it into line with other backends.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Acked-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c
index b58df71..9317fe8 100644
--- a/tcg/s390/tcg-target.c
+++ b/tcg/s390/tcg-target.c
@@ -2322,8 +2322,3 @@ static void tcg_target_qemu_prologue(TCGContext *s)
     /* br %r14 (return) */
     tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, TCG_REG_R14);
 }
-
-static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
-{
-    tcg_abort();
-}
commit 498562926d798abf9b2fa2533a108f73a914fd3a
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Sat Oct 1 13:56:23 2011 +0100

    tcg/ia64: Remove unused tcg_out_addi()
    
    Remove the unused function tcg_out_addi() from the ia64 TCG backend;
    this brings it into line with other backends.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c
index 3803ab6..bb22b9a 100644
--- a/tcg/ia64/tcg-target.c
+++ b/tcg/ia64/tcg-target.c
@@ -847,25 +847,6 @@ static inline void tcg_out_movi(TCGContext *s, TCGType type,
                    tcg_opc_x2 (TCG_REG_P0, OPC_MOVL_X2, reg, arg));
 }
 
-static inline void tcg_out_addi(TCGContext *s, TCGArg reg, tcg_target_long val)
-{
-    if (val == ((int32_t)val << 10) >> 10) {
-        tcg_out_bundle(s, MmI,
-                       tcg_opc_a5(TCG_REG_P0, OPC_ADDL_A5,
-                                  TCG_REG_R2, val, TCG_REG_R0),
-                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
-                       tcg_opc_a1 (TCG_REG_P0, OPC_ADD_A1, reg,
-                                   reg, TCG_REG_R2));
-    } else {
-        tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R2, val);
-        tcg_out_bundle(s, mmI,
-                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
-                       tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
-                       tcg_opc_a1 (TCG_REG_P0, OPC_ADD_A1, reg,
-                                   reg, TCG_REG_R2));
-    }
-}
-
 static void tcg_out_br(TCGContext *s, int label_index)
 {
     TCGLabel *l = &s->labels[label_index];
commit 6c731dc2af1e80c410e8605098deb1ac16ab72f0
Merge: 6e19a13... 7c0a340...
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sat Oct 8 10:01:46 2011 +0000

    Merge branch 'ppc-next' of git://repo.or.cz/qemu/agraf
    
    * 'ppc-next' of git://repo.or.cz/qemu/agraf: (64 commits)
      ppc64: Fix linker script
      pseries: Implement set-time-of-day RTAS function
      pseries: Refactor spapr irq allocation
      PPC: Clean up BookE timer code
      PPC: booke timers
      KVM: PPC: Use HIOR setting for -M pseries with PR KVM
      KVM: Update kernel headers
      KVM: Update kernel headers
      PPC: Fix heathrow PIC to use little endian MMIO
      PPC: Fix via-cuda memory registration
      ppc: move ADB stuff from ppc_mac.h to adb.h
      openpic: Unfold write_IRQreg
      openpic: Unfold read_IRQreg
      ppc405: use RAM_ADDR_FMT instead of %08lx
      Gdbstub: handle read of fpscr
      vscsi: send the CHECK_CONDITION status down together with autosense data
      pseries: Implement hcall-bulk hypervisor interface
      Implement POWER7's CFAR in TCG
      ppc: booke206: use MAV=2.0 TSIZE definition, fix 4G pages
      ppc: booke206: add "info tlb" support
      ...

commit 6e19a1379d3d12c2d8f934aa8154037a609f4507
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sat Oct 8 10:00:02 2011 +0000

    ARM: fix segfault
    
    Fix a bug in bccd9ec5f098668576342c83d90d6d6833d61d33,
    target-arm/op_helper.c missed a change unlike all other targets.
    This lead to a NULL pointer dereferences.
    
    Reviewed-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index ab9c923..1892b35 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -84,6 +84,7 @@ void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
     int ret;
 
     saved_env = env;
+    env = env1;
     ret = cpu_arm_handle_mmu_fault(env, addr, is_write, mmu_idx);
     if (unlikely(ret)) {
         if (retaddr) {
commit 7c0a3409627604c111d5c5e1ce4e0224c2b56315
Author: Andreas Färber <afaerber at suse.de>
Date:   Tue Oct 4 05:14:52 2011 +0000

    ppc64: Fix linker script
    
    Since commit 8733f609 (Fix linker scripts) linking on Linux/ppc64 fails:
    
      LINK  ppc64-linux-user/qemu-ppc64
    /usr/lib64/gcc/powerpc64-suse-linux/4.3/../../../../powerpc64-suse-linux/bin/ld:/home/afaerber/qemu/ppc64.ld:84: syntax error
    collect2: ld gab 1 als Ende-Status zurück
    make[1]: *** [qemu-ppc64] Fehler 1
    make: *** [subdir-ppc64-linux-user] Fehler 2
    
    Fix by removing a leftover line in the ppc64 linker script.
    
    Cc: Gerd Hoffmann <kraxel at redhat.com>
    Cc: Blue Swirl <blauwirbel at gmail.com>
    Signed-off-by: Andreas Färber <afaerber at suse.de>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/ppc64.ld b/ppc64.ld
index 0059ee5..0a7c0dd 100644
--- a/ppc64.ld
+++ b/ppc64.ld
@@ -81,8 +81,8 @@ SECTIONS
   .sdata2         : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) }
   .sbss2          : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
   .eh_frame_hdr : { *(.eh_frame_hdr) }
-*(.gcc_except_table.*) } /* Adjust the address for the data segment.  We want to
-adjust up to +     the same address within the page on the next page up.  */
+  /* Adjust the address for the data segment.  We want to adjust up to
+     the same address within the page on the next page up.  */
   . = ALIGN (0x10000) - ((0x10000 - .) & (0x10000 - 1)); . = DATA_SEGMENT_ALIGN
 (0x10000, 0x1000);   /* Exception handling  */
   .eh_frame       : { KEEP (*(.eh_frame)) }
commit ac26f8c3891dde7a3fc7f24a3a87905df843d905
Author: Breno Leitao <brenohl at br.ibm.com>
Date:   Wed Sep 28 16:53:16 2011 +0000

    pseries: Implement set-time-of-day RTAS function
    
    Currently there is no implementation for set-time-of-day rtas function,
    which causes the following warning "setting the clock failed (-1)" on
    the guest.
    
    This patch just creates this function, get the timedate diff and store in
    the papr environment, so that the correct value will be returned by
    get-time-of-day.
    
    In order to try it, just adjust the hardware time, run hwclock --systohc,
    so that, on when the system runs hwclock --hctosys, the value is correctly
    adjusted, i.e. the host time plus the timediff.
    
    Signed-off-by: Breno Leitao <brenohl at br.ibm.com>
    Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/spapr.h b/hw/spapr.h
index ec910de..6657c33 100644
--- a/hw/spapr.h
+++ b/hw/spapr.h
@@ -18,6 +18,7 @@ typedef struct sPAPREnvironment {
     void *fdt_skel;
     target_ulong entry_point;
     int next_irq;
+    int rtc_offset;
 } sPAPREnvironment;
 
 #define H_SUCCESS         0
diff --git a/hw/spapr_rtas.c b/hw/spapr_rtas.c
index 00c8ce5..d1ac74c 100644
--- a/hw/spapr_rtas.c
+++ b/hw/spapr_rtas.c
@@ -67,7 +67,7 @@ static void rtas_get_time_of_day(sPAPREnvironment *spapr,
         return;
     }
 
-    qemu_get_timedate(&tm, 0);
+    qemu_get_timedate(&tm, spapr->rtc_offset);
 
     rtas_st(rets, 0, 0); /* Success */
     rtas_st(rets, 1, tm.tm_year + 1900);
@@ -79,6 +79,27 @@ static void rtas_get_time_of_day(sPAPREnvironment *spapr,
     rtas_st(rets, 7, 0); /* we don't do nanoseconds */
 }
 
+static void rtas_set_time_of_day(sPAPREnvironment *spapr,
+                                 uint32_t token, uint32_t nargs,
+                                 target_ulong args,
+                                 uint32_t nret, target_ulong rets)
+{
+    struct tm tm;
+
+    tm.tm_year = rtas_ld(args, 0) - 1900;
+    tm.tm_mon = rtas_ld(args, 1) - 1;
+    tm.tm_mday = rtas_ld(args, 2);
+    tm.tm_hour = rtas_ld(args, 3);
+    tm.tm_min = rtas_ld(args, 4);
+    tm.tm_sec = rtas_ld(args, 5);
+
+    /* Just generate a monitor event for the change */
+    rtc_change_mon_event(&tm);
+    spapr->rtc_offset = qemu_timedate_diff(&tm);
+
+    rtas_st(rets, 0, 0); /* Success */
+}
+
 static void rtas_power_off(sPAPREnvironment *spapr,
                            uint32_t token, uint32_t nargs, target_ulong args,
                            uint32_t nret, target_ulong rets)
@@ -271,6 +292,7 @@ static void register_core_rtas(void)
 {
     spapr_rtas_register("display-character", rtas_display_character);
     spapr_rtas_register("get-time-of-day", rtas_get_time_of_day);
+    spapr_rtas_register("set-time-of-day", rtas_set_time_of_day);
     spapr_rtas_register("power-off", rtas_power_off);
     spapr_rtas_register("query-cpu-stopped-state",
                         rtas_query_cpu_stopped_state);
commit e6c866d417d1a09536f489e66c21cf49b7ec60b6
Author: David Gibson <david at gibson.dropbear.id.au>
Date:   Thu Sep 15 20:49:49 2011 +0000

    pseries: Refactor spapr irq allocation
    
    Paulo Bonzini changed the original spapr code, which manually assigned irq
    numbers for each virtual device, to allocate them automatically from the
    device initialization. That allowed spapr virtual devices to be constructed
    with -device, which is a good start.  However, the way that patch worked
    doesn't extend nicely for the future when we want to support devices other
    than sPAPR VIO devices (e.g. virtio and PCI).
    
    This patch rearranges the irq allocation to be global across the sPAPR
    environment, so it can be used by other bus types as well.
    
    Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/spapr.c b/hw/spapr.c
index deb4ae5..b118975 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -61,6 +61,30 @@
 
 sPAPREnvironment *spapr;
 
+qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num)
+{
+    uint32_t irq;
+    qemu_irq qirq;
+
+    if (hint) {
+        irq = hint;
+        /* FIXME: we should probably check for collisions somehow */
+    } else {
+        irq = spapr->next_irq++;
+    }
+
+    qirq = xics_find_qirq(spapr->icp, irq);
+    if (!qirq) {
+        return NULL;
+    }
+
+    if (irq_num) {
+        *irq_num = irq;
+    }
+
+    return qirq;
+}
+
 static void *spapr_create_fdt_skel(const char *cpu_model,
                                    target_phys_addr_t initrd_base,
                                    target_phys_addr_t initrd_size,
@@ -372,6 +396,7 @@ static void ppc_spapr_init(ram_addr_t ram_size,
 
     /* Set up Interrupt Controller */
     spapr->icp = xics_system_init(XICS_IRQS);
+    spapr->next_irq = 16;
 
     /* Set up VIO bus */
     spapr->vio_bus = spapr_vio_bus_init();
diff --git a/hw/spapr.h b/hw/spapr.h
index 3d21b7a..ec910de 100644
--- a/hw/spapr.h
+++ b/hw/spapr.h
@@ -17,6 +17,7 @@ typedef struct sPAPREnvironment {
     long rtas_size;
     void *fdt_skel;
     target_ulong entry_point;
+    int next_irq;
 } sPAPREnvironment;
 
 #define H_SUCCESS         0
@@ -281,11 +282,7 @@ void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn);
 target_ulong spapr_hypercall(CPUState *env, target_ulong opcode,
                              target_ulong *args);
 
-static inline qemu_irq spapr_find_qirq(sPAPREnvironment *spapr,
-                                        int irq_num)
-{
-    return xics_find_qirq(spapr->icp, irq_num);
-}
+qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num);
 
 static inline uint32_t rtas_ld(target_ulong phys, int n)
 {
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index 0546ccb..35818e1 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -600,7 +600,6 @@ static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo)
 {
     VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo;
     VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
-    VIOsPAPRBus *bus = DO_UPCAST(VIOsPAPRBus, bus, dev->qdev.parent_bus);
     char *id;
 
     if (asprintf(&id, "%s@%x", info->dt_name, dev->reg) < 0) {
@@ -608,10 +607,11 @@ static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo)
     }
 
     dev->qdev.id = id;
-    if (!dev->vio_irq_num) {
-        dev->vio_irq_num = bus->irq++;
+
+    dev->qirq = spapr_allocate_irq(dev->vio_irq_num, &dev->vio_irq_num);
+    if (!dev->qirq) {
+        return -1;
     }
-    dev->qirq = spapr_find_qirq(spapr, dev->vio_irq_num);
 
     rtce_init(dev);
 
@@ -666,7 +666,6 @@ VIOsPAPRBus *spapr_vio_bus_init(void)
 
     qbus = qbus_create(&spapr_vio_bus_info, dev, "spapr-vio");
     bus = DO_UPCAST(VIOsPAPRBus, bus, qbus);
-    bus->irq = 16;
 
     /* hcall-vio */
     spapr_register_hypercall(H_VIO_SIGNAL, h_vio_signal);
diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h
index 7eb5367..4fe5f74 100644
--- a/hw/spapr_vio.h
+++ b/hw/spapr_vio.h
@@ -67,7 +67,6 @@ typedef struct VIOsPAPRDevice {
 
 typedef struct VIOsPAPRBus {
     BusState bus;
-    int irq;
 } VIOsPAPRBus;
 
 typedef struct {
commit 44427c401f7c0053db31f40a58a427e1ae3cd8c3
Author: Alexander Graf <agraf at suse.de>
Date:   Mon Sep 19 15:17:47 2011 +0200

    PPC: Clean up BookE timer code
    
    The BookE timer code had some written-but-not-read variables. Get rid
    of them.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/ppc_booke.c b/hw/ppc_booke.c
index 3e2fff5..8871945 100644
--- a/hw/ppc_booke.c
+++ b/hw/ppc_booke.c
@@ -153,15 +153,9 @@ static void booke_update_fixed_timer(CPUState         *env,
 
 static void booke_decr_cb(void *opaque)
 {
-    CPUState *env;
-    ppc_tb_t *tb_env;
-    booke_timer_t *booke_timer;
+    CPUState *env = opaque;
 
-    env = opaque;
-    tb_env = env->tb_env;
-    booke_timer = tb_env->opaque;
     env->spr[SPR_BOOKE_TSR] |= TSR_DIS;
-
     booke_update_irq(env);
 
     if (env->spr[SPR_BOOKE_TCR] & TCR_ARE) {
@@ -211,13 +205,7 @@ static void booke_wdt_cb(void *opaque)
 
 void store_booke_tsr(CPUState *env, target_ulong val)
 {
-    ppc_tb_t *tb_env = env->tb_env;
-    booke_timer_t *booke_timer;
-
-    booke_timer = tb_env->opaque;
-
     env->spr[SPR_BOOKE_TSR] &= ~val;
-
     booke_update_irq(env);
 }
 
commit ddd1055b07fdfe488a22c2275adaca75f4206d30
Author: Fabien Chouteau <chouteau at adacore.com>
Date:   Tue Sep 13 04:00:32 2011 +0000

    PPC: booke timers
    
    While working on the emulation of the freescale p2010 (e500v2) I realized that
    there's no implementation of booke's timers features. Currently mpc8544 uses
    ppc_emb (ppc_emb_timers_init) which is close but not exactly like booke (for
    example booke uses different SPR).
    
    Signed-off-by: Fabien Chouteau <chouteau at adacore.com>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/Makefile.target b/Makefile.target
index fc3dfaa..1e9815c 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -229,7 +229,7 @@ obj-i386-$(CONFIG_KVM) += kvmclock.o
 obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
 
 # shared objects
-obj-ppc-y = ppc.o
+obj-ppc-y = ppc.o ppc_booke.o
 obj-ppc-y += vga.o
 # PREP target
 obj-ppc-y += i8259.o mc146818rtc.o
diff --git a/hw/ppc.c b/hw/ppc.c
index 8870748..25b59dd 100644
--- a/hw/ppc.c
+++ b/hw/ppc.c
@@ -50,7 +50,7 @@
 static void cpu_ppc_tb_stop (CPUState *env);
 static void cpu_ppc_tb_start (CPUState *env);
 
-static void ppc_set_irq (CPUState *env, int n_IRQ, int level)
+void ppc_set_irq(CPUState *env, int n_IRQ, int level)
 {
     unsigned int old_pending = env->pending_interrupts;
 
@@ -423,25 +423,8 @@ void ppce500_irq_init (CPUState *env)
 }
 /*****************************************************************************/
 /* PowerPC time base and decrementer emulation */
-struct ppc_tb_t {
-    /* Time base management */
-    int64_t  tb_offset;    /* Compensation                    */
-    int64_t  atb_offset;   /* Compensation                    */
-    uint32_t tb_freq;      /* TB frequency                    */
-    /* Decrementer management */
-    uint64_t decr_next;    /* Tick for next decr interrupt    */
-    uint32_t decr_freq;    /* decrementer frequency           */
-    struct QEMUTimer *decr_timer;
-    /* Hypervisor decrementer management */
-    uint64_t hdecr_next;    /* Tick for next hdecr interrupt  */
-    struct QEMUTimer *hdecr_timer;
-    uint64_t purr_load;
-    uint64_t purr_start;
-    void *opaque;
-};
 
-static inline uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk,
-                                      int64_t tb_offset)
+uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset)
 {
     /* TB time in tb periods */
     return muldiv64(vmclk, tb_env->tb_freq, get_ticks_per_sec()) + tb_offset;
@@ -611,10 +594,13 @@ static inline uint32_t _cpu_ppc_load_decr(CPUState *env, uint64_t next)
     int64_t diff;
 
     diff = next - qemu_get_clock_ns(vm_clock);
-    if (diff >= 0)
+    if (diff >= 0) {
         decr = muldiv64(diff, tb_env->decr_freq, get_ticks_per_sec());
-    else
+    } else if (tb_env->flags & PPC_TIMER_BOOKE) {
+        decr = 0;
+    }  else {
         decr = -muldiv64(-diff, tb_env->decr_freq, get_ticks_per_sec());
+    }
     LOG_TB("%s: %08" PRIx32 "\n", __func__, decr);
 
     return decr;
@@ -678,18 +664,24 @@ static void __cpu_ppc_store_decr (CPUState *env, uint64_t *nextp,
                 decr, value);
     now = qemu_get_clock_ns(vm_clock);
     next = now + muldiv64(value, get_ticks_per_sec(), tb_env->decr_freq);
-    if (is_excp)
+    if (is_excp) {
         next += *nextp - now;
-    if (next == now)
+    }
+    if (next == now) {
         next++;
+    }
     *nextp = next;
     /* Adjust timer */
     qemu_mod_timer(timer, next);
-    /* If we set a negative value and the decrementer was positive,
-     * raise an exception.
+
+    /* If we set a negative value and the decrementer was positive, raise an
+     * exception.
      */
-    if ((value & 0x80000000) && !(decr & 0x80000000))
+    if ((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED)
+        && (value & 0x80000000)
+        && !(decr & 0x80000000)) {
         (*raise_excp)(env);
+    }
 }
 
 static inline void _cpu_ppc_store_decr(CPUState *env, uint32_t decr,
@@ -763,6 +755,7 @@ clk_setup_cb cpu_ppc_tb_init (CPUState *env, uint32_t freq)
 
     tb_env = g_malloc0(sizeof(ppc_tb_t));
     env->tb_env = tb_env;
+    tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED;
     /* Create new timer */
     tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &cpu_ppc_decr_cb, env);
     if (0) {
@@ -806,11 +799,11 @@ uint32_t cpu_ppc601_load_rtcl (CPUState *env)
 }
 
 /*****************************************************************************/
-/* Embedded PowerPC timers */
+/* PowerPC 40x timers */
 
 /* PIT, FIT & WDT */
-typedef struct ppcemb_timer_t ppcemb_timer_t;
-struct ppcemb_timer_t {
+typedef struct ppc40x_timer_t ppc40x_timer_t;
+struct ppc40x_timer_t {
     uint64_t pit_reload;  /* PIT auto-reload value        */
     uint64_t fit_next;    /* Tick for next FIT interrupt  */
     struct QEMUTimer *fit_timer;
@@ -826,12 +819,12 @@ static void cpu_4xx_fit_cb (void *opaque)
 {
     CPUState *env;
     ppc_tb_t *tb_env;
-    ppcemb_timer_t *ppcemb_timer;
+    ppc40x_timer_t *ppc40x_timer;
     uint64_t now, next;
 
     env = opaque;
     tb_env = env->tb_env;
-    ppcemb_timer = tb_env->opaque;
+    ppc40x_timer = tb_env->opaque;
     now = qemu_get_clock_ns(vm_clock);
     switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) {
     case 0:
@@ -853,7 +846,7 @@ static void cpu_4xx_fit_cb (void *opaque)
     next = now + muldiv64(next, get_ticks_per_sec(), tb_env->tb_freq);
     if (next == now)
         next++;
-    qemu_mod_timer(ppcemb_timer->fit_timer, next);
+    qemu_mod_timer(ppc40x_timer->fit_timer, next);
     env->spr[SPR_40x_TSR] |= 1 << 26;
     if ((env->spr[SPR_40x_TCR] >> 23) & 0x1)
         ppc_set_irq(env, PPC_INTERRUPT_FIT, 1);
@@ -865,11 +858,11 @@ static void cpu_4xx_fit_cb (void *opaque)
 /* Programmable interval timer */
 static void start_stop_pit (CPUState *env, ppc_tb_t *tb_env, int is_excp)
 {
-    ppcemb_timer_t *ppcemb_timer;
+    ppc40x_timer_t *ppc40x_timer;
     uint64_t now, next;
 
-    ppcemb_timer = tb_env->opaque;
-    if (ppcemb_timer->pit_reload <= 1 ||
+    ppc40x_timer = tb_env->opaque;
+    if (ppc40x_timer->pit_reload <= 1 ||
         !((env->spr[SPR_40x_TCR] >> 26) & 0x1) ||
         (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) {
         /* Stop PIT */
@@ -877,9 +870,9 @@ static void start_stop_pit (CPUState *env, ppc_tb_t *tb_env, int is_excp)
         qemu_del_timer(tb_env->decr_timer);
     } else {
         LOG_TB("%s: start PIT %016" PRIx64 "\n",
-                    __func__, ppcemb_timer->pit_reload);
+                    __func__, ppc40x_timer->pit_reload);
         now = qemu_get_clock_ns(vm_clock);
-        next = now + muldiv64(ppcemb_timer->pit_reload,
+        next = now + muldiv64(ppc40x_timer->pit_reload,
                               get_ticks_per_sec(), tb_env->decr_freq);
         if (is_excp)
             next += tb_env->decr_next - now;
@@ -894,21 +887,21 @@ static void cpu_4xx_pit_cb (void *opaque)
 {
     CPUState *env;
     ppc_tb_t *tb_env;
-    ppcemb_timer_t *ppcemb_timer;
+    ppc40x_timer_t *ppc40x_timer;
 
     env = opaque;
     tb_env = env->tb_env;
-    ppcemb_timer = tb_env->opaque;
+    ppc40x_timer = tb_env->opaque;
     env->spr[SPR_40x_TSR] |= 1 << 27;
     if ((env->spr[SPR_40x_TCR] >> 26) & 0x1)
-        ppc_set_irq(env, ppcemb_timer->decr_excp, 1);
+        ppc_set_irq(env, ppc40x_timer->decr_excp, 1);
     start_stop_pit(env, tb_env, 1);
     LOG_TB("%s: ar %d ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx " "
            "%016" PRIx64 "\n", __func__,
            (int)((env->spr[SPR_40x_TCR] >> 22) & 0x1),
            (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1),
            env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR],
-           ppcemb_timer->pit_reload);
+           ppc40x_timer->pit_reload);
 }
 
 /* Watchdog timer */
@@ -916,12 +909,12 @@ static void cpu_4xx_wdt_cb (void *opaque)
 {
     CPUState *env;
     ppc_tb_t *tb_env;
-    ppcemb_timer_t *ppcemb_timer;
+    ppc40x_timer_t *ppc40x_timer;
     uint64_t now, next;
 
     env = opaque;
     tb_env = env->tb_env;
-    ppcemb_timer = tb_env->opaque;
+    ppc40x_timer = tb_env->opaque;
     now = qemu_get_clock_ns(vm_clock);
     switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) {
     case 0:
@@ -948,13 +941,13 @@ static void cpu_4xx_wdt_cb (void *opaque)
     switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) {
     case 0x0:
     case 0x1:
-        qemu_mod_timer(ppcemb_timer->wdt_timer, next);
-        ppcemb_timer->wdt_next = next;
+        qemu_mod_timer(ppc40x_timer->wdt_timer, next);
+        ppc40x_timer->wdt_next = next;
         env->spr[SPR_40x_TSR] |= 1 << 31;
         break;
     case 0x2:
-        qemu_mod_timer(ppcemb_timer->wdt_timer, next);
-        ppcemb_timer->wdt_next = next;
+        qemu_mod_timer(ppc40x_timer->wdt_timer, next);
+        ppc40x_timer->wdt_next = next;
         env->spr[SPR_40x_TSR] |= 1 << 30;
         if ((env->spr[SPR_40x_TCR] >> 27) & 0x1)
             ppc_set_irq(env, PPC_INTERRUPT_WDT, 1);
@@ -982,12 +975,12 @@ static void cpu_4xx_wdt_cb (void *opaque)
 void store_40x_pit (CPUState *env, target_ulong val)
 {
     ppc_tb_t *tb_env;
-    ppcemb_timer_t *ppcemb_timer;
+    ppc40x_timer_t *ppc40x_timer;
 
     tb_env = env->tb_env;
-    ppcemb_timer = tb_env->opaque;
+    ppc40x_timer = tb_env->opaque;
     LOG_TB("%s val" TARGET_FMT_lx "\n", __func__, val);
-    ppcemb_timer->pit_reload = val;
+    ppc40x_timer->pit_reload = val;
     start_stop_pit(env, tb_env, 0);
 }
 
@@ -996,31 +989,7 @@ target_ulong load_40x_pit (CPUState *env)
     return cpu_ppc_load_decr(env);
 }
 
-void store_booke_tsr (CPUState *env, target_ulong val)
-{
-    ppc_tb_t *tb_env = env->tb_env;
-    ppcemb_timer_t *ppcemb_timer;
-
-    ppcemb_timer = tb_env->opaque;
-
-    LOG_TB("%s: val " TARGET_FMT_lx "\n", __func__, val);
-    env->spr[SPR_40x_TSR] &= ~(val & 0xFC000000);
-    if (val & 0x80000000)
-        ppc_set_irq(env, ppcemb_timer->decr_excp, 0);
-}
-
-void store_booke_tcr (CPUState *env, target_ulong val)
-{
-    ppc_tb_t *tb_env;
-
-    tb_env = env->tb_env;
-    LOG_TB("%s: val " TARGET_FMT_lx "\n", __func__, val);
-    env->spr[SPR_40x_TCR] = val & 0xFFC00000;
-    start_stop_pit(env, tb_env, 1);
-    cpu_4xx_wdt_cb(env);
-}
-
-static void ppc_emb_set_tb_clk (void *opaque, uint32_t freq)
+static void ppc_40x_set_tb_clk (void *opaque, uint32_t freq)
 {
     CPUState *env = opaque;
     ppc_tb_t *tb_env = env->tb_env;
@@ -1032,30 +1001,31 @@ static void ppc_emb_set_tb_clk (void *opaque, uint32_t freq)
     /* XXX: we should also update all timers */
 }
 
-clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq,
+clk_setup_cb ppc_40x_timers_init (CPUState *env, uint32_t freq,
                                   unsigned int decr_excp)
 {
     ppc_tb_t *tb_env;
-    ppcemb_timer_t *ppcemb_timer;
+    ppc40x_timer_t *ppc40x_timer;
 
     tb_env = g_malloc0(sizeof(ppc_tb_t));
     env->tb_env = tb_env;
-    ppcemb_timer = g_malloc0(sizeof(ppcemb_timer_t));
+    tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED;
+    ppc40x_timer = g_malloc0(sizeof(ppc40x_timer_t));
     tb_env->tb_freq = freq;
     tb_env->decr_freq = freq;
-    tb_env->opaque = ppcemb_timer;
+    tb_env->opaque = ppc40x_timer;
     LOG_TB("%s freq %" PRIu32 "\n", __func__, freq);
-    if (ppcemb_timer != NULL) {
+    if (ppc40x_timer != NULL) {
         /* We use decr timer for PIT */
         tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &cpu_4xx_pit_cb, env);
-        ppcemb_timer->fit_timer =
+        ppc40x_timer->fit_timer =
             qemu_new_timer_ns(vm_clock, &cpu_4xx_fit_cb, env);
-        ppcemb_timer->wdt_timer =
+        ppc40x_timer->wdt_timer =
             qemu_new_timer_ns(vm_clock, &cpu_4xx_wdt_cb, env);
-        ppcemb_timer->decr_excp = decr_excp;
+        ppc40x_timer->decr_excp = decr_excp;
     }
 
-    return &ppc_emb_set_tb_clk;
+    return &ppc_40x_set_tb_clk;
 }
 
 /*****************************************************************************/
diff --git a/hw/ppc.h b/hw/ppc.h
index 3ccf134..9f91170 100644
--- a/hw/ppc.h
+++ b/hw/ppc.h
@@ -1,3 +1,5 @@
+void ppc_set_irq (CPUState *env, int n_IRQ, int level);
+
 /* PowerPC hardware exceptions management helpers */
 typedef void (*clk_setup_cb)(void *opaque, uint32_t freq);
 typedef struct clk_setup_t clk_setup_t;
@@ -11,6 +13,36 @@ static inline void clk_setup (clk_setup_t *clk, uint32_t freq)
         (*clk->cb)(clk->opaque, freq);
 }
 
+struct ppc_tb_t {
+    /* Time base management */
+    int64_t  tb_offset;    /* Compensation                    */
+    int64_t  atb_offset;   /* Compensation                    */
+    uint32_t tb_freq;      /* TB frequency                    */
+    /* Decrementer management */
+    uint64_t decr_next;    /* Tick for next decr interrupt    */
+    uint32_t decr_freq;    /* decrementer frequency           */
+    struct QEMUTimer *decr_timer;
+    /* Hypervisor decrementer management */
+    uint64_t hdecr_next;    /* Tick for next hdecr interrupt  */
+    struct QEMUTimer *hdecr_timer;
+    uint64_t purr_load;
+    uint64_t purr_start;
+    void *opaque;
+    uint32_t flags;
+};
+
+/* PPC Timers flags */
+#define PPC_TIMER_BOOKE              (1 << 0) /* Enable Booke support */
+#define PPC_TIMER_E500               (1 << 1) /* Enable e500 support */
+#define PPC_DECR_UNDERFLOW_TRIGGERED (1 << 2) /* Decr interrupt triggered when
+                                               * the most significant bit
+                                               * changes from 0 to 1.
+                                               */
+#define PPC_DECR_ZERO_TRIGGERED      (1 << 3) /* Decr interrupt triggered when
+                                               * the decrementer reaches zero.
+                                               */
+
+uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset);
 clk_setup_cb cpu_ppc_tb_init (CPUState *env, uint32_t freq);
 /* Embedded PowerPC DCR management */
 typedef uint32_t (*dcr_read_cb)(void *opaque, int dcrn);
@@ -19,7 +51,7 @@ int ppc_dcr_init (CPUState *env, int (*dcr_read_error)(int dcrn),
                   int (*dcr_write_error)(int dcrn));
 int ppc_dcr_register (CPUState *env, int dcrn, void *opaque,
                       dcr_read_cb drc_read, dcr_write_cb dcr_write);
-clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq,
+clk_setup_cb ppc_40x_timers_init (CPUState *env, uint32_t freq,
                                   unsigned int decr_excp);
 
 /* Embedded PowerPC reset */
@@ -55,3 +87,6 @@ enum {
 #define FW_CFG_PPC_KVM_PID      (FW_CFG_ARCH_LOCAL + 0x07)
 
 #define PPC_SERIAL_MM_BAUDBASE 399193
+
+/* ppc_booke.c */
+void ppc_booke_timers_init(CPUState *env, uint32_t freq, uint32_t flags);
diff --git a/hw/ppc4xx_devs.c b/hw/ppc4xx_devs.c
index 349f046..d18caa4 100644
--- a/hw/ppc4xx_devs.c
+++ b/hw/ppc4xx_devs.c
@@ -56,7 +56,7 @@ CPUState *ppc4xx_init (const char *cpu_model,
     cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */
     cpu_clk->opaque = env;
     /* Set time-base frequency to sysclk */
-    tb_clk->cb = ppc_emb_timers_init(env, sysclk, PPC_INTERRUPT_PIT);
+    tb_clk->cb = ppc_40x_timers_init(env, sysclk, PPC_INTERRUPT_PIT);
     tb_clk->opaque = env;
     ppc_dcr_init(env, NULL, NULL);
     /* Register qemu callbacks */
diff --git a/hw/ppc_booke.c b/hw/ppc_booke.c
new file mode 100644
index 0000000..3e2fff5
--- /dev/null
+++ b/hw/ppc_booke.c
@@ -0,0 +1,266 @@
+/*
+ * QEMU PowerPC Booke hardware System Emulator
+ *
+ * Copyright (c) 2011 AdaCore
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw.h"
+#include "ppc.h"
+#include "qemu-timer.h"
+#include "sysemu.h"
+#include "nvram.h"
+#include "qemu-log.h"
+#include "loader.h"
+
+
+/* Timer Control Register */
+
+#define TCR_WP_SHIFT  30        /* Watchdog Timer Period */
+#define TCR_WP_MASK   (0x3 << TCR_WP_SHIFT)
+#define TCR_WRC_SHIFT 28        /* Watchdog Timer Reset Control */
+#define TCR_WRC_MASK  (0x3 << TCR_WRC_SHIFT)
+#define TCR_WIE       (1 << 27) /* Watchdog Timer Interrupt Enable */
+#define TCR_DIE       (1 << 26) /* Decrementer Interrupt Enable */
+#define TCR_FP_SHIFT  24        /* Fixed-Interval Timer Period */
+#define TCR_FP_MASK   (0x3 << TCR_FP_SHIFT)
+#define TCR_FIE       (1 << 23) /* Fixed-Interval Timer Interrupt Enable */
+#define TCR_ARE       (1 << 22) /* Auto-Reload Enable */
+
+/* Timer Control Register (e500 specific fields) */
+
+#define TCR_E500_FPEXT_SHIFT 13 /* Fixed-Interval Timer Period Extension */
+#define TCR_E500_FPEXT_MASK  (0xf << TCR_E500_FPEXT_SHIFT)
+#define TCR_E500_WPEXT_SHIFT 17 /* Watchdog Timer Period Extension */
+#define TCR_E500_WPEXT_MASK  (0xf << TCR_E500_WPEXT_SHIFT)
+
+/* Timer Status Register  */
+
+#define TSR_FIS       (1 << 26) /* Fixed-Interval Timer Interrupt Status */
+#define TSR_DIS       (1 << 27) /* Decrementer Interrupt Status */
+#define TSR_WRS_SHIFT 28        /* Watchdog Timer Reset Status */
+#define TSR_WRS_MASK  (0x3 << TSR_WRS_SHIFT)
+#define TSR_WIS       (1 << 30) /* Watchdog Timer Interrupt Status */
+#define TSR_ENW       (1 << 31) /* Enable Next Watchdog Timer */
+
+typedef struct booke_timer_t booke_timer_t;
+struct booke_timer_t {
+
+    uint64_t fit_next;
+    struct QEMUTimer *fit_timer;
+
+    uint64_t wdt_next;
+    struct QEMUTimer *wdt_timer;
+
+    uint32_t flags;
+};
+
+static void booke_update_irq(CPUState *env)
+{
+    ppc_set_irq(env, PPC_INTERRUPT_DECR,
+                (env->spr[SPR_BOOKE_TSR] & TSR_DIS
+                 && env->spr[SPR_BOOKE_TCR] & TCR_DIE));
+
+    ppc_set_irq(env, PPC_INTERRUPT_WDT,
+                (env->spr[SPR_BOOKE_TSR] & TSR_WIS
+                 && env->spr[SPR_BOOKE_TCR] & TCR_WIE));
+
+    ppc_set_irq(env, PPC_INTERRUPT_FIT,
+                (env->spr[SPR_BOOKE_TSR] & TSR_FIS
+                 && env->spr[SPR_BOOKE_TCR] & TCR_FIE));
+}
+
+/* Return the location of the bit of time base at which the FIT will raise an
+   interrupt */
+static uint8_t booke_get_fit_target(CPUState *env, ppc_tb_t *tb_env)
+{
+    uint8_t fp = (env->spr[SPR_BOOKE_TCR] & TCR_FP_MASK) >> TCR_FP_SHIFT;
+
+    if (tb_env->flags & PPC_TIMER_E500) {
+        /* e500 Fixed-interval timer period extension */
+        uint32_t fpext = (env->spr[SPR_BOOKE_TCR] & TCR_E500_FPEXT_MASK)
+            >> TCR_E500_FPEXT_SHIFT;
+        fp = 63 - (fp | fpext << 2);
+    } else {
+        fp = env->fit_period[fp];
+    }
+
+    return fp;
+}
+
+/* Return the location of the bit of time base at which the WDT will raise an
+   interrupt */
+static uint8_t booke_get_wdt_target(CPUState *env, ppc_tb_t *tb_env)
+{
+    uint8_t wp = (env->spr[SPR_BOOKE_TCR] & TCR_WP_MASK) >> TCR_WP_SHIFT;
+
+    if (tb_env->flags & PPC_TIMER_E500) {
+        /* e500 Watchdog timer period extension */
+        uint32_t wpext = (env->spr[SPR_BOOKE_TCR] & TCR_E500_WPEXT_MASK)
+            >> TCR_E500_WPEXT_SHIFT;
+        wp = 63 - (wp | wpext << 2);
+    } else {
+        wp = env->wdt_period[wp];
+    }
+
+    return wp;
+}
+
+static void booke_update_fixed_timer(CPUState         *env,
+                                     uint8_t           target_bit,
+                                     uint64_t          *next,
+                                     struct QEMUTimer *timer)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t lapse;
+    uint64_t tb;
+    uint64_t period = 1 << (target_bit + 1);
+    uint64_t now;
+
+    now = qemu_get_clock_ns(vm_clock);
+    tb  = cpu_ppc_get_tb(tb_env, now, tb_env->tb_offset);
+
+    lapse = period - ((tb - (1 << target_bit)) & (period - 1));
+
+    *next = now + muldiv64(lapse, get_ticks_per_sec(), tb_env->tb_freq);
+
+    /* XXX: If expire time is now. We can't run the callback because we don't
+     * have access to it. So we just set the timer one nanosecond later.
+     */
+
+    if (*next == now) {
+        (*next)++;
+    }
+
+    qemu_mod_timer(timer, *next);
+}
+
+static void booke_decr_cb(void *opaque)
+{
+    CPUState *env;
+    ppc_tb_t *tb_env;
+    booke_timer_t *booke_timer;
+
+    env = opaque;
+    tb_env = env->tb_env;
+    booke_timer = tb_env->opaque;
+    env->spr[SPR_BOOKE_TSR] |= TSR_DIS;
+
+    booke_update_irq(env);
+
+    if (env->spr[SPR_BOOKE_TCR] & TCR_ARE) {
+        /* Auto Reload */
+        cpu_ppc_store_decr(env, env->spr[SPR_BOOKE_DECAR]);
+    }
+}
+
+static void booke_fit_cb(void *opaque)
+{
+    CPUState *env;
+    ppc_tb_t *tb_env;
+    booke_timer_t *booke_timer;
+
+    env = opaque;
+    tb_env = env->tb_env;
+    booke_timer = tb_env->opaque;
+    env->spr[SPR_BOOKE_TSR] |= TSR_FIS;
+
+    booke_update_irq(env);
+
+    booke_update_fixed_timer(env,
+                             booke_get_fit_target(env, tb_env),
+                             &booke_timer->fit_next,
+                             booke_timer->fit_timer);
+}
+
+static void booke_wdt_cb(void *opaque)
+{
+    CPUState *env;
+    ppc_tb_t *tb_env;
+    booke_timer_t *booke_timer;
+
+    env = opaque;
+    tb_env = env->tb_env;
+    booke_timer = tb_env->opaque;
+
+    /* TODO: There's lots of complicated stuff to do here */
+
+    booke_update_irq(env);
+
+    booke_update_fixed_timer(env,
+                             booke_get_wdt_target(env, tb_env),
+                             &booke_timer->wdt_next,
+                             booke_timer->wdt_timer);
+}
+
+void store_booke_tsr(CPUState *env, target_ulong val)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    booke_timer_t *booke_timer;
+
+    booke_timer = tb_env->opaque;
+
+    env->spr[SPR_BOOKE_TSR] &= ~val;
+
+    booke_update_irq(env);
+}
+
+void store_booke_tcr(CPUState *env, target_ulong val)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    booke_timer_t *booke_timer = tb_env->opaque;
+
+    tb_env = env->tb_env;
+    env->spr[SPR_BOOKE_TCR] = val;
+
+    booke_update_irq(env);
+
+    booke_update_fixed_timer(env,
+                             booke_get_fit_target(env, tb_env),
+                             &booke_timer->fit_next,
+                             booke_timer->fit_timer);
+
+    booke_update_fixed_timer(env,
+                             booke_get_wdt_target(env, tb_env),
+                             &booke_timer->wdt_next,
+                             booke_timer->wdt_timer);
+
+}
+
+void ppc_booke_timers_init(CPUState *env, uint32_t freq, uint32_t flags)
+{
+    ppc_tb_t *tb_env;
+    booke_timer_t *booke_timer;
+
+    tb_env      = g_malloc0(sizeof(ppc_tb_t));
+    booke_timer = g_malloc0(sizeof(booke_timer_t));
+
+    env->tb_env = tb_env;
+    tb_env->flags = flags | PPC_TIMER_BOOKE | PPC_DECR_ZERO_TRIGGERED;
+
+    tb_env->tb_freq    = freq;
+    tb_env->decr_freq  = freq;
+    tb_env->opaque     = booke_timer;
+    tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &booke_decr_cb, env);
+
+    booke_timer->fit_timer =
+        qemu_new_timer_ns(vm_clock, &booke_fit_cb, env);
+    booke_timer->wdt_timer =
+        qemu_new_timer_ns(vm_clock, &booke_wdt_cb, env);
+}
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 8095516..f00367e 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -268,11 +268,7 @@ static void mpc8544ds_init(ram_addr_t ram_size,
         irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
         env->spr[SPR_BOOKE_PIR] = env->cpu_index = i;
 
-        /* XXX register timer? */
-        ppc_emb_timers_init(env, 400000000, PPC_INTERRUPT_DECR);
-        ppc_dcr_init(env, NULL, NULL);
-        /* XXX Enable DEC interrupts - probably wrong in the backend */
-        env->spr[SPR_40x_TCR] = 1 << 26;
+        ppc_booke_timers_init(env, 400000000, PPC_TIMER_E500);
 
         /* Register reset handler */
         if (!i) {
diff --git a/hw/virtex_ml507.c b/hw/virtex_ml507.c
index 7459b0b..66df27a 100644
--- a/hw/virtex_ml507.c
+++ b/hw/virtex_ml507.c
@@ -81,7 +81,6 @@ static void mmubooke_create_initial_mapping(CPUState *env,
 static CPUState *ppc440_init_xilinx(ram_addr_t *ram_size,
                                     int do_init,
                                     const char *cpu_model,
-                                    clk_setup_t *cpu_clk, clk_setup_t *tb_clk,
                                     uint32_t sysclk)
 {
     CPUState *env;
@@ -93,11 +92,7 @@ static CPUState *ppc440_init_xilinx(ram_addr_t *ram_size,
         exit(1);
     }
 
-    cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */
-    cpu_clk->opaque = env;
-    /* Set time-base frequency to sysclk */
-    tb_clk->cb = ppc_emb_timers_init(env, sysclk, PPC_INTERRUPT_DECR);
-    tb_clk->opaque = env;
+    ppc_booke_timers_init(env, sysclk, 0/* no flags */);
 
     ppc_dcr_init(env, NULL, NULL);
 
@@ -197,7 +192,6 @@ static void virtex_init(ram_addr_t ram_size,
     DriveInfo *dinfo;
     ram_addr_t phys_ram;
     qemu_irq irq[32], *cpu_irq;
-    clk_setup_t clk_setup[7];
     int kernel_size;
     int i;
 
@@ -207,8 +201,7 @@ static void virtex_init(ram_addr_t ram_size,
     }
 
     memset(clk_setup, 0, sizeof(clk_setup));
-    env = ppc440_init_xilinx(&ram_size, 1, cpu_model, &clk_setup[0],
-                             &clk_setup[1], 400000000);
+    env = ppc440_init_xilinx(&ram_size, 1, cpu_model, 400000000);
     qemu_register_reset(main_cpu_reset, env);
 
     phys_ram = qemu_ram_alloc(NULL, "ram", ram_size);
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 3f4af22..3f77e30 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1018,8 +1018,35 @@ struct CPUPPCState {
 #if !defined(CONFIG_USER_ONLY)
     void *load_info;    /* Holds boot loading state.  */
 #endif
+
+    /* booke timers */
+
+    /* Specifies bit locations of the Time Base used to signal a fixed timer
+     * exception on a transition from 0 to 1. (watchdog or fixed-interval timer)
+     *
+     * 0 selects the least significant bit.
+     * 63 selects the most significant bit.
+     */
+    uint8_t fit_period[4];
+    uint8_t wdt_period[4];
 };
 
+#define SET_FIT_PERIOD(a_, b_, c_, d_)          \
+do {                                            \
+    env->fit_period[0] = (a_);                  \
+    env->fit_period[1] = (b_);                  \
+    env->fit_period[2] = (c_);                  \
+    env->fit_period[3] = (d_);                  \
+ } while (0)
+
+#define SET_WDT_PERIOD(a_, b_, c_, d_)          \
+do {                                            \
+    env->wdt_period[0] = (a_);                  \
+    env->wdt_period[1] = (b_);                  \
+    env->wdt_period[2] = (c_);                  \
+    env->wdt_period[3] = (d_);                  \
+ } while (0)
+
 #if !defined(CONFIG_USER_ONLY)
 /* Context used internally during MMU translations */
 typedef struct mmu_ctx_t mmu_ctx_t;
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index d09c7ca..ca0d852 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -3266,6 +3266,9 @@ static void init_proc_401 (CPUPPCState *env)
     env->icache_line_size = 32;
     /* Allocate hardware IRQ controller */
     ppc40x_irq_init(env);
+
+    SET_FIT_PERIOD(12, 16, 20, 24);
+    SET_WDT_PERIOD(16, 20, 24, 28);
 }
 
 /* PowerPC 401x2                                                             */
@@ -3304,6 +3307,9 @@ static void init_proc_401x2 (CPUPPCState *env)
     env->icache_line_size = 32;
     /* Allocate hardware IRQ controller */
     ppc40x_irq_init(env);
+
+    SET_FIT_PERIOD(12, 16, 20, 24);
+    SET_WDT_PERIOD(16, 20, 24, 28);
 }
 
 /* PowerPC 401x3                                                             */
@@ -3337,6 +3343,9 @@ static void init_proc_401x3 (CPUPPCState *env)
     env->icache_line_size = 32;
     /* Allocate hardware IRQ controller */
     ppc40x_irq_init(env);
+
+    SET_FIT_PERIOD(12, 16, 20, 24);
+    SET_WDT_PERIOD(16, 20, 24, 28);
 }
 
 /* IOP480                                                                    */
@@ -3375,6 +3384,9 @@ static void init_proc_IOP480 (CPUPPCState *env)
     env->icache_line_size = 32;
     /* Allocate hardware IRQ controller */
     ppc40x_irq_init(env);
+
+    SET_FIT_PERIOD(8, 12, 16, 20);
+    SET_WDT_PERIOD(16, 20, 24, 28);
 }
 
 /* PowerPC 403                                                               */
@@ -3405,6 +3417,9 @@ static void init_proc_403 (CPUPPCState *env)
     env->icache_line_size = 32;
     /* Allocate hardware IRQ controller */
     ppc40x_irq_init(env);
+
+    SET_FIT_PERIOD(8, 12, 16, 20);
+    SET_WDT_PERIOD(16, 20, 24, 28);
 }
 
 /* PowerPC 403 GCX                                                           */
@@ -3455,6 +3470,9 @@ static void init_proc_403GCX (CPUPPCState *env)
     env->icache_line_size = 32;
     /* Allocate hardware IRQ controller */
     ppc40x_irq_init(env);
+
+    SET_FIT_PERIOD(8, 12, 16, 20);
+    SET_WDT_PERIOD(16, 20, 24, 28);
 }
 
 /* PowerPC 405                                                               */
@@ -3504,6 +3522,9 @@ static void init_proc_405 (CPUPPCState *env)
     env->icache_line_size = 32;
     /* Allocate hardware IRQ controller */
     ppc40x_irq_init(env);
+
+    SET_FIT_PERIOD(8, 12, 16, 20);
+    SET_WDT_PERIOD(16, 20, 24, 28);
 }
 
 /* PowerPC 440 EP                                                            */
@@ -3586,6 +3607,9 @@ static void init_proc_440EP (CPUPPCState *env)
     env->dcache_line_size = 32;
     env->icache_line_size = 32;
     /* XXX: TODO: allocate internal IRQ controller */
+
+    SET_FIT_PERIOD(12, 16, 20, 24);
+    SET_WDT_PERIOD(20, 24, 28, 32);
 }
 
 /* PowerPC 440 GP                                                            */
@@ -3650,6 +3674,9 @@ static void init_proc_440GP (CPUPPCState *env)
     env->dcache_line_size = 32;
     env->icache_line_size = 32;
     /* XXX: TODO: allocate internal IRQ controller */
+
+    SET_FIT_PERIOD(12, 16, 20, 24);
+    SET_WDT_PERIOD(20, 24, 28, 32);
 }
 
 /* PowerPC 440x4                                                             */
@@ -3714,6 +3741,9 @@ static void init_proc_440x4 (CPUPPCState *env)
     env->dcache_line_size = 32;
     env->icache_line_size = 32;
     /* XXX: TODO: allocate internal IRQ controller */
+
+    SET_FIT_PERIOD(12, 16, 20, 24);
+    SET_WDT_PERIOD(20, 24, 28, 32);
 }
 
 /* PowerPC 440x5                                                             */
@@ -3795,6 +3825,9 @@ static void init_proc_440x5 (CPUPPCState *env)
     env->dcache_line_size = 32;
     env->icache_line_size = 32;
     ppc40x_irq_init(env);
+
+    SET_FIT_PERIOD(12, 16, 20, 24);
+    SET_WDT_PERIOD(20, 24, 28, 32);
 }
 
 /* PowerPC 460 (guessed)                                                     */
@@ -3883,6 +3916,9 @@ static void init_proc_460 (CPUPPCState *env)
     env->dcache_line_size = 32;
     env->icache_line_size = 32;
     /* XXX: TODO: allocate internal IRQ controller */
+
+    SET_FIT_PERIOD(12, 16, 20, 24);
+    SET_WDT_PERIOD(20, 24, 28, 32);
 }
 
 /* PowerPC 460F (guessed)                                                    */
@@ -3974,6 +4010,9 @@ static void init_proc_460F (CPUPPCState *env)
     env->dcache_line_size = 32;
     env->icache_line_size = 32;
     /* XXX: TODO: allocate internal IRQ controller */
+
+    SET_FIT_PERIOD(12, 16, 20, 24);
+    SET_WDT_PERIOD(20, 24, 28, 32);
 }
 
 /* Freescale 5xx cores (aka RCPU) */
commit 94135e813c14bac3f967e6b5aa35b9d617737e68
Author: Alexander Graf <agraf at suse.de>
Date:   Wed Sep 14 21:38:45 2011 +0200

    KVM: PPC: Use HIOR setting for -M pseries with PR KVM
    
    When running with PR KVM, we need to set HIOR directly. Thankfully there
    is now a new interface to set registers individually so we can just use that
    and poke HIOR into the guest vcpu's HIOR register.
    
    While at it, this also sets SDR1 because -M pseries requires it to run.
    
    With this patch, -M pseries works properly with PR KVM.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index 35a6f10..75832d8 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -705,10 +705,11 @@ int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len)
 
 void kvmppc_set_papr(CPUState *env)
 {
-    struct kvm_enable_cap cap;
+    struct kvm_enable_cap cap = {};
+    struct kvm_one_reg reg = {};
+    struct kvm_sregs sregs = {};
     int ret;
 
-    memset(&cap, 0, sizeof(cap));
     cap.cap = KVM_CAP_PPC_PAPR;
     ret = kvm_vcpu_ioctl(env, KVM_ENABLE_CAP, &cap);
 
@@ -723,7 +724,25 @@ void kvmppc_set_papr(CPUState *env)
      *     Once we have qdev CPUs, move HIOR to a qdev property and
      *     remove this chunk.
      */
-    /* XXX Set HIOR using new ioctl */
+    reg.id = KVM_ONE_REG_PPC_HIOR;
+    reg.u.reg64 = env->spr[SPR_HIOR];
+    ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, &reg);
+    if (ret) {
+        goto fail;
+    }
+
+    /* Set SDR1 so kernel space finds the HTAB */
+    ret = kvm_vcpu_ioctl(env, KVM_GET_SREGS, &sregs);
+    if (ret) {
+        goto fail;
+    }
+
+    sregs.u.s.sdr1 = env->spr[SPR_SDR1];
+
+    ret = kvm_vcpu_ioctl(env, KVM_SET_SREGS, &sregs);
+    if (ret) {
+        goto fail;
+    }
 
     return;
 
commit 9d4e4f8cbc29a4d684268f16542c8e5431530113
Author: Alexander Graf <agraf at suse.de>
Date:   Wed Sep 14 10:51:29 2011 +0200

    KVM: Update kernel headers
    
    Update HIOR and generic register get/set.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h
index 25964ee..fb3fddc 100644
--- a/linux-headers/asm-powerpc/kvm.h
+++ b/linux-headers/asm-powerpc/kvm.h
@@ -327,4 +327,6 @@ struct kvm_book3e_206_tlb_params {
 	__u32 reserved[8];
 };
 
+#define KVM_ONE_REG_PPC_HIOR	KVM_ONE_REG_PPC | 0x100
+
 #endif /* __LINUX_KVM_POWERPC_H */
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index 6f5095c..a8761d3 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -554,8 +554,10 @@ struct kvm_ppc_pvinfo {
 #define KVM_CAP_PPC_SMT 64
 #define KVM_CAP_PPC_RMA	65
 #define KVM_CAP_MAX_VCPUS 66       /* returns max vcpus per vm */
+#define KVM_CAP_PPC_HIOR 67
 #define KVM_CAP_PPC_PAPR 68
 #define KVM_CAP_SW_TLB 69
+#define KVM_CAP_ONE_REG 70
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -650,6 +652,34 @@ struct kvm_dirty_tlb {
 	__u32 num_dirty;
 };
 
+/* Available with KVM_CAP_ONE_REG */
+
+#define KVM_ONE_REG_GENERIC		0x0000000000000000ULL
+
+/*
+ * Architecture specific registers are to be defined in arch headers and
+ * ORed with the arch identifier.
+ */
+#define KVM_ONE_REG_PPC			0x1000000000000000ULL
+#define KVM_ONE_REG_X86			0x2000000000000000ULL
+#define KVM_ONE_REG_IA64		0x3000000000000000ULL
+#define KVM_ONE_REG_ARM			0x4000000000000000ULL
+#define KVM_ONE_REG_S390		0x5000000000000000ULL
+
+struct kvm_one_reg {
+	__u64 id;
+	union {
+		__u8 reg8;
+		__u16 reg16;
+		__u32 reg32;
+		__u64 reg64;
+		__u8 reg128[16];
+		__u8 reg256[32];
+		__u8 reg512[64];
+		__u8 reg1024[128];
+	} u;
+};
+
 /*
  * ioctls for VM fds
  */
@@ -778,6 +808,9 @@ struct kvm_dirty_tlb {
 #define KVM_ALLOCATE_RMA	  _IOR(KVMIO,  0xa9, struct kvm_allocate_rma)
 /* Available with KVM_CAP_SW_TLB */
 #define KVM_DIRTY_TLB		  _IOW(KVMIO,  0xaa, struct kvm_dirty_tlb)
+/* Available with KVM_CAP_ONE_REG */
+#define KVM_GET_ONE_REG		  _IOWR(KVMIO, 0xab, struct kvm_one_reg)
+#define KVM_SET_ONE_REG		  _IOW(KVMIO,  0xac, struct kvm_one_reg)
 
 #define KVM_DEV_ASSIGN_ENABLE_IOMMU	(1 << 0)
 
commit d38f674c446ca55cc8a62a993ba00c99be8742e7
Author: Alexander Graf <agraf at suse.de>
Date:   Wed Sep 14 10:26:26 2011 +0200

    KVM: Update kernel headers
    
    Removes ABI-breaking HIOR parts - KVM patch to follow.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h
index 28eecf0..25964ee 100644
--- a/linux-headers/asm-powerpc/kvm.h
+++ b/linux-headers/asm-powerpc/kvm.h
@@ -149,12 +149,6 @@ struct kvm_regs {
 #define KVM_SREGS_E_UPDATE_DBSR		(1 << 3)
 
 /*
- * Book3S special bits to indicate contents in the struct by maintaining
- * backwards compatibility with older structs. If adding a new field,
- * please make sure to add a flag for that new field */
-#define KVM_SREGS_S_HIOR		(1 << 0)
-
-/*
  * In KVM_SET_SREGS, reserved/pad fields must be left untouched from a
  * previous KVM_GET_REGS.
  *
@@ -179,8 +173,6 @@ struct kvm_sregs {
 				__u64 ibat[8];
 				__u64 dbat[8];
 			} ppc32;
-			__u64 flags; /* KVM_SREGS_S_ */
-			__u64 hior;
 		} s;
 		struct {
 			union {
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index 8bb6cde..6f5095c 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -554,7 +554,6 @@ struct kvm_ppc_pvinfo {
 #define KVM_CAP_PPC_SMT 64
 #define KVM_CAP_PPC_RMA	65
 #define KVM_CAP_MAX_VCPUS 66       /* returns max vcpus per vm */
-#define KVM_CAP_PPC_HIOR 67
 #define KVM_CAP_PPC_PAPR 68
 #define KVM_CAP_SW_TLB 69
 
commit 0157644c7b0bce8f3169bb17ca588ad1e8039fe2
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Sep 13 10:41:23 2011 +0200

    PPC: Fix heathrow PIC to use little endian MMIO
    
    During the memory API conversion, the indication on little endianness of
    MMIO for the heathrow PIC got dropped. This patch adds it back again.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/heathrow_pic.c b/hw/heathrow_pic.c
index 51996ab..16f48d1 100644
--- a/hw/heathrow_pic.c
+++ b/hw/heathrow_pic.c
@@ -126,7 +126,7 @@ static uint64_t pic_read(void *opaque, target_phys_addr_t addr,
 static const MemoryRegionOps heathrow_pic_ops = {
     .read = pic_read,
     .write = pic_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
 static void heathrow_pic_set_irq(void *opaque, int num, int level)
commit ea0a7eb4603d5929d25ac32e27d2e318b5cea910
Author: Alexander Graf <agraf at suse.de>
Date:   Thu Sep 8 18:51:17 2011 +0200

    PPC: Fix via-cuda memory registration
    
    Commit 23c5e4ca (convert to memory API) broke the VIA Cuda emulation layer
    by not registering the IO structs.
    
    This patch registers them properly and thus makes -M g3beige and -M mac99
    work again.
    
    Tested-by: Andreas Färber <andreas.faerber at web.de>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/cuda.c b/hw/cuda.c
index 6f05975..4077436 100644
--- a/hw/cuda.c
+++ b/hw/cuda.c
@@ -634,16 +634,20 @@ static uint32_t cuda_readl (void *opaque, target_phys_addr_t addr)
     return 0;
 }
 
-static CPUWriteMemoryFunc * const cuda_write[] = {
-    &cuda_writeb,
-    &cuda_writew,
-    &cuda_writel,
-};
-
-static CPUReadMemoryFunc * const cuda_read[] = {
-    &cuda_readb,
-    &cuda_readw,
-    &cuda_readl,
+static MemoryRegionOps cuda_ops = {
+    .old_mmio = {
+        .write = {
+            cuda_writeb,
+            cuda_writew,
+            cuda_writel,
+        },
+        .read = {
+            cuda_readb,
+            cuda_readw,
+            cuda_readl,
+        },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static bool cuda_timer_exist(void *opaque, int version_id)
@@ -740,8 +744,8 @@ void cuda_init (MemoryRegion **cuda_mem, qemu_irq irq)
     s->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET;
 
     s->adb_poll_timer = qemu_new_timer_ns(vm_clock, cuda_adb_poll, s);
-    cpu_register_io_memory(cuda_read, cuda_write, s,
-                                             DEVICE_NATIVE_ENDIAN);
+    memory_region_init_io(&s->mem, &cuda_ops, s, "cuda", 0x2000);
+
     *cuda_mem = &s->mem;
     vmstate_register(NULL, -1, &vmstate_cuda, s);
     qemu_register_reset(cuda_reset, s);
commit 7a880d9352575c70bae6fb246436c513ff5fe418
Author: Laurent Vivier <laurent at vivier.eu>
Date:   Sun Sep 4 08:41:15 2011 +0000

    ppc: move ADB stuff from ppc_mac.h to adb.h
    
    Allow to use ADB in non-ppc macintosh
    
    Signed-off-by: Laurent Vivier <laurent at vivier.eu>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/adb.c b/hw/adb.c
index 8dedbf8..aa15f55 100644
--- a/hw/adb.c
+++ b/hw/adb.c
@@ -22,7 +22,7 @@
  * THE SOFTWARE.
  */
 #include "hw.h"
-#include "ppc_mac.h"
+#include "adb.h"
 #include "console.h"
 
 /* debug ADB */
diff --git a/hw/adb.h b/hw/adb.h
new file mode 100644
index 0000000..b2a591c
--- /dev/null
+++ b/hw/adb.h
@@ -0,0 +1,67 @@
+/*
+ * QEMU ADB emulation shared definitions and prototypes
+ *
+ * Copyright (c) 2004-2007 Fabrice Bellard
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#if !defined(__ADB_H__)
+#define __ADB_H__
+
+#define MAX_ADB_DEVICES 16
+
+#define ADB_MAX_OUT_LEN 16
+
+typedef struct ADBDevice ADBDevice;
+
+/* buf = NULL means polling */
+typedef int ADBDeviceRequest(ADBDevice *d, uint8_t *buf_out,
+                              const uint8_t *buf, int len);
+typedef int ADBDeviceReset(ADBDevice *d);
+
+struct ADBDevice {
+    struct ADBBusState *bus;
+    int devaddr;
+    int handler;
+    ADBDeviceRequest *devreq;
+    ADBDeviceReset *devreset;
+    void *opaque;
+};
+
+typedef struct ADBBusState {
+    ADBDevice devices[MAX_ADB_DEVICES];
+    int nb_devices;
+    int poll_index;
+} ADBBusState;
+
+int adb_request(ADBBusState *s, uint8_t *buf_out,
+                const uint8_t *buf, int len);
+int adb_poll(ADBBusState *s, uint8_t *buf_out);
+
+ADBDevice *adb_register_device(ADBBusState *s, int devaddr,
+                               ADBDeviceRequest *devreq,
+                               ADBDeviceReset *devreset,
+                               void *opaque);
+void adb_kbd_init(ADBBusState *bus);
+void adb_mouse_init(ADBBusState *bus);
+
+extern ADBBusState adb_bus;
+#endif /* !defined(__ADB_H__) */
diff --git a/hw/cuda.c b/hw/cuda.c
index 5c92d81..6f05975 100644
--- a/hw/cuda.c
+++ b/hw/cuda.c
@@ -24,6 +24,7 @@
  */
 #include "hw.h"
 #include "ppc_mac.h"
+#include "adb.h"
 #include "qemu-timer.h"
 #include "sysemu.h"
 
diff --git a/hw/ppc_mac.h b/hw/ppc_mac.h
index 7351bb6..af75e45 100644
--- a/hw/ppc_mac.h
+++ b/hw/ppc_mac.h
@@ -77,46 +77,4 @@ void macio_nvram_setup_bar(MacIONVRAMState *s, MemoryRegion *bar,
 void pmac_format_nvram_partition (MacIONVRAMState *nvr, int len);
 uint32_t macio_nvram_read (void *opaque, uint32_t addr);
 void macio_nvram_write (void *opaque, uint32_t addr, uint32_t val);
-
-/* adb.c */
-
-#define MAX_ADB_DEVICES 16
-
-#define ADB_MAX_OUT_LEN 16
-
-typedef struct ADBDevice ADBDevice;
-
-/* buf = NULL means polling */
-typedef int ADBDeviceRequest(ADBDevice *d, uint8_t *buf_out,
-                              const uint8_t *buf, int len);
-typedef int ADBDeviceReset(ADBDevice *d);
-
-struct ADBDevice {
-    struct ADBBusState *bus;
-    int devaddr;
-    int handler;
-    ADBDeviceRequest *devreq;
-    ADBDeviceReset *devreset;
-    void *opaque;
-};
-
-typedef struct ADBBusState {
-    ADBDevice devices[MAX_ADB_DEVICES];
-    int nb_devices;
-    int poll_index;
-} ADBBusState;
-
-int adb_request(ADBBusState *s, uint8_t *buf_out,
-                const uint8_t *buf, int len);
-int adb_poll(ADBBusState *s, uint8_t *buf_out);
-
-ADBDevice *adb_register_device(ADBBusState *s, int devaddr,
-                               ADBDeviceRequest *devreq,
-                               ADBDeviceReset *devreset,
-                               void *opaque);
-void adb_kbd_init(ADBBusState *bus);
-void adb_mouse_init(ADBBusState *bus);
-
-extern ADBBusState adb_bus;
-
 #endif /* !defined(__PPC_MAC_H__) */
diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c
index b1cc3d7..b9a50db 100644
--- a/hw/ppc_newworld.c
+++ b/hw/ppc_newworld.c
@@ -49,6 +49,7 @@
 #include "hw.h"
 #include "ppc.h"
 #include "ppc_mac.h"
+#include "adb.h"
 #include "mac_dbdma.h"
 #include "nvram.h"
 #include "pc.h"
diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c
index fa2c1e7..ebcaafa 100644
--- a/hw/ppc_oldworld.c
+++ b/hw/ppc_oldworld.c
@@ -26,6 +26,7 @@
 #include "hw.h"
 #include "ppc.h"
 #include "ppc_mac.h"
+#include "adb.h"
 #include "mac_dbdma.h"
 #include "nvram.h"
 #include "pc.h"
commit 11de8b716665f1f6d5e586c62411f47ae539c0dc
Author: Alexander Graf <agraf at suse.de>
Date:   Wed Sep 7 13:47:22 2011 +0200

    openpic: Unfold write_IRQreg
    
    The helper function write_IRQreg was always called with a specific argument on
    the type of register to access. Inside the function we were simply doing a
    switch on that constant argument again. It's a lot easier to just unfold this
    into two separate functions and call each individually.
    
    Reported-by: Blue Swirl <blauwirbel at gmail.com>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/openpic.c b/hw/openpic.c
index fbd8837..43b8f27 100644
--- a/hw/openpic.c
+++ b/hw/openpic.c
@@ -482,30 +482,25 @@ static inline uint32_t read_IRQreg_ipvp(openpic_t *opp, int n_IRQ)
     return opp->src[n_IRQ].ipvp;
 }
 
-static inline void write_IRQreg (openpic_t *opp, int n_IRQ,
-                                 uint32_t reg, uint32_t val)
+static inline void write_IRQreg_ide(openpic_t *opp, int n_IRQ, uint32_t val)
 {
     uint32_t tmp;
 
-    switch (reg) {
-    case IRQ_IPVP:
-        /* NOTE: not fully accurate for special IRQs, but simple and
-           sufficient */
-        /* ACTIVITY bit is read-only */
-        opp->src[n_IRQ].ipvp =
-            (opp->src[n_IRQ].ipvp & 0x40000000) |
-            (val & 0x800F00FF);
-        openpic_update_irq(opp, n_IRQ);
-        DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n",
-                n_IRQ, val, opp->src[n_IRQ].ipvp);
-        break;
-    case IRQ_IDE:
-        tmp = val & 0xC0000000;
-        tmp |= val & ((1ULL << MAX_CPU) - 1);
-        opp->src[n_IRQ].ide = tmp;
-        DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide);
-        break;
-    }
+    tmp = val & 0xC0000000;
+    tmp |= val & ((1ULL << MAX_CPU) - 1);
+    opp->src[n_IRQ].ide = tmp;
+    DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide);
+}
+
+static inline void write_IRQreg_ipvp(openpic_t *opp, int n_IRQ, uint32_t val)
+{
+    /* NOTE: not fully accurate for special IRQs, but simple and sufficient */
+    /* ACTIVITY bit is read-only */
+    opp->src[n_IRQ].ipvp = (opp->src[n_IRQ].ipvp & 0x40000000)
+                         | (val & 0x800F00FF);
+    openpic_update_irq(opp, n_IRQ);
+    DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n", n_IRQ, val,
+            opp->src[n_IRQ].ipvp);
 }
 
 #if 0 // Code provision for Intel model
@@ -535,10 +530,10 @@ static void write_doorbell_register (penpic_t *opp, int n_dbl,
 {
     switch (offset) {
     case DBL_IVPR_OFFSET:
-        write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP, value);
+        write_IRQreg_ipvp(opp, IRQ_DBL0 + n_dbl, value);
         break;
     case DBL_IDE_OFFSET:
-        write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE, value);
+        write_IRQreg_ide(opp, IRQ_DBL0 + n_dbl, value);
         break;
     case DBL_DMR_OFFSET:
         opp->doorbells[n_dbl].dmr = value;
@@ -576,10 +571,10 @@ static void write_mailbox_register (openpic_t *opp, int n_mbx,
         opp->mailboxes[n_mbx].mbr = value;
         break;
     case MBX_IVPR_OFFSET:
-        write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP, value);
+        write_IRQreg_ipvp(opp, IRQ_MBX0 + n_mbx, value);
         break;
     case MBX_DMR_OFFSET:
-        write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE, value);
+        write_IRQreg_ide(opp, IRQ_MBX0 + n_mbx, value);
         break;
     }
 }
@@ -636,7 +631,7 @@ static void openpic_gbl_write (void *opaque, target_phys_addr_t addr, uint32_t v
         {
             int idx;
             idx = (addr - 0x10A0) >> 4;
-            write_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IPVP, val);
+            write_IRQreg_ipvp(opp, opp->irq_ipi0 + idx, val);
         }
         break;
     case 0x10E0: /* SPVE */
@@ -729,10 +724,10 @@ static void openpic_timer_write (void *opaque, uint32_t addr, uint32_t val)
         opp->timers[idx].tibc = val;
         break;
     case 0x20: /* TIVP */
-        write_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IPVP, val);
+        write_IRQreg_ipvp(opp, opp->irq_tim0 + idx, val);
         break;
     case 0x30: /* TIDE */
-        write_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IDE, val);
+        write_IRQreg_ide(opp, opp->irq_tim0 + idx, val);
         break;
     }
 }
@@ -782,10 +777,10 @@ static void openpic_src_write (void *opaque, uint32_t addr, uint32_t val)
     idx = addr >> 5;
     if (addr & 0x10) {
         /* EXDE / IFEDE / IEEDE */
-        write_IRQreg(opp, idx, IRQ_IDE, val);
+        write_IRQreg_ide(opp, idx, val);
     } else {
         /* EXVP / IFEVP / IEEVP */
-        write_IRQreg(opp, idx, IRQ_IPVP, val);
+        write_IRQreg_ipvp(opp, idx, val);
     }
 }
 
@@ -835,8 +830,8 @@ static void openpic_cpu_write_internal(void *opaque, target_phys_addr_t addr,
     case 0x70:
         idx = (addr - 0x40) >> 4;
         /* we use IDE as mask which CPUs to deliver the IPI to still. */
-        write_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IDE,
-                     opp->src[opp->irq_ipi0 + idx].ide | val);
+        write_IRQreg_ide(opp, opp->irq_ipi0 + idx,
+                         opp->src[opp->irq_ipi0 + idx].ide | val);
         openpic_set_irq(opp, opp->irq_ipi0 + idx, 1);
         openpic_set_irq(opp, opp->irq_ipi0 + idx, 0);
         break;
@@ -1330,13 +1325,13 @@ static void mpic_timer_write (void *opaque, target_phys_addr_t addr, uint32_t va
         mpp->timers[idx].tibc = val;
         break;
     case 0x20: /* GTIVPR */
-        write_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IPVP, val);
+        write_IRQreg_ipvp(mpp, MPIC_TMR_IRQ + idx, val);
         break;
     case 0x30: /* GTIDR & TFRR */
         if ((addr & 0xF0) == 0xF0)
             mpp->dst[cpu].tfrr = val;
         else
-            write_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IDE, val);
+            write_IRQreg_ide(mpp, MPIC_TMR_IRQ + idx, val);
         break;
     }
 }
@@ -1391,10 +1386,10 @@ static void mpic_src_ext_write (void *opaque, target_phys_addr_t addr,
         idx += (addr & 0xFFF0) >> 5;
         if (addr & 0x10) {
             /* EXDE / IFEDE / IEEDE */
-            write_IRQreg(mpp, idx, IRQ_IDE, val);
+            write_IRQreg_ide(mpp, idx, val);
         } else {
             /* EXVP / IFEVP / IEEVP */
-            write_IRQreg(mpp, idx, IRQ_IPVP, val);
+            write_IRQreg_ipvp(mpp, idx, val);
         }
     }
 }
@@ -1441,10 +1436,10 @@ static void mpic_src_int_write (void *opaque, target_phys_addr_t addr,
         idx += (addr & 0xFFF0) >> 5;
         if (addr & 0x10) {
             /* EXDE / IFEDE / IEEDE */
-            write_IRQreg(mpp, idx, IRQ_IDE, val);
+            write_IRQreg_ide(mpp, idx, val);
         } else {
             /* EXVP / IFEVP / IEEVP */
-            write_IRQreg(mpp, idx, IRQ_IPVP, val);
+            write_IRQreg_ipvp(mpp, idx, val);
         }
     }
 }
@@ -1491,10 +1486,10 @@ static void mpic_src_msg_write (void *opaque, target_phys_addr_t addr,
         idx += (addr & 0xFFF0) >> 5;
         if (addr & 0x10) {
             /* EXDE / IFEDE / IEEDE */
-            write_IRQreg(mpp, idx, IRQ_IDE, val);
+            write_IRQreg_ide(mpp, idx, val);
         } else {
             /* EXVP / IFEVP / IEEVP */
-            write_IRQreg(mpp, idx, IRQ_IPVP, val);
+            write_IRQreg_ipvp(mpp, idx, val);
         }
     }
 }
@@ -1541,10 +1536,10 @@ static void mpic_src_msi_write (void *opaque, target_phys_addr_t addr,
         idx += (addr & 0xFFF0) >> 5;
         if (addr & 0x10) {
             /* EXDE / IFEDE / IEEDE */
-            write_IRQreg(mpp, idx, IRQ_IDE, val);
+            write_IRQreg_ide(mpp, idx, val);
         } else {
             /* EXVP / IFEVP / IEEVP */
-            write_IRQreg(mpp, idx, IRQ_IPVP, val);
+            write_IRQreg_ipvp(mpp, idx, val);
         }
     }
 }
commit 8d3a8c1e77b0485d4335aa3733c550dc606ac819
Author: Alexander Graf <agraf at suse.de>
Date:   Wed Sep 7 13:41:54 2011 +0200

    openpic: Unfold read_IRQreg
    
    The helper function read_IRQreg was always called with a specific argument on
    the type of register to access. Inside the function we were simply doing a
    switch on that constant argument again. It's a lot easier to just unfold this
    into two separate functions and call each individually.
    
    Reported-by: Blue Swirl <blauwirbel at gmail.com>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/openpic.c b/hw/openpic.c
index 03e442b..fbd8837 100644
--- a/hw/openpic.c
+++ b/hw/openpic.c
@@ -472,20 +472,14 @@ static void openpic_reset (void *opaque)
     opp->glbc = 0x00000000;
 }
 
-static inline uint32_t read_IRQreg (openpic_t *opp, int n_IRQ, uint32_t reg)
+static inline uint32_t read_IRQreg_ide(openpic_t *opp, int n_IRQ)
 {
-    uint32_t retval;
-
-    switch (reg) {
-    case IRQ_IPVP:
-        retval = opp->src[n_IRQ].ipvp;
-        break;
-    case IRQ_IDE:
-        retval = opp->src[n_IRQ].ide;
-        break;
-    }
+    return opp->src[n_IRQ].ide;
+}
 
-    return retval;
+static inline uint32_t read_IRQreg_ipvp(openpic_t *opp, int n_IRQ)
+{
+    return opp->src[n_IRQ].ipvp;
 }
 
 static inline void write_IRQreg (openpic_t *opp, int n_IRQ,
@@ -523,10 +517,10 @@ static uint32_t read_doorbell_register (openpic_t *opp,
 
     switch (offset) {
     case DBL_IPVP_OFFSET:
-        retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP);
+        retval = read_IRQreg_ipvp(opp, IRQ_DBL0 + n_dbl);
         break;
     case DBL_IDE_OFFSET:
-        retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE);
+        retval = read_IRQreg_ide(opp, IRQ_DBL0 + n_dbl);
         break;
     case DBL_DMR_OFFSET:
         retval = opp->doorbells[n_dbl].dmr;
@@ -564,10 +558,10 @@ static uint32_t read_mailbox_register (openpic_t *opp,
         retval = opp->mailboxes[n_mbx].mbr;
         break;
     case MBX_IVPR_OFFSET:
-        retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP);
+        retval = read_IRQreg_ipvp(opp, IRQ_MBX0 + n_mbx);
         break;
     case MBX_DMR_OFFSET:
-        retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE);
+        retval = read_IRQreg_ide(opp, IRQ_MBX0 + n_mbx);
         break;
     }
 
@@ -695,7 +689,7 @@ static uint32_t openpic_gbl_read (void *opaque, target_phys_addr_t addr)
         {
             int idx;
             idx = (addr - 0x10A0) >> 4;
-            retval = read_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IPVP);
+            retval = read_IRQreg_ipvp(opp, opp->irq_ipi0 + idx);
         }
         break;
     case 0x10E0: /* SPVE */
@@ -765,10 +759,10 @@ static uint32_t openpic_timer_read (void *opaque, uint32_t addr)
         retval = opp->timers[idx].tibc;
         break;
     case 0x20: /* TIPV */
-        retval = read_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IPVP);
+        retval = read_IRQreg_ipvp(opp, opp->irq_tim0 + idx);
         break;
     case 0x30: /* TIDE */
-        retval = read_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IDE);
+        retval = read_IRQreg_ide(opp, opp->irq_tim0 + idx);
         break;
     }
     DPRINTF("%s: => %08x\n", __func__, retval);
@@ -809,10 +803,10 @@ static uint32_t openpic_src_read (void *opaque, uint32_t addr)
     idx = addr >> 5;
     if (addr & 0x10) {
         /* EXDE / IFEDE / IEEDE */
-        retval = read_IRQreg(opp, idx, IRQ_IDE);
+        retval = read_IRQreg_ide(opp, idx);
     } else {
         /* EXVP / IFEVP / IEEVP */
-        retval = read_IRQreg(opp, idx, IRQ_IPVP);
+        retval = read_IRQreg_ipvp(opp, idx);
     }
     DPRINTF("%s: => %08x\n", __func__, retval);
 
@@ -1368,13 +1362,13 @@ static uint32_t mpic_timer_read (void *opaque, target_phys_addr_t addr)
         retval = mpp->timers[idx].tibc;
         break;
     case 0x20: /* TIPV */
-        retval = read_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IPVP);
+        retval = read_IRQreg_ipvp(mpp, MPIC_TMR_IRQ + idx);
         break;
     case 0x30: /* TIDR */
         if ((addr &0xF0) == 0XF0)
             retval = mpp->dst[cpu].tfrr;
         else
-            retval = read_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IDE);
+            retval = read_IRQreg_ide(mpp, MPIC_TMR_IRQ + idx);
         break;
     }
     DPRINTF("%s: => %08x\n", __func__, retval);
@@ -1421,10 +1415,10 @@ static uint32_t mpic_src_ext_read (void *opaque, target_phys_addr_t addr)
         idx += (addr & 0xFFF0) >> 5;
         if (addr & 0x10) {
             /* EXDE / IFEDE / IEEDE */
-            retval = read_IRQreg(mpp, idx, IRQ_IDE);
+            retval = read_IRQreg_ide(mpp, idx);
         } else {
             /* EXVP / IFEVP / IEEVP */
-            retval = read_IRQreg(mpp, idx, IRQ_IPVP);
+            retval = read_IRQreg_ipvp(mpp, idx);
         }
         DPRINTF("%s: => %08x\n", __func__, retval);
     }
@@ -1471,10 +1465,10 @@ static uint32_t mpic_src_int_read (void *opaque, target_phys_addr_t addr)
         idx += (addr & 0xFFF0) >> 5;
         if (addr & 0x10) {
             /* EXDE / IFEDE / IEEDE */
-            retval = read_IRQreg(mpp, idx, IRQ_IDE);
+            retval = read_IRQreg_ide(mpp, idx);
         } else {
             /* EXVP / IFEVP / IEEVP */
-            retval = read_IRQreg(mpp, idx, IRQ_IPVP);
+            retval = read_IRQreg_ipvp(mpp, idx);
         }
         DPRINTF("%s: => %08x\n", __func__, retval);
     }
@@ -1521,10 +1515,10 @@ static uint32_t mpic_src_msg_read (void *opaque, target_phys_addr_t addr)
         idx += (addr & 0xFFF0) >> 5;
         if (addr & 0x10) {
             /* EXDE / IFEDE / IEEDE */
-            retval = read_IRQreg(mpp, idx, IRQ_IDE);
+            retval = read_IRQreg_ide(mpp, idx);
         } else {
             /* EXVP / IFEVP / IEEVP */
-            retval = read_IRQreg(mpp, idx, IRQ_IPVP);
+            retval = read_IRQreg_ipvp(mpp, idx);
         }
         DPRINTF("%s: => %08x\n", __func__, retval);
     }
@@ -1570,10 +1564,10 @@ static uint32_t mpic_src_msi_read (void *opaque, target_phys_addr_t addr)
         idx += (addr & 0xFFF0) >> 5;
         if (addr & 0x10) {
             /* EXDE / IFEDE / IEEDE */
-            retval = read_IRQreg(mpp, idx, IRQ_IDE);
+            retval = read_IRQreg_ide(mpp, idx);
         } else {
             /* EXVP / IFEVP / IEEVP */
-            retval = read_IRQreg(mpp, idx, IRQ_IPVP);
+            retval = read_IRQreg_ipvp(mpp, idx);
         }
         DPRINTF("%s: => %08x\n", __func__, retval);
     }
commit e5697f20a262e1fbfd8288950d043f359dc19f60
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Mon Sep 5 03:02:29 2011 +0000

    ppc405: use RAM_ADDR_FMT instead of %08lx
    
    The RAM_ADDR_FMT macro hides the type of ram_addr_t so that format
    strings can be safely used.  Make sure to use RAM_ADDR_FMT so that the
    build works on 32-bit hosts with Xen enabled.  Whether Xen should affect
    ppc TCG targets is questionable but a separate issue.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c
index e6c8ac6..712a6be 100644
--- a/hw/ppc405_boards.c
+++ b/hw/ppc405_boards.c
@@ -213,7 +213,8 @@ static void ref405ep_init (ram_addr_t ram_size,
     sram_size = 512 * 1024;
     sram_offset = qemu_ram_alloc(NULL, "ef405ep.sram", sram_size);
 #ifdef DEBUG_BOARD_INIT
-    printf("%s: register SRAM at offset %08lx\n", __func__, sram_offset);
+    printf("%s: register SRAM at offset " RAM_ADDR_FMT "\n",
+           __func__, sram_offset);
 #endif
     cpu_register_physical_memory(0xFFF00000, sram_size,
                                  sram_offset | IO_MEM_RAM);
@@ -357,7 +358,7 @@ static void ref405ep_init (ram_addr_t ram_size,
 #ifdef DEBUG_BOARD_INIT
     printf("%s: Done\n", __func__);
 #endif
-    printf("bdloc %016lx\n", (unsigned long)bdloc);
+    printf("bdloc " RAM_ADDR_FMT "\n", bdloc);
 }
 
 static QEMUMachine ref405ep_machine = {
commit 5a576fb3e20c3087a6d30be5a94550ace003c6d7
Author: Fabien Chouteau <chouteau at adacore.com>
Date:   Thu Sep 1 04:56:00 2011 +0000

    Gdbstub: handle read of fpscr
    
    Signed-off-by: Fabien Chouteau <chouteau at adacore.com>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/gdbstub.c b/gdbstub.c
index 12dd100..1d99e19 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -733,7 +733,7 @@ static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
             {
                 if (gdb_has_xml)
                     return 0;
-                GET_REG32(0); /* fpscr */
+                GET_REG32(env->fpscr);
             }
         }
     }
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 211f3bd..d09c7ca 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -9700,8 +9700,7 @@ static int gdb_get_float_reg(CPUState *env, uint8_t *mem_buf, int n)
         return 8;
     }
     if (n == 32) {
-        /* FPSCR not implemented  */
-        memset(mem_buf, 0, 4);
+        stl_p(mem_buf, env->fpscr);
         return 4;
     }
     return 0;
commit f5b6ffcf2a94337df31e801dd11b34896bd4fe2b
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Wed Aug 24 05:28:52 2011 +0000

    vscsi: send the CHECK_CONDITION status down together with autosense data
    
    I introduced this bug in commit 05751d3 (vscsi: always use get_sense,
    2011-08-03) because at the time there was no way to expose a sense
    condition to SLOF and Linux manages to work around the bug.  However,
    the bug becomes evident now that SCSI devices also report unit
    attention on reset.
    
    SLOF also has problems dealing with unit attention conditions, so
    it still will not boot even with this fix (just like OpenBIOS).
    IBM folks are aware of their part of the bug. :-)
    
    Reported-by: Thomas Huth <thuth at linux.vnet.ibm.com>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Acked-by: David Gibson <david at gibson.dropbear.id.au>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c
index 6fc82f6..e8426d7 100644
--- a/hw/spapr_vscsi.c
+++ b/hw/spapr_vscsi.c
@@ -483,7 +483,6 @@ static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status)
     if (status == CHECK_CONDITION) {
         req->senselen = scsi_req_get_sense(req->sreq, req->sense,
                                            sizeof(req->sense));
-        status = 0;
         dprintf("VSCSI: Sense data, %d bytes:\n", len);
         dprintf("       %02x  %02x  %02x  %02x  %02x  %02x  %02x  %02x\n",
                 req->sense[0], req->sense[1], req->sense[2], req->sense[3],
commit a3d0abaecaa2981ad8c0036b6caf0ff1324fa57d
Author: David Gibson <david at gibson.dropbear.id.au>
Date:   Wed Aug 31 15:50:50 2011 +0000

    pseries: Implement hcall-bulk hypervisor interface
    
    This patch adds support for the H_REMOVE_BULK hypercall on the pseries
    machine.  Strictly speaking this isn't necessarym since the kernel will
    only attempt to use this if hcall-bulk is advertised in the device tree,
    which previously it was not.
    
    Adding this support may give a marginal performance increase, but more
    importantly it reduces the differences between the emulated machine and
    an existing PowerVM or kvm system, both of which already implement
    hcall-bulk.
    
    Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/spapr.c b/hw/spapr.c
index 91953cf..deb4ae5 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -75,7 +75,7 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
     uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
     uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)};
     char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt"
-        "\0hcall-tce\0hcall-vio\0hcall-splpar";
+        "\0hcall-tce\0hcall-vio\0hcall-splpar\0hcall-bulk";
     uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
     int i;
     char *modelname;
diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c
index 0c61c10..84281be 100644
--- a/hw/spapr_hcall.c
+++ b/hw/spapr_hcall.c
@@ -174,20 +174,26 @@ static target_ulong h_enter(CPUState *env, sPAPREnvironment *spapr,
     return H_SUCCESS;
 }
 
-static target_ulong h_remove(CPUState *env, sPAPREnvironment *spapr,
-                             target_ulong opcode, target_ulong *args)
+enum {
+    REMOVE_SUCCESS = 0,
+    REMOVE_NOT_FOUND = 1,
+    REMOVE_PARM = 2,
+    REMOVE_HW = 3,
+};
+
+static target_ulong remove_hpte(CPUState *env, target_ulong ptex,
+                                target_ulong avpn,
+                                target_ulong flags,
+                                target_ulong *vp, target_ulong *rp)
 {
-    target_ulong flags = args[0];
-    target_ulong pte_index = args[1];
-    target_ulong avpn = args[2];
     uint8_t *hpte;
     target_ulong v, r, rb;
 
-    if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
-        return H_PARAMETER;
+    if ((ptex * HASH_PTE_SIZE_64) & ~env->htab_mask) {
+        return REMOVE_PARM;
     }
 
-    hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
+    hpte = env->external_htab + (ptex * HASH_PTE_SIZE_64);
     while (!lock_hpte(hpte, HPTE_V_HVLOCK)) {
         /* We have no real concurrency in qemu soft-emulation, so we
          * will never actually have a contested lock */
@@ -202,14 +208,106 @@ static target_ulong h_remove(CPUState *env, sPAPREnvironment *spapr,
         ((flags & H_ANDCOND) && (v & avpn) != 0)) {
         stq_p(hpte, v & ~HPTE_V_HVLOCK);
         assert(!(ldq_p(hpte) & HPTE_V_HVLOCK));
-        return H_NOT_FOUND;
+        return REMOVE_NOT_FOUND;
     }
-    args[0] = v & ~HPTE_V_HVLOCK;
-    args[1] = r;
+    *vp = v & ~HPTE_V_HVLOCK;
+    *rp = r;
     stq_p(hpte, 0);
-    rb = compute_tlbie_rb(v, r, pte_index);
+    rb = compute_tlbie_rb(v, r, ptex);
     ppc_tlb_invalidate_one(env, rb);
     assert(!(ldq_p(hpte) & HPTE_V_HVLOCK));
+    return REMOVE_SUCCESS;
+}
+
+static target_ulong h_remove(CPUState *env, sPAPREnvironment *spapr,
+                             target_ulong opcode, target_ulong *args)
+{
+    target_ulong flags = args[0];
+    target_ulong pte_index = args[1];
+    target_ulong avpn = args[2];
+    int ret;
+
+    ret = remove_hpte(env, pte_index, avpn, flags,
+                      &args[0], &args[1]);
+
+    switch (ret) {
+    case REMOVE_SUCCESS:
+        return H_SUCCESS;
+
+    case REMOVE_NOT_FOUND:
+        return H_NOT_FOUND;
+
+    case REMOVE_PARM:
+        return H_PARAMETER;
+
+    case REMOVE_HW:
+        return H_HARDWARE;
+    }
+
+    assert(0);
+}
+
+#define H_BULK_REMOVE_TYPE             0xc000000000000000ULL
+#define   H_BULK_REMOVE_REQUEST        0x4000000000000000ULL
+#define   H_BULK_REMOVE_RESPONSE       0x8000000000000000ULL
+#define   H_BULK_REMOVE_END            0xc000000000000000ULL
+#define H_BULK_REMOVE_CODE             0x3000000000000000ULL
+#define   H_BULK_REMOVE_SUCCESS        0x0000000000000000ULL
+#define   H_BULK_REMOVE_NOT_FOUND      0x1000000000000000ULL
+#define   H_BULK_REMOVE_PARM           0x2000000000000000ULL
+#define   H_BULK_REMOVE_HW             0x3000000000000000ULL
+#define H_BULK_REMOVE_RC               0x0c00000000000000ULL
+#define H_BULK_REMOVE_FLAGS            0x0300000000000000ULL
+#define   H_BULK_REMOVE_ABSOLUTE       0x0000000000000000ULL
+#define   H_BULK_REMOVE_ANDCOND        0x0100000000000000ULL
+#define   H_BULK_REMOVE_AVPN           0x0200000000000000ULL
+#define H_BULK_REMOVE_PTEX             0x00ffffffffffffffULL
+
+#define H_BULK_REMOVE_MAX_BATCH        4
+
+static target_ulong h_bulk_remove(CPUState *env, sPAPREnvironment *spapr,
+                                  target_ulong opcode, target_ulong *args)
+{
+    int i;
+
+    for (i = 0; i < H_BULK_REMOVE_MAX_BATCH; i++) {
+        target_ulong *tsh = &args[i*2];
+        target_ulong tsl = args[i*2 + 1];
+        target_ulong v, r, ret;
+
+        if ((*tsh & H_BULK_REMOVE_TYPE) == H_BULK_REMOVE_END) {
+            break;
+        } else if ((*tsh & H_BULK_REMOVE_TYPE) != H_BULK_REMOVE_REQUEST) {
+            return H_PARAMETER;
+        }
+
+        *tsh &= H_BULK_REMOVE_PTEX | H_BULK_REMOVE_FLAGS;
+        *tsh |= H_BULK_REMOVE_RESPONSE;
+
+        if ((*tsh & H_BULK_REMOVE_ANDCOND) && (*tsh & H_BULK_REMOVE_AVPN)) {
+            *tsh |= H_BULK_REMOVE_PARM;
+            return H_PARAMETER;
+        }
+
+        ret = remove_hpte(env, *tsh & H_BULK_REMOVE_PTEX, tsl,
+                          (*tsh & H_BULK_REMOVE_FLAGS) >> 26,
+                          &v, &r);
+
+        *tsh |= ret << 60;
+
+        switch (ret) {
+        case REMOVE_SUCCESS:
+            *tsh |= (r & (HPTE_R_C | HPTE_R_R)) << 43;
+            break;
+
+        case REMOVE_PARM:
+            return H_PARAMETER;
+
+        case REMOVE_HW:
+            return H_HARDWARE;
+        }
+    }
+
     return H_SUCCESS;
 }
 
@@ -581,6 +679,9 @@ static void hypercall_init(void)
     spapr_register_hypercall(H_REMOVE, h_remove);
     spapr_register_hypercall(H_PROTECT, h_protect);
 
+    /* hcall-bulk */
+    spapr_register_hypercall(H_BULK_REMOVE, h_bulk_remove);
+
     /* hcall-dabr */
     spapr_register_hypercall(H_SET_DABR, h_set_dabr);
 
commit 697ab892786d47008807a49f57b2fd86adfcd098
Author: David Gibson <david at gibson.dropbear.id.au>
Date:   Wed Aug 31 15:45:10 2011 +0000

    Implement POWER7's CFAR in TCG
    
    This patch implements support for the CFAR SPR on POWER7 (Come From
    Address Register), which snapshots the PC value at the time of a branch or
    an rfid.  The latest powerpc-next kernel also catches it and can show it in
    xmon or in the signal frames.
    
    This works well enough to let recent kernels boot (which otherwise oops
    on the CFAR access).  It hasn't been tested enough to be confident that the
    CFAR values are actually accurate, but one thing at a time.
    
    Signed-off-by: Ben Herrenschmidt <benh at kernel.crashing.org>
    Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 32706df..3f4af22 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -555,6 +555,8 @@ enum {
     /* Decrementer clock: RTC clock (POWER, 601) or bus clock                */
     POWERPC_FLAG_RTC_CLK  = 0x00010000,
     POWERPC_FLAG_BUS_CLK  = 0x00020000,
+    /* Has CFAR                                                              */
+    POWERPC_FLAG_CFAR     = 0x00040000,
 };
 
 /*****************************************************************************/
@@ -872,6 +874,10 @@ struct CPUPPCState {
     target_ulong ctr;
     /* condition register */
     uint32_t crf[8];
+#if defined(TARGET_PPC64)
+    /* CFAR */
+    target_ulong cfar;
+#endif
     /* XER */
     target_ulong xer;
     /* Reservation address */
@@ -1204,6 +1210,7 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
 #define SPR_601_UDECR         (0x006)
 #define SPR_LR                (0x008)
 #define SPR_CTR               (0x009)
+#define SPR_DSCR              (0x011)
 #define SPR_DSISR             (0x012)
 #define SPR_DAR               (0x013) /* DAE for PowerPC 601 */
 #define SPR_601_RTCU          (0x014)
@@ -1212,6 +1219,7 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
 #define SPR_SDR1              (0x019)
 #define SPR_SRR0              (0x01A)
 #define SPR_SRR1              (0x01B)
+#define SPR_CFAR              (0x01C)
 #define SPR_AMR               (0x01D)
 #define SPR_BOOKE_PID         (0x030)
 #define SPR_BOOKE_DECAR       (0x036)
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 4277460..1e362fc 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -69,6 +69,9 @@ static TCGv cpu_nip;
 static TCGv cpu_msr;
 static TCGv cpu_ctr;
 static TCGv cpu_lr;
+#if defined(TARGET_PPC64)
+static TCGv cpu_cfar;
+#endif
 static TCGv cpu_xer;
 static TCGv cpu_reserve;
 static TCGv_i32 cpu_fpscr;
@@ -154,6 +157,11 @@ void ppc_translate_init(void)
     cpu_lr = tcg_global_mem_new(TCG_AREG0,
                                 offsetof(CPUState, lr), "lr");
 
+#if defined(TARGET_PPC64)
+    cpu_cfar = tcg_global_mem_new(TCG_AREG0,
+                                  offsetof(CPUState, cfar), "cfar");
+#endif
+
     cpu_xer = tcg_global_mem_new(TCG_AREG0,
                                  offsetof(CPUState, xer), "xer");
 
@@ -187,6 +195,7 @@ typedef struct DisasContext {
     int le_mode;
 #if defined(TARGET_PPC64)
     int sf_mode;
+    int has_cfar;
 #endif
     int fpu_enabled;
     int altivec_enabled;
@@ -3345,6 +3354,14 @@ static inline void gen_qemu_st32fiw(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
 /* stfiwx */
 GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX);
 
+static inline void gen_update_cfar(DisasContext *ctx, target_ulong nip)
+{
+#if defined(TARGET_PPC64)
+    if (ctx->has_cfar)
+        tcg_gen_movi_tl(cpu_cfar, nip);
+#endif
+}
+
 /***                                Branch                                 ***/
 static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
 {
@@ -3407,6 +3424,7 @@ static void gen_b(DisasContext *ctx)
         target = li;
     if (LK(ctx->opcode))
         gen_setlr(ctx, ctx->nip);
+    gen_update_cfar(ctx, ctx->nip);
     gen_goto_tb(ctx, 0, target);
 }
 
@@ -3469,6 +3487,7 @@ static inline void gen_bcond(DisasContext *ctx, int type)
         }
         tcg_temp_free_i32(temp);
     }
+    gen_update_cfar(ctx, ctx->nip);
     if (type == BCOND_IM) {
         target_ulong li = (target_long)((int16_t)(BD(ctx->opcode)));
         if (likely(AA(ctx->opcode) == 0)) {
@@ -3580,6 +3599,7 @@ static void gen_rfi(DisasContext *ctx)
         gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
         return;
     }
+    gen_update_cfar(ctx, ctx->nip);
     gen_helper_rfi();
     gen_sync_exception(ctx);
 #endif
@@ -3596,6 +3616,7 @@ static void gen_rfid(DisasContext *ctx)
         gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
         return;
     }
+    gen_update_cfar(ctx, ctx->nip);
     gen_helper_rfid();
     gen_sync_exception(ctx);
 #endif
@@ -9263,6 +9284,12 @@ void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
          */
     }
 
+#if defined(TARGET_PPC64)
+    if (env->flags & POWERPC_FLAG_CFAR) {
+        cpu_fprintf(f, " CFAR " TARGET_FMT_lx"\n", env->cfar);
+    }
+#endif
+
     switch (env->mmu_model) {
     case POWERPC_MMU_32B:
     case POWERPC_MMU_601:
@@ -9371,6 +9398,7 @@ static inline void gen_intermediate_code_internal(CPUState *env,
     ctx.le_mode = env->hflags & (1 << MSR_LE) ? 1 : 0;
 #if defined(TARGET_PPC64)
     ctx.sf_mode = msr_sf;
+    ctx.has_cfar = !!(env->flags & POWERPC_FLAG_CFAR);
 #endif
     ctx.fpu_enabled = msr_fp;
     if ((env->flags & POWERPC_FLAG_SPE) && msr_spe)
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 9ea193d..211f3bd 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -129,6 +129,19 @@ static void spr_write_lr (void *opaque, int sprn, int gprn)
     tcg_gen_mov_tl(cpu_lr, cpu_gpr[gprn]);
 }
 
+/* CFAR */
+#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
+static void spr_read_cfar (void *opaque, int gprn, int sprn)
+{
+    tcg_gen_mov_tl(cpu_gpr[gprn], cpu_cfar);
+}
+
+static void spr_write_cfar (void *opaque, int sprn, int gprn)
+{
+    tcg_gen_mov_tl(cpu_cfar, cpu_gpr[gprn]);
+}
+#endif /* defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) */
+
 /* CTR */
 static void spr_read_ctr (void *opaque, int gprn, int sprn)
 {
@@ -6489,7 +6502,7 @@ static void init_proc_970MP (CPUPPCState *env)
 #define POWERPC_BFDM_POWER7   (bfd_mach_ppc64)
 #define POWERPC_FLAG_POWER7   (POWERPC_FLAG_VRE | POWERPC_FLAG_SE |            \
                               POWERPC_FLAG_BE | POWERPC_FLAG_PMM |            \
-                              POWERPC_FLAG_BUS_CLK)
+                              POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR)
 #define check_pow_POWER7    check_pow_nocheck
 
 static void init_proc_POWER7 (CPUPPCState *env)
@@ -6508,6 +6521,14 @@ static void init_proc_POWER7 (CPUPPCState *env)
                  &spr_read_purr, SPR_NOACCESS,
                  &spr_read_purr, SPR_NOACCESS,
                  0x00000000);
+    spr_register(env, SPR_CFAR, "SPR_CFAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_cfar, &spr_write_cfar,
+                 0x00000000);
+    spr_register(env, SPR_DSCR, "SPR_DSCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
 #endif /* !CONFIG_USER_ONLY */
     /* Memory management */
     /* XXX : not implemented */
commit 2bd9543cd303d9f6cbd37b7466bb03543035156b
Author: Scott Wood <scottwood at freescale.com>
Date:   Thu Aug 18 10:38:40 2011 +0000

    ppc: booke206: use MAV=2.0 TSIZE definition, fix 4G pages
    
    This definition is backward compatible with MAV=1.0 as long as
    the guest does not set reserved bits in MAS1/MAS4.
    
    Also, fix the shift in booke206_tlb_to_page_size -- it's the base
    that should be able to hold a 4G page size, not the shift count.
    
    Signed-off-by: Scott Wood <scottwood at freescale.com>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 61151d8..8095516 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -174,7 +174,7 @@ out:
 /* Create -kernel TLB entries for BookE, linearly spanning 256MB.  */
 static inline target_phys_addr_t booke206_page_size_to_tlb(uint64_t size)
 {
-    return (ffs(size >> 10) - 1) >> 1;
+    return ffs(size >> 10) - 1;
 }
 
 static void mmubooke_create_initial_mapping(CPUState *env,
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 5200e6e..32706df 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -667,8 +667,8 @@ enum {
 #define MAS0_ATSEL_TLB     0
 #define MAS0_ATSEL_LRAT    MAS0_ATSEL
 
-#define MAS1_TSIZE_SHIFT   8
-#define MAS1_TSIZE_MASK    (0xf << MAS1_TSIZE_SHIFT)
+#define MAS1_TSIZE_SHIFT   7
+#define MAS1_TSIZE_MASK    (0x1f << MAS1_TSIZE_SHIFT)
 
 #define MAS1_TS_SHIFT      12
 #define MAS1_TS            (1 << MAS1_TS_SHIFT)
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 4b3731e..6339be3 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -1293,7 +1293,7 @@ target_phys_addr_t booke206_tlb_to_page_size(CPUState *env, ppcmas_tlb_t *tlb)
 {
     uint32_t tlbncfg;
     int tlbn = booke206_tlbm_to_tlbn(env, tlb);
-    target_phys_addr_t tlbm_size;
+    int tlbm_size;
 
     tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
 
@@ -1301,9 +1301,10 @@ target_phys_addr_t booke206_tlb_to_page_size(CPUState *env, ppcmas_tlb_t *tlb)
         tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
     } else {
         tlbm_size = (tlbncfg & TLBnCFG_MINSIZE) >> TLBnCFG_MINSIZE_SHIFT;
+        tlbm_size <<= 1;
     }
 
-    return (1 << (tlbm_size << 1)) << 10;
+    return 1024ULL << tlbm_size;
 }
 
 /* TLB check function for MAS based SoftTLBs */
commit bebabbc7aa7d1c5a45ee325838adf58a19f1b1ee
Author: Scott Wood <scottwood at freescale.com>
Date:   Thu Aug 18 10:38:42 2011 +0000

    ppc: booke206: add "info tlb" support
    
    Signed-off-by: Scott Wood <scottwood at freescale.com>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 9e1cca8..506014c 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1306,7 +1306,7 @@ show i8259 (PIC) state
 @item info pci
 show emulated PCI device info
 @item info tlb
-show virtual to physical memory mappings (i386, SH4 and SPARC only)
+show virtual to physical memory mappings (i386, SH4, SPARC, and PPC only)
 @item info mem
 show the active virtual memory mappings (i386 only)
 @item info jit
diff --git a/monitor.c b/monitor.c
index d323ea5..58e149f 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2462,7 +2462,7 @@ static void tlb_info(Monitor *mon)
 
 #endif
 
-#if defined(TARGET_SPARC)
+#if defined(TARGET_SPARC) || defined(TARGET_PPC)
 static void tlb_info(Monitor *mon)
 {
     CPUState *env1 = mon_get_cpu();
@@ -2965,7 +2965,8 @@ 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) || defined(TARGET_SPARC)
+#if defined(TARGET_I386) || defined(TARGET_SH4) || defined(TARGET_SPARC) || \
+    defined(TARGET_PPC)
     {
         .name       = "tlb",
         .args_type  = "",
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 3e7f797..5200e6e 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -2045,4 +2045,6 @@ static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
     env->nip = tb->pc;
 }
 
+void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env);
+
 #endif /* !defined (__CPU_PPC_H__) */
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 96ea464..4b3731e 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -1465,6 +1465,94 @@ found_tlb:
     return ret;
 }
 
+static const char *book3e_tsize_to_str[32] = {
+    "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K", "512K",
+    "1M", "2M", "4M", "8M", "16M", "32M", "64M", "128M", "256M", "512M",
+    "1G", "2G", "4G", "8G", "16G", "32G", "64G", "128G", "256G", "512G",
+    "1T", "2T"
+};
+
+static void mmubooke206_dump_one_tlb(FILE *f, fprintf_function cpu_fprintf,
+                                     CPUState *env, int tlbn, int offset,
+                                     int tlbsize)
+{
+    ppcmas_tlb_t *entry;
+    int i;
+
+    cpu_fprintf(f, "\nTLB%d:\n", tlbn);
+    cpu_fprintf(f, "Effective          Physical           Size TID   TS SRWX URWX WIMGE U0123\n");
+
+    entry = &env->tlb.tlbm[offset];
+    for (i = 0; i < tlbsize; i++, entry++) {
+        target_phys_addr_t ea, pa, size;
+        int tsize;
+
+        if (!(entry->mas1 & MAS1_VALID)) {
+            continue;
+        }
+
+        tsize = (entry->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
+        size = 1024ULL << tsize;
+        ea = entry->mas2 & ~(size - 1);
+        pa = entry->mas7_3 & ~(size - 1);
+
+        cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u  S%c%c%c U%c%c%c %c%c%c%c%c U%c%c%c%c\n",
+                    (uint64_t)ea, (uint64_t)pa,
+                    book3e_tsize_to_str[tsize],
+                    (entry->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT,
+                    (entry->mas1 & MAS1_TS) >> MAS1_TS_SHIFT,
+                    entry->mas7_3 & MAS3_SR ? 'R' : '-',
+                    entry->mas7_3 & MAS3_SW ? 'W' : '-',
+                    entry->mas7_3 & MAS3_SX ? 'X' : '-',
+                    entry->mas7_3 & MAS3_UR ? 'R' : '-',
+                    entry->mas7_3 & MAS3_UW ? 'W' : '-',
+                    entry->mas7_3 & MAS3_UX ? 'X' : '-',
+                    entry->mas2 & MAS2_W ? 'W' : '-',
+                    entry->mas2 & MAS2_I ? 'I' : '-',
+                    entry->mas2 & MAS2_M ? 'M' : '-',
+                    entry->mas2 & MAS2_G ? 'G' : '-',
+                    entry->mas2 & MAS2_E ? 'E' : '-',
+                    entry->mas7_3 & MAS3_U0 ? '0' : '-',
+                    entry->mas7_3 & MAS3_U1 ? '1' : '-',
+                    entry->mas7_3 & MAS3_U2 ? '2' : '-',
+                    entry->mas7_3 & MAS3_U3 ? '3' : '-');
+    }
+}
+
+static void mmubooke206_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
+                                 CPUState *env)
+{
+    int offset = 0;
+    int i;
+
+    if (kvm_enabled() && !env->kvm_sw_tlb) {
+        cpu_fprintf(f, "Cannot access KVM TLB\n");
+        return;
+    }
+
+    for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
+        int size = booke206_tlb_size(env, i);
+
+        if (size == 0) {
+            continue;
+        }
+
+        mmubooke206_dump_one_tlb(f, cpu_fprintf, env, i, offset, size);
+        offset += size;
+    }
+}
+
+void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
+{
+    switch (env->mmu_model) {
+    case POWERPC_MMU_BOOKE206:
+        mmubooke206_dump_mmu(f, cpu_fprintf, env);
+        break;
+    default:
+        cpu_fprintf(f, "%s: unimplemented\n", __func__);
+    }
+}
+
 static inline int check_physical(CPUState *env, mmu_ctx_t *ctx,
                                  target_ulong eaddr, int rw)
 {
commit 93dd5e852c043f7b86595e1bfa0b4f9a39a6acfb
Author: Scott Wood <scottwood at freescale.com>
Date:   Wed Aug 31 11:26:56 2011 +0000

    kvm: ppc: booke206: use MMU API
    
    Share the TLB array with KVM.  This allows us to set the initial TLB
    both on initial boot and reset, is useful for debugging, and could
    eventually be used to support migration.
    
    Signed-off-by: Scott Wood <scottwood at freescale.com>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index b86a008..61151d8 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -189,6 +189,8 @@ static void mmubooke_create_initial_mapping(CPUState *env,
     tlb->mas2 = va & TARGET_PAGE_MASK;
     tlb->mas7_3 = pa & TARGET_PAGE_MASK;
     tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
+
+    env->tlb_dirty = true;
 }
 
 static void mpc8544ds_cpu_reset_sec(void *opaque)
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index b8d42e0..3e7f797 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -934,6 +934,8 @@ struct CPUPPCState {
     ppc_tlb_t tlb;   /* TLB is optional. Allocate them only if needed        */
     /* 403 dedicated access protection registers */
     target_ulong pb[4];
+    bool tlb_dirty;   /* Set to non-zero when modifying TLB                  */
+    bool kvm_sw_tlb;  /* non-zero if KVM SW TLB API is active                */
 #endif
 
     /* Other registers */
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index f65b6e1..35a6f10 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -112,6 +112,52 @@ static int kvm_arch_sync_sregs(CPUState *cenv)
     return kvm_vcpu_ioctl(cenv, KVM_SET_SREGS, &sregs);
 }
 
+/* Set up a shared TLB array with KVM */
+static int kvm_booke206_tlb_init(CPUState *env)
+{
+    struct kvm_book3e_206_tlb_params params = {};
+    struct kvm_config_tlb cfg = {};
+    struct kvm_enable_cap encap = {};
+    unsigned int entries = 0;
+    int ret, i;
+
+    if (!kvm_enabled() ||
+        !kvm_check_extension(env->kvm_state, KVM_CAP_SW_TLB)) {
+        return 0;
+    }
+
+    assert(ARRAY_SIZE(params.tlb_sizes) == BOOKE206_MAX_TLBN);
+
+    for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
+        params.tlb_sizes[i] = booke206_tlb_size(env, i);
+        params.tlb_ways[i] = booke206_tlb_ways(env, i);
+        entries += params.tlb_sizes[i];
+    }
+
+    assert(entries == env->nb_tlb);
+    assert(sizeof(struct kvm_book3e_206_tlb_entry) == sizeof(ppcmas_tlb_t));
+
+    env->tlb_dirty = true;
+
+    cfg.array = (uintptr_t)env->tlb.tlbm;
+    cfg.array_len = sizeof(ppcmas_tlb_t) * entries;
+    cfg.params = (uintptr_t)&params;
+    cfg.mmu_type = KVM_MMU_FSL_BOOKE_NOHV;
+
+    encap.cap = KVM_CAP_SW_TLB;
+    encap.args[0] = (uintptr_t)&cfg;
+
+    ret = kvm_vcpu_ioctl(env, KVM_ENABLE_CAP, &encap);
+    if (ret < 0) {
+        fprintf(stderr, "%s: couldn't enable KVM_CAP_SW_TLB: %s\n",
+                __func__, strerror(-ret));
+        return ret;
+    }
+
+    env->kvm_sw_tlb = true;
+    return 0;
+}
+
 int kvm_arch_init_vcpu(CPUState *cenv)
 {
     int ret;
@@ -123,6 +169,15 @@ int kvm_arch_init_vcpu(CPUState *cenv)
 
     idle_timer = qemu_new_timer_ns(vm_clock, kvm_kick_env, cenv);
 
+    /* Some targets support access to KVM's guest TLB. */
+    switch (cenv->mmu_model) {
+    case POWERPC_MMU_BOOKE206:
+        ret = kvm_booke206_tlb_init(cenv);
+        break;
+    default:
+        break;
+    }
+
     return ret;
 }
 
@@ -130,6 +185,31 @@ void kvm_arch_reset_vcpu(CPUState *env)
 {
 }
 
+static void kvm_sw_tlb_put(CPUState *env)
+{
+    struct kvm_dirty_tlb dirty_tlb;
+    unsigned char *bitmap;
+    int ret;
+
+    if (!env->kvm_sw_tlb) {
+        return;
+    }
+
+    bitmap = g_malloc((env->nb_tlb + 7) / 8);
+    memset(bitmap, 0xFF, (env->nb_tlb + 7) / 8);
+
+    dirty_tlb.bitmap = (uintptr_t)bitmap;
+    dirty_tlb.num_dirty = env->nb_tlb;
+
+    ret = kvm_vcpu_ioctl(env, KVM_DIRTY_TLB, &dirty_tlb);
+    if (ret) {
+        fprintf(stderr, "%s: KVM_DIRTY_TLB: %s\n",
+                __func__, strerror(-ret));
+    }
+
+    g_free(bitmap);
+}
+
 int kvm_arch_put_registers(CPUState *env, int level)
 {
     struct kvm_regs regs;
@@ -167,6 +247,11 @@ int kvm_arch_put_registers(CPUState *env, int level)
     if (ret < 0)
         return ret;
 
+    if (env->tlb_dirty) {
+        kvm_sw_tlb_put(env);
+        env->tlb_dirty = false;
+    }
+
     return ret;
 }
 
commit a54fc0800e420df862acf089e638e0fa2d8c3585
Author: Alexander Graf <agraf at suse.de>
Date:   Wed Aug 31 15:13:41 2011 +0200

    KVM: Update kernel headers
    
    Another round of KVM features, another round of kernel header updates :)
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h
index 579e219..28eecf0 100644
--- a/linux-headers/asm-powerpc/kvm.h
+++ b/linux-headers/asm-powerpc/kvm.h
@@ -284,6 +284,11 @@ struct kvm_guest_debug_arch {
 #define KVM_INTERRUPT_UNSET	-2U
 #define KVM_INTERRUPT_SET_LEVEL	-3U
 
+#define KVM_CPU_440		1
+#define KVM_CPU_E500V2		2
+#define KVM_CPU_3S_32		3
+#define KVM_CPU_3S_64		4
+
 /* for KVM_CAP_SPAPR_TCE */
 struct kvm_create_spapr_tce {
 	__u64 liobn;
@@ -295,4 +300,39 @@ struct kvm_allocate_rma {
 	__u64 rma_size;
 };
 
+struct kvm_book3e_206_tlb_entry {
+	__u32 mas8;
+	__u32 mas1;
+	__u64 mas2;
+	__u64 mas7_3;
+};
+
+struct kvm_book3e_206_tlb_params {
+	/*
+	 * For mmu types KVM_MMU_FSL_BOOKE_NOHV and KVM_MMU_FSL_BOOKE_HV:
+	 *
+	 * - The number of ways of TLB0 must be a power of two between 2 and
+	 *   16.
+	 * - TLB1 must be fully associative.
+	 * - The size of TLB0 must be a multiple of the number of ways, and
+	 *   the number of sets must be a power of two.
+	 * - The size of TLB1 may not exceed 64 entries.
+	 * - TLB0 supports 4 KiB pages.
+	 * - The page sizes supported by TLB1 are as indicated by
+	 *   TLB1CFG (if MMUCFG[MAVN] = 0) or TLB1PS (if MMUCFG[MAVN] = 1)
+	 *   as returned by KVM_GET_SREGS.
+	 * - TLB2 and TLB3 are reserved, and their entries in tlb_sizes[]
+	 *   and tlb_ways[] must be zero.
+	 *
+	 * tlb_ways[n] = tlb_sizes[n] means the array is fully associative.
+	 *
+	 * KVM will adjust TLBnCFG based on the sizes configured here,
+	 * though arrays greater than 2048 entries will have TLBnCFG[NENTRY]
+	 * set to zero.
+	 */
+	__u32 tlb_sizes[4];
+	__u32 tlb_ways[4];
+	__u32 reserved[8];
+};
+
 #endif /* __LINUX_KVM_POWERPC_H */
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index 2062375..8bb6cde 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -556,6 +556,7 @@ struct kvm_ppc_pvinfo {
 #define KVM_CAP_MAX_VCPUS 66       /* returns max vcpus per vm */
 #define KVM_CAP_PPC_HIOR 67
 #define KVM_CAP_PPC_PAPR 68
+#define KVM_CAP_SW_TLB 69
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -635,6 +636,21 @@ struct kvm_clock_data {
 	__u32 pad[9];
 };
 
+#define KVM_MMU_FSL_BOOKE_NOHV		0
+#define KVM_MMU_FSL_BOOKE_HV		1
+
+struct kvm_config_tlb {
+	__u64 params;
+	__u64 array;
+	__u32 mmu_type;
+	__u32 array_len;
+};
+
+struct kvm_dirty_tlb {
+	__u64 bitmap;
+	__u32 num_dirty;
+};
+
 /*
  * ioctls for VM fds
  */
@@ -761,6 +777,8 @@ struct kvm_clock_data {
 #define KVM_CREATE_SPAPR_TCE	  _IOW(KVMIO,  0xa8, struct kvm_create_spapr_tce)
 /* Available with KVM_CAP_RMA */
 #define KVM_ALLOCATE_RMA	  _IOR(KVMIO,  0xa9, struct kvm_allocate_rma)
+/* Available with KVM_CAP_SW_TLB */
+#define KVM_DIRTY_TLB		  _IOW(KVMIO,  0xaa, struct kvm_dirty_tlb)
 
 #define KVM_DEV_ASSIGN_ENABLE_IOMMU	(1 << 0)
 
commit 68722054035304ec84912fadf185483298d82a8d
Author: Nishanth Aravamudan <nacc at us.ibm.com>
Date:   Wed Aug 10 16:36:27 2011 +0000

    pseries: use macro for firmware filename
    
    For some time we've had a nicely defined macro with the filename for our
    firmware image.  However we didn't actually use it in the place we're
    supposed to.  This patch fixes it.
    
    Signed-off-by: Nishanth Aravamudan <nacc at us.ibm.com>
    Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/spapr.c b/hw/spapr.c
index 00aed62..91953cf 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -442,7 +442,7 @@ static void ppc_spapr_init(ram_addr_t ram_size,
                     "%ldM guest RAM\n", MIN_RAM_SLOF);
             exit(1);
         }
-        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "slof.bin");
+        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, FW_FILE_NAME);
         fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE);
         if (fw_size < 0) {
             hw_error("qemu: could not load LPAR rtas '%s'\n", filename);
commit 827200a2df044bbedd55c0894d94391263b7654c
Author: David Gibson <david at gibson.dropbear.id.au>
Date:   Wed Aug 10 14:44:20 2011 +0000

    pseries: Add real mode debugging hcalls
    
    PAPR systems support several hypercalls intended for use in real mode
    debugging tools.  These implement reads and writes to arbitrary guest
    physical addresses.  This is useful for real mode software because it
    allows access to IO addresses and memory outside the RMA without going
    through the somewhat involved process of setting up the hash page table
    and enabling translation.
    
    We want these so that when we add real IO devices, the SLOF firmware can
    boot from them without having to enter virtual mode.
    
    Signed-off-by: Benjamin Herrenschmidt <benh at kernel.crashing.org>
    Signed-off-by: David Gibson <dwg at au1.ibm.com>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c
index 70f853c..0c61c10 100644
--- a/hw/spapr_hcall.c
+++ b/hw/spapr_hcall.c
@@ -463,6 +463,67 @@ static target_ulong h_rtas(CPUState *env, sPAPREnvironment *spapr,
                            nret, rtas_r3 + 12 + 4*nargs);
 }
 
+static target_ulong h_logical_load(CPUState *env, sPAPREnvironment *spapr,
+                                   target_ulong opcode, target_ulong *args)
+{
+    target_ulong size = args[0];
+    target_ulong addr = args[1];
+
+    switch (size) {
+    case 1:
+        args[0] = ldub_phys(addr);
+        return H_SUCCESS;
+    case 2:
+        args[0] = lduw_phys(addr);
+        return H_SUCCESS;
+    case 4:
+        args[0] = ldl_phys(addr);
+        return H_SUCCESS;
+    case 8:
+        args[0] = ldq_phys(addr);
+        return H_SUCCESS;
+    }
+    return H_PARAMETER;
+}
+
+static target_ulong h_logical_store(CPUState *env, sPAPREnvironment *spapr,
+                                    target_ulong opcode, target_ulong *args)
+{
+    target_ulong size = args[0];
+    target_ulong addr = args[1];
+    target_ulong val  = args[2];
+
+    switch (size) {
+    case 1:
+        stb_phys(addr, val);
+        return H_SUCCESS;
+    case 2:
+        stw_phys(addr, val);
+        return H_SUCCESS;
+    case 4:
+        stl_phys(addr, val);
+        return H_SUCCESS;
+    case 8:
+        stq_phys(addr, val);
+        return H_SUCCESS;
+    }
+    return H_PARAMETER;
+}
+
+static target_ulong h_logical_icbi(CPUState *env, sPAPREnvironment *spapr,
+                                   target_ulong opcode, target_ulong *args)
+{
+    /* Nothing to do on emulation, KVM will trap this in the kernel */
+    return H_SUCCESS;
+}
+
+static target_ulong h_logical_dcbf(CPUState *env, sPAPREnvironment *spapr,
+                                   target_ulong opcode, target_ulong *args)
+{
+    /* Nothing to do on emulation, KVM will trap this in the kernel */
+    return H_SUCCESS;
+}
+
 static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
 static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE + 1];
 
@@ -527,6 +588,18 @@ static void hypercall_init(void)
     spapr_register_hypercall(H_REGISTER_VPA, h_register_vpa);
     spapr_register_hypercall(H_CEDE, h_cede);
 
+    /* "debugger" hcalls (also used by SLOF). Note: We do -not- differenciate
+     * here between the "CI" and the "CACHE" variants, they will use whatever
+     * mapping attributes qemu is using. When using KVM, the kernel will
+     * enforce the attributes more strongly
+     */
+    spapr_register_hypercall(H_LOGICAL_CI_LOAD, h_logical_load);
+    spapr_register_hypercall(H_LOGICAL_CI_STORE, h_logical_store);
+    spapr_register_hypercall(H_LOGICAL_CACHE_LOAD, h_logical_load);
+    spapr_register_hypercall(H_LOGICAL_CACHE_STORE, h_logical_store);
+    spapr_register_hypercall(H_LOGICAL_ICBI, h_logical_icbi);
+    spapr_register_hypercall(H_LOGICAL_DCBF, h_logical_dcbf);
+
     /* qemu/KVM-PPC specific hcalls */
     spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas);
 }
commit 4e85f82c857550c5864b27ea96571d722bd80b61
Author: Elie Richa <richa at adacore.com>
Date:   Fri Jul 22 05:58:39 2011 +0000

    PPC: Fix sync instructions problem in SMP
    
    In the current emulation of the load-and-reserve (lwarx) and
    store-conditional (stwcx.) instructions, the internal reservation
    mechanism is taken into account, however each CPU has its own
    reservation information and this information is not synchronized between
    CPUs to perform proper synchronization.
    The following test case with 2 CPUs shows that the semantics of the
    "lwarx" and "stwcx." instructions are not preserved by the emulation.
    The test case does the following :
    	- CPU0: reserve a memory location
    	- CPU1: reserve the same memory location
    	- CPU0: perform stwcx. on the location
    The last store-conditional operation succeeds while it is supposed to
    fail since the reservation was supposed to be lost at the second reserve
    operation.
    
    This (one line) patch fixes this problem in a very simple manner by
    removing the reservation of a CPU every time it is scheduled (in
    cpu_exec()). While this is a harsh workaround, it does not affect the
    guest code much because reservations are usually held for a very short
    time, that is an lwarx is almost always followed by an stwcx. a few
    instructions below. Therefore, in most cases, the reservation will be
    taken and consumed before a CPU switch occurs. However in the rare case
    where a CPU switch does occur between the lwarx and its corresponding
    stwcx.  this patch solves a potential erroneous behavior of the
    synchronization instructions.
    
    Signed-off-by: Elie Richa <richa at adacore.com>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/cpu-exec.c b/cpu-exec.c
index aef66f2..a9fa608 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -217,6 +217,7 @@ int cpu_exec(CPUState *env)
 #elif defined(TARGET_ARM)
 #elif defined(TARGET_UNICORE32)
 #elif defined(TARGET_PPC)
+    env->reserve_addr = -1;
 #elif defined(TARGET_LM32)
 #elif defined(TARGET_MICROBLAZE)
 #elif defined(TARGET_MIPS)
commit f73a2575a3bce8a3c487331c918d2c0f9b2e489d
Author: David Gibson <david at gibson.dropbear.id.au>
Date:   Wed Aug 3 21:02:19 2011 +0000

    pseries: More complete WIMG validation in H_ENTER code
    
    Currently our implementation of the H_ENTER hypercall, which inserts a
    mapping in the hash page table assumes that only ordinary memory is ever
    mapped, and only permits mapping attribute bits accordingly (WIMG==0010).
    
    However, we intend to start adding emulated IO to the pseries platform
    (and real IO with PCI passthrough on kvm) which means this simple test
    will no longer suffice.
    
    This patch extends the h_enter validation code to check if the given
    address is a RAM address.  If it is it enforces WIMG==0010, otherwise
    it assumes that it is an IO mapping and instead enforces WIMG=010x.
    
    Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/spapr.c b/hw/spapr.c
index 9eefef9..00aed62 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -336,7 +336,8 @@ static void ppc_spapr_init(ram_addr_t ram_size,
     }
 
     /* allocate RAM */
-    ram_offset = qemu_ram_alloc(NULL, "ppc_spapr.ram", ram_size);
+    spapr->ram_limit = ram_size;
+    ram_offset = qemu_ram_alloc(NULL, "ppc_spapr.ram", spapr->ram_limit);
     cpu_register_physical_memory(0, ram_size, ram_offset);
 
     /* allocate hash page table.  For now we always make this 16mb,
diff --git a/hw/spapr.h b/hw/spapr.h
index 009c459..3d21b7a 100644
--- a/hw/spapr.h
+++ b/hw/spapr.h
@@ -10,6 +10,7 @@ typedef struct sPAPREnvironment {
     struct VIOsPAPRBus *vio_bus;
     struct icp_state *icp;
 
+    target_phys_addr_t ram_limit;
     void *htab;
     long htab_size;
     target_phys_addr_t fdt_addr, rtas_addr;
diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c
index f7ead04..70f853c 100644
--- a/hw/spapr_hcall.c
+++ b/hw/spapr_hcall.c
@@ -99,6 +99,8 @@ static target_ulong h_enter(CPUState *env, sPAPREnvironment *spapr,
     target_ulong pte_index = args[1];
     target_ulong pteh = args[2];
     target_ulong ptel = args[3];
+    target_ulong page_shift = 12;
+    target_ulong raddr;
     target_ulong i;
     uint8_t *hpte;
 
@@ -111,6 +113,7 @@ static target_ulong h_enter(CPUState *env, sPAPREnvironment *spapr,
 #endif
         if ((ptel & 0xff000) == 0) {
             /* 16M page */
+            page_shift = 24;
             /* lowest AVA bit must be 0 for 16M pages */
             if (pteh & 0x80) {
                 return H_PARAMETER;
@@ -120,12 +123,23 @@ static target_ulong h_enter(CPUState *env, sPAPREnvironment *spapr,
         }
     }
 
-    /* FIXME: bounds check the pa? */
+    raddr = (ptel & HPTE_R_RPN) & ~((1ULL << page_shift) - 1);
 
-    /* Check WIMG */
-    if ((ptel & HPTE_R_WIMG) != HPTE_R_M) {
-        return H_PARAMETER;
+    if (raddr < spapr->ram_limit) {
+        /* Regular RAM - should have WIMG=0010 */
+        if ((ptel & HPTE_R_WIMG) != HPTE_R_M) {
+            return H_PARAMETER;
+        }
+    } else {
+        /* Looks like an IO address */
+        /* FIXME: What WIMG combinations could be sensible for IO?
+         * For now we allow WIMG=010x, but are there others? */
+        /* FIXME: Should we check against registered IO addresses? */
+        if ((ptel & (HPTE_R_W | HPTE_R_I | HPTE_R_M)) != HPTE_R_I) {
+            return H_PARAMETER;
+        }
     }
+
     pteh &= ~0x60ULL;
 
     if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
commit 9dfef5aae422d479d8e561889da05cf31d850d5c
Author: David Gibson <david at gibson.dropbear.id.au>
Date:   Wed Aug 3 21:02:18 2011 +0000

    pseries: interrupt controller should not have a 'reg' property
    
    The interrupt controller presented in the device tree for the pseries
    machine is manipulated by the guest only through hypervisor calls.  It
    has no real or emulated registers for the guest to access.
    
    However, it currently has a bogus 'reg' property advertising a register
    window.  Moreover, this property has an invalid format, being a 32-bit
    zero, when the #address-cells property on the root bus indicates that it
    needs a 64-bit address.  Since the guest never attempts to manipulate
    the node directly, it works, but it is ugly and can cause warnings when
    manipulating the device tree in other tools (such as future firmware
    versions).
    
    This patch, therefore, corrects the problem by entirely removing the
    interrupt-controller node's 'reg' property.
    
    Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/spapr.c b/hw/spapr.c
index bb00ae6..9eefef9 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -194,12 +194,11 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
     _FDT((fdt_end_node(fdt)));
 
     /* interrupt controller */
-    _FDT((fdt_begin_node(fdt, "interrupt-controller at 0")));
+    _FDT((fdt_begin_node(fdt, "interrupt-controller")));
 
     _FDT((fdt_property_string(fdt, "device_type",
                               "PowerPC-External-Interrupt-Presentation")));
     _FDT((fdt_property_string(fdt, "compatible", "IBM,ppc-xicp")));
-    _FDT((fdt_property_cell(fdt, "reg", 0)));
     _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0)));
     _FDT((fdt_property(fdt, "ibm,interrupt-server-ranges",
                        interrupt_server_ranges_prop,
commit 0c103f8e6999889e974246533bf7bf9c433a0471
Author: David Gibson <david at gibson.dropbear.id.au>
Date:   Wed Aug 3 21:02:17 2011 +0000

    pseries: Add a phandle to the xicp interrupt controller device tree node
    
    Future devices we will be adding to the pseries machine (e.g. PCI) will
    need nodes in the device tree which explicitly reference the top-level
    interrupt controller via interrupt-parent or interrupt-map properties.
    
    In order to do this, the interrupt controller node needs an assigned
    phandle.  This patch adds the appropriate property, in preparation.
    
    Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/spapr.c b/hw/spapr.c
index 760e323..bb00ae6 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -57,6 +57,8 @@
 #define MAX_CPUS                256
 #define XICS_IRQS		1024
 
+#define PHANDLE_XICP            0x00001111
+
 sPAPREnvironment *spapr;
 
 static void *spapr_create_fdt_skel(const char *cpu_model,
@@ -202,6 +204,9 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
     _FDT((fdt_property(fdt, "ibm,interrupt-server-ranges",
                        interrupt_server_ranges_prop,
                        sizeof(interrupt_server_ranges_prop))));
+    _FDT((fdt_property_cell(fdt, "#interrupt-cells", 2)));
+    _FDT((fdt_property_cell(fdt, "linux,phandle", PHANDLE_XICP)));
+    _FDT((fdt_property_cell(fdt, "phandle", PHANDLE_XICP)));
 
     _FDT((fdt_end_node(fdt)));
 
commit cc67b9c89907d752f9970b7078afe69afcf10b7a
Author: David Gibson <david at gibson.dropbear.id.au>
Date:   Wed Aug 3 21:02:14 2011 +0000

    pseries: Bugfixes for interrupt numbering in XICS code
    
    The implementation of the XICS interrupt controller contains several
    (difficult to trigger) bugs due to the fact that we were not 100%
    consistent with which irq numbering we used.  In most places, global
    numbers were used as handled by the presentation layer, however a few
    functions took "local" numberings, that is the source number within
    the interrupt source controller which is offset from the global
    number.  In most cases the function and its caller agreed on this, but
    in a few cases it didn't.
    
    This patch cleans this up by always using global numbering.
    Translation to the local number is now always and only done when we
    look up the individual interrupt source state structure.  This should
    remove the existing bugs and with luck reduce the chances of
    re-introducing such bugs.
    
    Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/xics.c b/hw/xics.c
index 80e064e..1c5eaa4 100644
--- a/hw/xics.c
+++ b/hw/xics.c
@@ -185,17 +185,17 @@ static int ics_valid_irq(struct ics_state *ics, uint32_t nr)
         && (nr < (ics->offset + ics->nr_irqs));
 }
 
-static void ics_set_irq_msi(void *opaque, int nr, int val)
+static void ics_set_irq_msi(void *opaque, int srcno, int val)
 {
     struct ics_state *ics = (struct ics_state *)opaque;
-    struct ics_irq_state *irq = ics->irqs + nr;
+    struct ics_irq_state *irq = ics->irqs + srcno;
 
     if (val) {
         if (irq->priority == 0xff) {
             irq->masked_pending = 1;
             /* masked pending */ ;
         } else  {
-            icp_irq(ics->icp, irq->server, nr + ics->offset, irq->priority);
+            icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority);
         }
     }
 }
@@ -227,7 +227,7 @@ static void ics_resend_msi(struct ics_state *ics)
 static void ics_write_xive_msi(struct ics_state *ics, int nr, int server,
                                uint8_t priority)
 {
-    struct ics_irq_state *irq = ics->irqs + nr;
+    struct ics_irq_state *irq = ics->irqs + nr - ics->offset;
 
     irq->server = server;
     irq->priority = priority;
@@ -237,7 +237,7 @@ static void ics_write_xive_msi(struct ics_state *ics, int nr, int server,
     }
 
     irq->masked_pending = 0;
-    icp_irq(ics->icp, server, nr + ics->offset, priority);
+    icp_irq(ics->icp, server, nr, priority);
 }
 
 static void ics_reject(struct ics_state *ics, int nr)
@@ -332,7 +332,7 @@ static void rtas_set_xive(sPAPREnvironment *spapr, uint32_t token,
         return;
     }
 
-    ics_write_xive_msi(ics, nr - ics->offset, server, priority);
+    ics_write_xive_msi(ics, nr, server, priority);
 
     rtas_st(rets, 0, 0); /* Success */
 }
@@ -386,7 +386,7 @@ static void rtas_int_off(sPAPREnvironment *spapr, uint32_t token,
     struct ics_irq_state *irq = xics->irqs + (nr - xics->offset);
 
     irq->saved_priority = irq->priority;
-    ics_write_xive_msi(xics, nr - xics->offset, irq->server, 0xff);
+    ics_write_xive_msi(xics, nr, irq->server, 0xff);
 #endif
 
     rtas_st(rets, 0, 0); /* Success */
@@ -416,8 +416,7 @@ static void rtas_int_on(sPAPREnvironment *spapr, uint32_t token,
 #if 0
     struct ics_irq_state *irq = xics->irqs + (nr - xics->offset);
 
-    ics_write_xive_msi(xics, nr - xics->offset,
-                       irq->server, irq->saved_priority);
+    ics_write_xive_msi(xics, nr, irq->server, irq->saved_priority);
 #endif
 
     rtas_st(rets, 0, 0); /* Success */
commit 0a8b293893051f5c170ae7a2209c12fb92666027
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Aug 9 18:07:13 2011 +0200

    PPC: SPAPR: Use KVM function for time info
    
    One of the things we can't fake on PPC is the timer speed. So
    we need to extract the frequency information from the host and
    put it back into the guest device tree.
    
    Luckily, we already have functions for that from the non-pseries
    targets, so all we need to do is to connect the dots and the guest
    suddenly gets to know its real timer speeds.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/spapr.c b/hw/spapr.c
index c5c9a95..760e323 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -140,6 +140,8 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
         char *nodename;
         uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
                            0xffffffff, 0xffffffff};
+        uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq() : TIMEBASE_FREQ;
+        uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000;
 
         if (asprintf(&nodename, "%s@%x", modelname, index) < 0) {
             fprintf(stderr, "Allocation failure\n");
@@ -158,10 +160,8 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
                                 env->dcache_line_size)));
         _FDT((fdt_property_cell(fdt, "icache-block-size",
                                 env->icache_line_size)));
-        _FDT((fdt_property_cell(fdt, "timebase-frequency", TIMEBASE_FREQ)));
-        /* Hardcode CPU frequency for now.  It's kind of arbitrary on
-         * full emu, for kvm we should copy it from the host */
-        _FDT((fdt_property_cell(fdt, "clock-frequency", 1000000000)));
+        _FDT((fdt_property_cell(fdt, "timebase-frequency", tbfreq)));
+        _FDT((fdt_property_cell(fdt, "clock-frequency", cpufreq)));
         _FDT((fdt_property_cell(fdt, "ibm,slb-size", env->slb_nr)));
         _FDT((fdt_property(fdt, "ibm,pft-size",
                            pft_size_prop, sizeof(pft_size_prop))));
commit f61b4bedaf3508b0dffa2e4b277af1f6646c3418
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Aug 9 17:57:37 2011 +0200

    PPC: Enable to use PAPR with PR style KVM
    
    When running PR style KVM, we need to tell the kernel that we want
    to run in PAPR mode now. This means that we need to pass some more
    register information down and enable papr mode. We also need to align
    the HTAB to htab_size boundary.
    
    Using this patch, -M pseries works with kvm even on non-hv kvm
    implementations, as long as the preceding kernel patches are in.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    
    ---
    
    v1 -> v2:
    
      - match on CONFIG_PSERIES
    
    v2 -> v3:
    
      - remove HIOR pieces from PAPR patch (ABI breakage)

diff --git a/hw/spapr.c b/hw/spapr.c
index 8cf93fe..c5c9a95 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -38,6 +38,9 @@
 #include "hw/spapr_vio.h"
 #include "hw/xics.h"
 
+#include "kvm.h"
+#include "kvm_ppc.h"
+
 #include <libfdt.h>
 
 #define KERNEL_LOAD_ADDR        0x00000000
@@ -336,12 +339,21 @@ static void ppc_spapr_init(ram_addr_t ram_size,
      * later we should probably make it scale to the size of guest
      * RAM */
     spapr->htab_size = 1ULL << (pteg_shift + 7);
-    spapr->htab = g_malloc(spapr->htab_size);
+    spapr->htab = qemu_memalign(spapr->htab_size, spapr->htab_size);
 
     for (env = first_cpu; env != NULL; env = env->next_cpu) {
         env->external_htab = spapr->htab;
         env->htab_base = -1;
         env->htab_mask = spapr->htab_size - 1;
+
+        /* Tell KVM that we're in PAPR mode */
+        env->spr[SPR_SDR1] = (unsigned long)spapr->htab |
+                             ((pteg_shift + 7) - 18);
+        env->spr[SPR_HIOR] = 0;
+
+        if (kvm_enabled()) {
+            kvmppc_set_papr(env);
+        }
     }
 
     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin");
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index 77b98c4..f65b6e1 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -29,6 +29,10 @@
 #include "cpu.h"
 #include "device_tree.h"
 
+#include "hw/sysbus.h"
+#include "hw/spapr.h"
+#include "hw/spapr_vio.h"
+
 //#define DEBUG_KVM
 
 #ifdef DEBUG_KVM
@@ -455,6 +459,14 @@ int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run)
         dprintf("handle halt\n");
         ret = kvmppc_handle_halt(env);
         break;
+#ifdef CONFIG_PSERIES
+    case KVM_EXIT_PAPR_HCALL:
+        dprintf("handle PAPR hypercall\n");
+        run->papr_hcall.ret = spapr_hypercall(env, run->papr_hcall.nr,
+                                              run->papr_hcall.args);
+        ret = 1;
+        break;
+#endif
     default:
         fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason);
         ret = -1;
@@ -606,6 +618,34 @@ int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len)
     return 0;
 }
 
+void kvmppc_set_papr(CPUState *env)
+{
+    struct kvm_enable_cap cap;
+    int ret;
+
+    memset(&cap, 0, sizeof(cap));
+    cap.cap = KVM_CAP_PPC_PAPR;
+    ret = kvm_vcpu_ioctl(env, KVM_ENABLE_CAP, &cap);
+
+    if (ret) {
+        goto fail;
+    }
+
+    /*
+     * XXX We set HIOR here. It really should be a qdev property of
+     *     the CPU node, but we don't have CPUs converted to qdev yet.
+     *
+     *     Once we have qdev CPUs, move HIOR to a qdev property and
+     *     remove this chunk.
+     */
+    /* XXX Set HIOR using new ioctl */
+
+    return;
+
+fail:
+    cpu_abort(env, "This KVM version does not support PAPR\n");
+}
+
 bool kvm_arch_stop_on_emulation_error(CPUState *env)
 {
     return true;
diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h
index 76f98d9..c484e60 100644
--- a/target-ppc/kvm_ppc.h
+++ b/target-ppc/kvm_ppc.h
@@ -17,6 +17,7 @@ uint32_t kvmppc_get_tbfreq(void);
 uint64_t kvmppc_get_clockfreq(void);
 int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len);
 int kvmppc_set_interrupt(CPUState *env, int irq, int level);
+void kvmppc_set_papr(CPUState *env);
 
 #else
 
@@ -40,6 +41,10 @@ static inline int kvmppc_set_interrupt(CPUState *env, int irq, int level)
     return -1;
 }
 
+static inline void kvmppc_set_papr(CPUState *env)
+{
+}
+
 #endif
 
 #ifndef CONFIG_KVM
commit 7c6da3deb8b8670043f2ea5b21da939436ce41c3
Author: Alexander Graf <agraf at suse.de>
Date:   Tue Aug 9 14:02:19 2011 +0200

    KVM: update kernel headers
    
    This patch updates the kvm kernel headers to the latest version.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h
index 777d307..579e219 100644
--- a/linux-headers/asm-powerpc/kvm.h
+++ b/linux-headers/asm-powerpc/kvm.h
@@ -22,6 +22,10 @@
 
 #include <linux/types.h>
 
+/* Select powerpc specific features in <linux/kvm.h> */
+#define __KVM_HAVE_SPAPR_TCE
+#define __KVM_HAVE_PPC_SMT
+
 struct kvm_regs {
 	__u64 pc;
 	__u64 cr;
@@ -145,6 +149,12 @@ struct kvm_regs {
 #define KVM_SREGS_E_UPDATE_DBSR		(1 << 3)
 
 /*
+ * Book3S special bits to indicate contents in the struct by maintaining
+ * backwards compatibility with older structs. If adding a new field,
+ * please make sure to add a flag for that new field */
+#define KVM_SREGS_S_HIOR		(1 << 0)
+
+/*
  * In KVM_SET_SREGS, reserved/pad fields must be left untouched from a
  * previous KVM_GET_REGS.
  *
@@ -169,6 +179,8 @@ struct kvm_sregs {
 				__u64 ibat[8];
 				__u64 dbat[8];
 			} ppc32;
+			__u64 flags; /* KVM_SREGS_S_ */
+			__u64 hior;
 		} s;
 		struct {
 			union {
@@ -272,4 +284,15 @@ struct kvm_guest_debug_arch {
 #define KVM_INTERRUPT_UNSET	-2U
 #define KVM_INTERRUPT_SET_LEVEL	-3U
 
+/* for KVM_CAP_SPAPR_TCE */
+struct kvm_create_spapr_tce {
+	__u64 liobn;
+	__u32 window_size;
+};
+
+/* for KVM_ALLOCATE_RMA */
+struct kvm_allocate_rma {
+	__u64 rma_size;
+};
+
 #endif /* __LINUX_KVM_POWERPC_H */
diff --git a/linux-headers/asm-x86/kvm_para.h b/linux-headers/asm-x86/kvm_para.h
index 834d71e..f2ac46a 100644
--- a/linux-headers/asm-x86/kvm_para.h
+++ b/linux-headers/asm-x86/kvm_para.h
@@ -21,6 +21,7 @@
  */
 #define KVM_FEATURE_CLOCKSOURCE2        3
 #define KVM_FEATURE_ASYNC_PF		4
+#define KVM_FEATURE_STEAL_TIME		5
 
 /* The last 8 bits are used to indicate how to interpret the flags field
  * in pvclock structure. If no bits are set, all flags are ignored.
@@ -30,10 +31,23 @@
 #define MSR_KVM_WALL_CLOCK  0x11
 #define MSR_KVM_SYSTEM_TIME 0x12
 
+#define KVM_MSR_ENABLED 1
 /* Custom MSRs falls in the range 0x4b564d00-0x4b564dff */
 #define MSR_KVM_WALL_CLOCK_NEW  0x4b564d00
 #define MSR_KVM_SYSTEM_TIME_NEW 0x4b564d01
 #define MSR_KVM_ASYNC_PF_EN 0x4b564d02
+#define MSR_KVM_STEAL_TIME  0x4b564d03
+
+struct kvm_steal_time {
+	__u64 steal;
+	__u32 version;
+	__u32 flags;
+	__u32 pad[12];
+};
+
+#define KVM_STEAL_ALIGNMENT_BITS 5
+#define KVM_STEAL_VALID_BITS ((-1ULL << (KVM_STEAL_ALIGNMENT_BITS + 1)))
+#define KVM_STEAL_RESERVED_MASK (((1 << KVM_STEAL_ALIGNMENT_BITS) - 1 ) << 1)
 
 #define KVM_MAX_MMU_OP_BATCH           32
 
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index fc63b73..2062375 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -161,6 +161,7 @@ struct kvm_pit_config {
 #define KVM_EXIT_NMI              16
 #define KVM_EXIT_INTERNAL_ERROR   17
 #define KVM_EXIT_OSI              18
+#define KVM_EXIT_PAPR_HCALL	  19
 
 /* For KVM_EXIT_INTERNAL_ERROR */
 #define KVM_INTERNAL_ERROR_EMULATION 1
@@ -264,6 +265,11 @@ struct kvm_run {
 		struct {
 			__u64 gprs[32];
 		} osi;
+		struct {
+			__u64 nr;
+			__u64 ret;
+			__u64 args[9];
+		} papr_hcall;
 		/* Fix the size of the union. */
 		char padding[256];
 	};
@@ -457,7 +463,7 @@ struct kvm_ppc_pvinfo {
 #define KVM_CAP_VAPIC 6
 #define KVM_CAP_EXT_CPUID 7
 #define KVM_CAP_CLOCKSOURCE 8
-#define KVM_CAP_NR_VCPUS 9       /* returns max vcpus per vm */
+#define KVM_CAP_NR_VCPUS 9       /* returns recommended max vcpus per vm */
 #define KVM_CAP_NR_MEMSLOTS 10   /* returns max memory slots per vm */
 #define KVM_CAP_PIT 11
 #define KVM_CAP_NOP_IO_DELAY 12
@@ -544,6 +550,12 @@ struct kvm_ppc_pvinfo {
 #define KVM_CAP_TSC_CONTROL 60
 #define KVM_CAP_GET_TSC_KHZ 61
 #define KVM_CAP_PPC_BOOKE_SREGS 62
+#define KVM_CAP_SPAPR_TCE 63
+#define KVM_CAP_PPC_SMT 64
+#define KVM_CAP_PPC_RMA	65
+#define KVM_CAP_MAX_VCPUS 66       /* returns max vcpus per vm */
+#define KVM_CAP_PPC_HIOR 67
+#define KVM_CAP_PPC_PAPR 68
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -746,6 +758,9 @@ struct kvm_clock_data {
 /* Available with KVM_CAP_XCRS */
 #define KVM_GET_XCRS		  _IOR(KVMIO,  0xa6, struct kvm_xcrs)
 #define KVM_SET_XCRS		  _IOW(KVMIO,  0xa7, struct kvm_xcrs)
+#define KVM_CREATE_SPAPR_TCE	  _IOW(KVMIO,  0xa8, struct kvm_create_spapr_tce)
+/* Available with KVM_CAP_RMA */
+#define KVM_ALLOCATE_RMA	  _IOR(KVMIO,  0xa9, struct kvm_allocate_rma)
 
 #define KVM_DEV_ASSIGN_ENABLE_IOMMU	(1 << 0)
 
@@ -773,20 +788,14 @@ struct kvm_assigned_pci_dev {
 
 struct kvm_assigned_irq {
 	__u32 assigned_dev_id;
-	__u32 host_irq;
+	__u32 host_irq; /* ignored (legacy field) */
 	__u32 guest_irq;
 	__u32 flags;
 	union {
-		struct {
-			__u32 addr_lo;
-			__u32 addr_hi;
-			__u32 data;
-		} guest_msi;
 		__u32 reserved[12];
 	};
 };
 
-
 struct kvm_assigned_msix_nr {
 	__u32 assigned_dev_id;
 	__u16 entry_nr;
diff --git a/linux-headers/linux/kvm_para.h b/linux-headers/linux/kvm_para.h
index 7bdcf93..b315e27 100644
--- a/linux-headers/linux/kvm_para.h
+++ b/linux-headers/linux/kvm_para.h
@@ -26,3 +26,4 @@
 #include <asm/kvm_para.h>
 
 #endif /* __LINUX_KVM_PARA_H */
+
commit 0a6b8dde6523a93d263631ddb9a726b2790a3cf8
Author: Alexander Graf <agraf at suse.de>
Date:   Wed Aug 10 14:21:41 2011 +0200

    PPC: Add new target config for pseries
    
    We only support -M pseries when certain prerequisites are met, such
    as a PPC64 guest and libfdt. To only gather these requirements in
    a single place, this patch introduces a new CONFIG_PSERIES variable
    that gets set when all prerequisites are met.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/Makefile.target b/Makefile.target
index ff3efa4..fc3dfaa 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -239,10 +239,8 @@ obj-ppc-y += ppc_oldworld.o
 # NewWorld PowerMac
 obj-ppc-y += ppc_newworld.o
 # IBM pSeries (sPAPR)
-ifeq ($(CONFIG_FDT)$(TARGET_PPC64),yy)
-obj-ppc-y += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o
-obj-ppc-y += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o
-endif
+obj-ppc-$(CONFIG_PSERIES) += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o
+obj-ppc-$(CONFIG_PSERIES) += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o
 # PowerPC 4xx boards
 obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
 obj-ppc-y += ppc440.o ppc440_bamboo.o
diff --git a/configure b/configure
index 59b1494..29cdd75 100755
--- a/configure
+++ b/configure
@@ -3389,6 +3389,9 @@ case "$target_arch2" in
       fi
     fi
 esac
+if test "$target_arch2" = "ppc64" -a "$fdt" = "yes"; then
+  echo "CONFIG_PSERIES=y" >> $config_target_mak
+fi
 if test "$target_bigendian" = "yes" ; then
   echo "TARGET_WORDS_BIGENDIAN=y" >> $config_target_mak
 fi
commit a2a674204b51ec58c9bbc1bc9de62f68e1fc36f5
Author: Alexander Graf <agraf at suse.de>
Date:   Thu Jul 21 01:45:37 2011 +0200

    PPC: E500: Bump CPU count to 15
    
    Now that we have everything in place, make the machine description
    aware of the fact that we can now handle 15 virtual CPUs!
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    
    ---
    
    v1 -> v2:
    
      - Max cpus is 15 because of MPIC

diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index dfa8034..b86a008 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -396,6 +396,7 @@ static QEMUMachine mpc8544ds_machine = {
     .name = "mpc8544ds",
     .desc = "mpc8544ds",
     .init = mpc8544ds_init,
+    .max_cpus = 15,
 };
 
 static void mpc8544ds_machine_init(void)
commit 1e3debf098acfc222344b6afcc45d04f1c7c4185
Author: Alexander Graf <agraf at suse.de>
Date:   Sat Jul 23 10:56:40 2011 +0200

    MPC8544DS: Generate CPU nodes on init
    
    With this patch, we generate CPU nodes in the machine initialization, giving
    us the freedom to generate as many nodes as we want and as the machine supports,
    but only those.
    
    This is a first step towards a much cleaner device tree generation
    infrastructure, where we would not require precompiled dtb blobs anymore.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index a3e1ce4..dfa8034 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -123,23 +123,43 @@ static int mpc8544_load_device_tree(CPUState *env,
                              hypercall, sizeof(hypercall));
     }
 
-    for (i = 0; i < smp_cpus; i++) {
+    /* We need to generate the cpu nodes in reverse order, so Linux can pick
+       the first node as boot node and be happy */
+    for (i = smp_cpus - 1; i >= 0; i--) {
         char cpu_name[128];
-        uint64_t cpu_release_addr[] = {
-            cpu_to_be64(MPC8544_SPIN_BASE + (i * 0x20))
-        };
+        uint64_t cpu_release_addr = cpu_to_be64(MPC8544_SPIN_BASE + (i * 0x20));
+
+        for (env = first_cpu; env != NULL; env = env->next_cpu) {
+            if (env->cpu_index == i) {
+                break;
+            }
+        }
+
+        if (!env) {
+            continue;
+        }
 
-        snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x", i);
+        snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x", env->cpu_index);
+        qemu_devtree_add_subnode(fdt, cpu_name);
         qemu_devtree_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
         qemu_devtree_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
-        qemu_devtree_setprop(fdt, cpu_name, "cpu-release-addr",
-                             cpu_release_addr, sizeof(cpu_release_addr));
-    }
-
-    for (i = smp_cpus; i < 32; i++) {
-        char cpu_name[128];
-        snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x", i);
-        qemu_devtree_nop_node(fdt, cpu_name);
+        qemu_devtree_setprop_string(fdt, cpu_name, "device_type", "cpu");
+        qemu_devtree_setprop_cell(fdt, cpu_name, "reg", env->cpu_index);
+        qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-line-size",
+                                  env->dcache_line_size);
+        qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-line-size",
+                                  env->icache_line_size);
+        qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000);
+        qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000);
+        qemu_devtree_setprop_cell(fdt, cpu_name, "bus-frequency", 0);
+        if (env->cpu_index) {
+            qemu_devtree_setprop_string(fdt, cpu_name, "status", "disabled");
+            qemu_devtree_setprop_string(fdt, cpu_name, "enable-method", "spin-table");
+            qemu_devtree_setprop(fdt, cpu_name, "cpu-release-addr",
+                                 &cpu_release_addr, sizeof(cpu_release_addr));
+        } else {
+            qemu_devtree_setprop_string(fdt, cpu_name, "status", "okay");
+        }
     }
 
     ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
commit be637f74d4991089170ddb89a49400b1fb8feff8
Author: Alexander Graf <agraf at suse.de>
Date:   Sat Jul 23 10:55:50 2011 +0200

    MPC8544DS: Remove CPU nodes
    
    We want to generate the CPU nodes in machine init code, so remove them from
    the device tree definition that we precompile.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/pc-bios/mpc8544ds.dtb b/pc-bios/mpc8544ds.dtb
index ae318b1..c6d3021 100644
Binary files a/pc-bios/mpc8544ds.dtb and b/pc-bios/mpc8544ds.dtb differ
diff --git a/pc-bios/mpc8544ds.dts b/pc-bios/mpc8544ds.dts
index a88b47c..7eb3160 100644
--- a/pc-bios/mpc8544ds.dts
+++ b/pc-bios/mpc8544ds.dts
@@ -25,18 +25,6 @@
 	cpus {
 		#address-cells = <1>;
 		#size-cells = <0>;
-
-		PowerPC,8544 at 0 {
-			device_type = "cpu";
-			reg = <0x0>;
-			d-cache-line-size = <32>;	// 32 bytes
-			i-cache-line-size = <32>;	// 32 bytes
-			d-cache-size = <0x8000>;		// L1, 32K
-			i-cache-size = <0x8000>;		// L1, 32K
-			timebase-frequency = <0>;
-			bus-frequency = <0>;
-			clock-frequency = <0>;
-		};
 	};
 
 	memory {
commit ded57c5f3a2dd49728b1cb51f17194e880514ff6
Author: Alexander Graf <agraf at suse.de>
Date:   Sat Jul 23 10:54:11 2011 +0200

    device tree: give dt more size
    
    We currently load a device tree blob and then just take its size x2 to
    account for modifications we do inside. While this is nice and great,
    it fails when we have a small device tree as blob and lots of nodes added
    in machine init code.
    
    So for now, just make it 20k bigger than it was before. We maybe want to
    be more clever about this later.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/device_tree.c b/device_tree.c
index 751538e..dc69232 100644
--- a/device_tree.c
+++ b/device_tree.c
@@ -41,6 +41,7 @@ void *load_device_tree(const char *filename_path, int *sizep)
     }
 
     /* Expand to 2x size to give enough room for manipulation.  */
+    dt_size += 10000;
     dt_size *= 2;
     /* First allocate space in qemu for device tree */
     fdt = g_malloc0(dt_size);
commit ccbcfedd17fd2d13521fcee66810d0df464ec1cc
Author: Alexander Graf <agraf at suse.de>
Date:   Sat Jul 23 10:52:00 2011 +0200

    device tree: dont fail operations
    
    When we screw up and issue an FDT command that doesn't work, we really need to
    know immediately and usually can't continue to create the machine. To make sure
    we don't need to add error checking in all device tree modification code users,
    we can just add the fail checks to the qemu abstract functions.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/device_tree.c b/device_tree.c
index f4a78c8..751538e 100644
--- a/device_tree.c
+++ b/device_tree.c
@@ -72,56 +72,81 @@ fail:
     return NULL;
 }
 
-int qemu_devtree_setprop(void *fdt, const char *node_path,
-                         const char *property, void *val_array, int size)
+static int findnode_nofail(void *fdt, const char *node_path)
 {
     int offset;
 
     offset = fdt_path_offset(fdt, node_path);
-    if (offset < 0)
-        return offset;
+    if (offset < 0) {
+        fprintf(stderr, "%s Couldn't find node %s: %s\n", __func__, node_path,
+                fdt_strerror(offset));
+        exit(1);
+    }
+
+    return offset;
+}
+
+int qemu_devtree_setprop(void *fdt, const char *node_path,
+                         const char *property, void *val_array, int size)
+{
+    int r;
+
+    r = fdt_setprop(fdt, findnode_nofail(fdt, node_path), property, val_array, size);
+    if (r < 0) {
+        fprintf(stderr, "%s: Couldn't set %s/%s: %s\n", __func__, node_path,
+                property, fdt_strerror(r));
+        exit(1);
+    }
 
-    return fdt_setprop(fdt, offset, property, val_array, size);
+    return r;
 }
 
 int qemu_devtree_setprop_cell(void *fdt, const char *node_path,
                               const char *property, uint32_t val)
 {
-    int offset;
+    int r;
 
-    offset = fdt_path_offset(fdt, node_path);
-    if (offset < 0)
-        return offset;
+    r = fdt_setprop_cell(fdt, findnode_nofail(fdt, node_path), property, val);
+    if (r < 0) {
+        fprintf(stderr, "%s: Couldn't set %s/%s = %#08x: %s\n", __func__,
+                node_path, property, val, fdt_strerror(r));
+        exit(1);
+    }
 
-    return fdt_setprop_cell(fdt, offset, property, val);
+    return r;
 }
 
 int qemu_devtree_setprop_string(void *fdt, const char *node_path,
                                 const char *property, const char *string)
 {
-    int offset;
+    int r;
 
-    offset = fdt_path_offset(fdt, node_path);
-    if (offset < 0)
-        return offset;
+    r = fdt_setprop_string(fdt, findnode_nofail(fdt, node_path), property, string);
+    if (r < 0) {
+        fprintf(stderr, "%s: Couldn't set %s/%s = %s: %s\n", __func__,
+                node_path, property, string, fdt_strerror(r));
+        exit(1);
+    }
 
-    return fdt_setprop_string(fdt, offset, property, string);
+    return r;
 }
 
 int qemu_devtree_nop_node(void *fdt, const char *node_path)
 {
-    int offset;
+    int r;
 
-    offset = fdt_path_offset(fdt, node_path);
-    if (offset < 0)
-        return offset;
+    r = fdt_nop_node(fdt, findnode_nofail(fdt, node_path));
+    if (r < 0) {
+        fprintf(stderr, "%s: Couldn't nop node %s: %s\n", __func__, node_path,
+                fdt_strerror(r));
+        exit(1);
+    }
 
-    return fdt_nop_node(fdt, offset);
+    return r;
 }
 
 int qemu_devtree_add_subnode(void *fdt, const char *name)
 {
-    int offset;
     char *dupname = g_strdup(name);
     char *basename = strrchr(dupname, '/');
     int retval;
@@ -133,12 +158,13 @@ int qemu_devtree_add_subnode(void *fdt, const char *name)
     basename[0] = '\0';
     basename++;
 
-    offset = fdt_path_offset(fdt, dupname);
-    if (offset < 0) {
-        return offset;
+    retval = fdt_add_subnode(fdt, findnode_nofail(fdt, dupname), basename);
+    if (retval < 0) {
+        fprintf(stderr, "FDT: Failed to create subnode %s: %s\n", name,
+                fdt_strerror(retval));
+        exit(1);
     }
 
-    retval = fdt_add_subnode(fdt, offset, basename);
     g_free(dupname);
     return retval;
 }
commit 80ad781643b68c91316687051965e12021abeab6
Author: Alexander Graf <agraf at suse.de>
Date:   Fri Jul 22 13:55:37 2011 +0200

    device tree: add add_subnode command
    
    We want to be able to create subnodes in our device tree, so export it through
    the qemu device tree abstraction framework.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/device_tree.c b/device_tree.c
index 23e89e3..f4a78c8 100644
--- a/device_tree.c
+++ b/device_tree.c
@@ -118,3 +118,27 @@ int qemu_devtree_nop_node(void *fdt, const char *node_path)
 
     return fdt_nop_node(fdt, offset);
 }
+
+int qemu_devtree_add_subnode(void *fdt, const char *name)
+{
+    int offset;
+    char *dupname = g_strdup(name);
+    char *basename = strrchr(dupname, '/');
+    int retval;
+
+    if (!basename) {
+        return -1;
+    }
+
+    basename[0] = '\0';
+    basename++;
+
+    offset = fdt_path_offset(fdt, dupname);
+    if (offset < 0) {
+        return offset;
+    }
+
+    retval = fdt_add_subnode(fdt, offset, basename);
+    g_free(dupname);
+    return retval;
+}
diff --git a/device_tree.h b/device_tree.h
index 76fce5f..4378685 100644
--- a/device_tree.h
+++ b/device_tree.h
@@ -23,5 +23,6 @@ int qemu_devtree_setprop_cell(void *fdt, const char *node_path,
 int qemu_devtree_setprop_string(void *fdt, const char *node_path,
                                 const char *property, const char *string);
 int qemu_devtree_nop_node(void *fdt, const char *node_path);
+int qemu_devtree_add_subnode(void *fdt, const char *name);
 
 #endif /* __DEVICE_TREE_H__ */
commit 10f25a46c5202329cc028bcd79a0ca5f277261a4
Author: Alexander Graf <agraf at suse.de>
Date:   Thu Jul 21 03:06:12 2011 +0200

    PPC: E500: Update cpu-release-addr property in cpu nodes
    
    The guest OS wants to know where the guest spins, so let's tell him while
    updating the CPU nodes with the frequencies anyways.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    
    ---
    
    v1 -> v2:
    
      - use new spin table address

diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 3b8b449..a3e1ce4 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -125,9 +125,15 @@ static int mpc8544_load_device_tree(CPUState *env,
 
     for (i = 0; i < smp_cpus; i++) {
         char cpu_name[128];
+        uint64_t cpu_release_addr[] = {
+            cpu_to_be64(MPC8544_SPIN_BASE + (i * 0x20))
+        };
+
         snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x", i);
         qemu_devtree_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
         qemu_devtree_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
+        qemu_devtree_setprop(fdt, cpu_name, "cpu-release-addr",
+                             cpu_release_addr, sizeof(cpu_release_addr));
     }
 
     for (i = smp_cpus; i < 32; i++) {
commit 5c145dacacad04f751ca5c3fb6467e590e7f3c46
Author: Alexander Graf <agraf at suse.de>
Date:   Fri Jul 22 13:32:29 2011 +0200

    PPC: E500: Add PV spinning code
    
    CPUs that are not the boot CPU need to run in spinning code to check if they
    should run off to execute and if so where to jump to. This usually happens
    by leaving secondary CPUs looping and checking if some variable in memory
    changed.
    
    In an environment like Qemu however we can be more clever. We can just export
    the spin table the primary CPU modifies as MMIO region that would event based
    wake up the respective secondary CPUs. That saves us quite some cycles while
    the secondary CPUs are not up yet.
    
    So this patch adds a PV device that simply exports the spinning table into the
    guest and thus allows the primary CPU to wake up secondary ones.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    
    ---
    
    v1 -> v2:
    
      - change into MMIO scheme
      - map the secondary NIP instead of 0 1:1
      - only map 64MB for TLB, same as u-boot
      - prepare code for 64-bit spinnings
    
    v2 -> v3:
    
      - remove r6
      - set MAS2_M
      - map EA 0
      - use second TLB1 entry
    
    v3 -> v4:
    
      - change to memoryops
    
    v4 -> v5:
    
      - fix endianness bugs
    
    v5 -> v6:
    
      - add header

diff --git a/Makefile.target b/Makefile.target
index 8db9f37..ff3efa4 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -247,7 +247,7 @@ endif
 obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
 obj-ppc-y += ppc440.o ppc440_bamboo.o
 # PowerPC E500 boards
-obj-ppc-y += ppce500_mpc8544ds.o mpc8544_guts.o
+obj-ppc-y += ppce500_mpc8544ds.o mpc8544_guts.o ppce500_spin.o
 # PowerPC 440 Xilinx ML507 reference board.
 obj-ppc-y += virtex_ml507.o
 obj-ppc-$(CONFIG_KVM) += kvm_ppc.o
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 9379624..3b8b449 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -49,6 +49,7 @@
 #define MPC8544_PCI_IO             0xE1000000
 #define MPC8544_PCI_IOLEN          0x10000
 #define MPC8544_UTIL_BASE          (MPC8544_CCSRBAR_BASE + 0xe0000)
+#define MPC8544_SPIN_BASE          0xEF000000
 
 struct boot_info
 {
@@ -164,6 +165,18 @@ static void mmubooke_create_initial_mapping(CPUState *env,
     tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
 }
 
+static void mpc8544ds_cpu_reset_sec(void *opaque)
+{
+    CPUState *env = opaque;
+
+    cpu_reset(env);
+
+    /* Secondary CPU starts in halted state for now. Needs to change when
+       implementing non-kernel boot. */
+    env->halted = 1;
+    env->exception_index = EXCP_HLT;
+}
+
 static void mpc8544ds_cpu_reset(void *opaque)
 {
     CPUState *env = opaque;
@@ -172,6 +185,7 @@ static void mpc8544ds_cpu_reset(void *opaque)
     cpu_reset(env);
 
     /* Set initial guest state. */
+    env->halted = 0;
     env->gpr[1] = (16<<20) - 8;
     env->gpr[3] = bi->dt_base;
     env->nip = bi->entry;
@@ -199,7 +213,6 @@ static void mpc8544ds_init(ram_addr_t ram_size,
     unsigned int pci_irq_nrs[4] = {1, 2, 3, 4};
     qemu_irq **irqs, *mpic;
     DeviceState *dev;
-    struct boot_info *boot_info;
     CPUState *firstenv = NULL;
 
     /* Setup CPUs */
@@ -234,9 +247,16 @@ static void mpc8544ds_init(ram_addr_t ram_size,
         env->spr[SPR_40x_TCR] = 1 << 26;
 
         /* Register reset handler */
-        boot_info = g_malloc0(sizeof(struct boot_info));
-        qemu_register_reset(mpc8544ds_cpu_reset, env);
-        env->load_info = boot_info;
+        if (!i) {
+            /* Primary CPU */
+            struct boot_info *boot_info;
+            boot_info = g_malloc0(sizeof(struct boot_info));
+            qemu_register_reset(mpc8544ds_cpu_reset, env);
+            env->load_info = boot_info;
+        } else {
+            /* Secondary CPUs */
+            qemu_register_reset(mpc8544ds_cpu_reset_sec, env);
+        }
     }
 
     env = firstenv;
@@ -289,6 +309,9 @@ static void mpc8544ds_init(ram_addr_t ram_size,
         }
     }
 
+    /* Register spinning region */
+    sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL);
+
     /* Load kernel. */
     if (kernel_filename) {
         kernel_size = load_uimage(kernel_filename, &entry, &loadaddr, NULL);
@@ -321,6 +344,8 @@ static void mpc8544ds_init(ram_addr_t ram_size,
 
     /* If we're loading a kernel directly, we must load the device tree too. */
     if (kernel_filename) {
+        struct boot_info *boot_info;
+
 #ifndef CONFIG_FDT
         cpu_abort(env, "Compiled without FDT support - can't load kernel\n");
 #endif
diff --git a/hw/ppce500_spin.c b/hw/ppce500_spin.c
new file mode 100644
index 0000000..cccd940
--- /dev/null
+++ b/hw/ppce500_spin.c
@@ -0,0 +1,215 @@
+/*
+ * QEMU PowerPC e500v2 ePAPR spinning code
+ *
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: 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/>.
+ *
+ * This code is not really a device, but models an interface that usually
+ * firmware takes care of. It's used when QEMU plays the role of firmware.
+ *
+ * Specification:
+ *
+ * https://www.power.org/resources/downloads/Power_ePAPR_APPROVED_v1.1.pdf
+ *
+ */
+
+#include "hw.h"
+#include "sysemu.h"
+#include "sysbus.h"
+#include "kvm.h"
+
+#define MAX_CPUS 32
+
+typedef struct spin_info {
+    uint64_t addr;
+    uint64_t r3;
+    uint32_t resv;
+    uint32_t pir;
+    uint64_t reserved;
+} __attribute__ ((packed)) SpinInfo;
+
+typedef struct spin_state {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    SpinInfo spin[MAX_CPUS];
+} SpinState;
+
+typedef struct spin_kick {
+    CPUState *env;
+    SpinInfo *spin;
+} SpinKick;
+
+static void spin_reset(void *opaque)
+{
+    SpinState *s = opaque;
+    int i;
+
+    for (i = 0; i < MAX_CPUS; i++) {
+        SpinInfo *info = &s->spin[i];
+
+        info->pir = i;
+        info->r3 = i;
+        info->addr = 1;
+    }
+}
+
+/* Create -kernel TLB entries for BookE, linearly spanning 256MB.  */
+static inline target_phys_addr_t booke206_page_size_to_tlb(uint64_t size)
+{
+    return (ffs(size >> 10) - 1) >> 1;
+}
+
+static void mmubooke_create_initial_mapping(CPUState *env,
+                                     target_ulong va,
+                                     target_phys_addr_t pa,
+                                     target_phys_addr_t len)
+{
+    ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 1);
+    target_phys_addr_t size;
+
+    size = (booke206_page_size_to_tlb(len) << MAS1_TSIZE_SHIFT);
+    tlb->mas1 = MAS1_VALID | size;
+    tlb->mas2 = (va & TARGET_PAGE_MASK) | MAS2_M;
+    tlb->mas7_3 = pa & TARGET_PAGE_MASK;
+    tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
+}
+
+static void spin_kick(void *data)
+{
+    SpinKick *kick = data;
+    CPUState *env = kick->env;
+    SpinInfo *curspin = kick->spin;
+    target_phys_addr_t map_size = 64 * 1024 * 1024;
+    target_phys_addr_t map_start;
+
+    cpu_synchronize_state(env);
+    stl_p(&curspin->pir, env->spr[SPR_PIR]);
+    env->nip = ldq_p(&curspin->addr) & (map_size - 1);
+    env->gpr[3] = ldq_p(&curspin->r3);
+    env->gpr[4] = 0;
+    env->gpr[5] = 0;
+    env->gpr[6] = 0;
+    env->gpr[7] = map_size;
+    env->gpr[8] = 0;
+    env->gpr[9] = 0;
+
+    map_start = ldq_p(&curspin->addr) & ~(map_size - 1);
+    mmubooke_create_initial_mapping(env, 0, map_start, map_size);
+
+    env->halted = 0;
+    env->exception_index = -1;
+    qemu_cpu_kick(env);
+}
+
+static void spin_write(void *opaque, target_phys_addr_t addr, uint64_t value,
+                       unsigned len)
+{
+    SpinState *s = opaque;
+    int env_idx = addr / sizeof(SpinInfo);
+    CPUState *env;
+    SpinInfo *curspin = &s->spin[env_idx];
+    uint8_t *curspin_p = (uint8_t*)curspin;
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        if (env->cpu_index == env_idx) {
+            break;
+        }
+    }
+
+    if (!env) {
+        /* Unknown CPU */
+        return;
+    }
+
+    if (!env->cpu_index) {
+        /* primary CPU doesn't spin */
+        return;
+    }
+
+    curspin_p = &curspin_p[addr % sizeof(SpinInfo)];
+    switch (len) {
+    case 1:
+        stb_p(curspin_p, value);
+        break;
+    case 2:
+        stw_p(curspin_p, value);
+        break;
+    case 4:
+        stl_p(curspin_p, value);
+        break;
+    }
+
+    if (!(ldq_p(&curspin->addr) & 1)) {
+        /* run CPU */
+        SpinKick kick = {
+            .env = env,
+            .spin = curspin,
+        };
+
+        run_on_cpu(env, spin_kick, &kick);
+    }
+}
+
+static uint64_t spin_read(void *opaque, target_phys_addr_t addr, unsigned len)
+{
+    SpinState *s = opaque;
+    uint8_t *spin_p = &((uint8_t*)s->spin)[addr];
+
+    switch (len) {
+    case 1:
+        return ldub_p(spin_p);
+    case 2:
+        return lduw_p(spin_p);
+    case 4:
+        return ldl_p(spin_p);
+    default:
+        assert(0);
+    }
+}
+
+const MemoryRegionOps spin_rw_ops = {
+    .read = spin_read,
+    .write = spin_write,
+    .endianness = DEVICE_BIG_ENDIAN,
+};
+
+static int ppce500_spin_initfn(SysBusDevice *dev)
+{
+    SpinState *s;
+
+    s = FROM_SYSBUS(SpinState, sysbus_from_qdev(dev));
+
+    memory_region_init_io(&s->iomem, &spin_rw_ops, s, "e500 spin pv device",
+                          sizeof(SpinInfo) * MAX_CPUS);
+    sysbus_init_mmio_region(dev, &s->iomem);
+
+    qemu_register_reset(spin_reset, s);
+
+    return 0;
+}
+
+static SysBusDeviceInfo ppce500_spin_info = {
+    .init         = ppce500_spin_initfn,
+    .qdev.name    = "e500-spin",
+    .qdev.size    = sizeof(SpinState),
+};
+
+static void ppce500_spin_register(void)
+{
+    sysbus_register_withprop(&ppce500_spin_info);
+}
+device_init(ppce500_spin_register);
commit 66bc7e00404a2a6ce92b0f4ee2ecc5df416650b3
Author: Alexander Graf <agraf at suse.de>
Date:   Thu Jul 21 03:02:31 2011 +0200

    PPC: E500: Remove unneeded CPU nodes
    
    We should only keep CPU nodes in the device tree around that we really have
    virtual CPUs for. So remove all superfluous entries that we just keep there
    in case someone wants to create a lot of vCPUs.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 0791e27..9379624 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -129,6 +129,12 @@ static int mpc8544_load_device_tree(CPUState *env,
         qemu_devtree_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
     }
 
+    for (i = smp_cpus; i < 32; i++) {
+        char cpu_name[128];
+        snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x", i);
+        qemu_devtree_nop_node(fdt, cpu_name);
+    }
+
     ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
     g_free(fdt);
 
commit 621d05e3011bb369a6d48881ceaabb4ecf1a8790
Author: Alexander Graf <agraf at suse.de>
Date:   Thu Jul 21 03:01:11 2011 +0200

    PPC: E500: Update freqs for all CPUs
    
    Now that we can so nicely find out the host's frequencies, we should also
    make sure that we get them into all virtual CPUs' device tree nodes.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 2c7c677..0791e27 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -70,9 +70,9 @@ static int mpc8544_load_device_tree(CPUState *env,
     int fdt_size;
     void *fdt;
     uint8_t hypercall[16];
-    char cpu_name[128] = "/cpus/PowerPC,8544 at 0";
     uint32_t clock_freq = 400000000;
     uint32_t tb_freq = 400000000;
+    int i;
 
     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
     if (!filename) {
@@ -122,8 +122,12 @@ static int mpc8544_load_device_tree(CPUState *env,
                              hypercall, sizeof(hypercall));
     }
 
-    qemu_devtree_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
-    qemu_devtree_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
+    for (i = 0; i < smp_cpus; i++) {
+        char cpu_name[128];
+        snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x", i);
+        qemu_devtree_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
+        qemu_devtree_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
+    }
 
     ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
     g_free(fdt);
commit 921e28db8dac945af8ae065b862c46393b259374
Author: Alexander Graf <agraf at suse.de>
Date:   Thu Jul 21 02:54:51 2011 +0200

    PPC: KVM: Add stubs for kvm helper functions
    
    We have a bunch of helper functions that don't have any stubs for them in case
    we don't have CONFIG_KVM enabled. That didn't bite us so far, because gcc can
    optimize them out pretty well, but we should really provide them.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    
    ---
    
    v1 -> v2:
    
       - use uint64_t for clockfreq

diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h
index 0c659c8..76f98d9 100644
--- a/target-ppc/kvm_ppc.h
+++ b/target-ppc/kvm_ppc.h
@@ -11,11 +11,37 @@
 
 void kvmppc_init(void);
 
+#ifdef CONFIG_KVM
+
 uint32_t kvmppc_get_tbfreq(void);
 uint64_t kvmppc_get_clockfreq(void);
 int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len);
 int kvmppc_set_interrupt(CPUState *env, int irq, int level);
 
+#else
+
+static inline uint32_t kvmppc_get_tbfreq(void)
+{
+    return 0;
+}
+
+static inline uint64_t kvmppc_get_clockfreq(void)
+{
+    return 0;
+}
+
+static inline int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len)
+{
+    return -1;
+}
+
+static inline int kvmppc_set_interrupt(CPUState *env, int irq, int level)
+{
+    return -1;
+}
+
+#endif
+
 #ifndef CONFIG_KVM
 #define kvmppc_eieio() do { } while (0)
 #else
commit e95a69cb6dce91c971bdf34a84a4026ff6b7821f
Author: Alexander Graf <agraf at suse.de>
Date:   Thu Jul 21 02:46:11 2011 +0200

    PPC: KVM: Remove kvmppc_read_host_property
    
    We just got rid of the last user of kvmppc_read_host_property, so we
    can now safely remove it.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/target-ppc/kvm_ppc.c b/target-ppc/kvm_ppc.c
index 26ecc9d..24fc6bc 100644
--- a/target-ppc/kvm_ppc.c
+++ b/target-ppc/kvm_ppc.c
@@ -21,41 +21,6 @@
 static QEMUTimer *kvmppc_timer;
 static unsigned int kvmppc_timer_rate;
 
-#ifdef CONFIG_FDT
-int kvmppc_read_host_property(const char *node_path, const char *prop,
-                                     void *val, size_t len)
-{
-    char *path;
-    FILE *f;
-    int ret = 0;
-    int pathlen;
-
-    pathlen = snprintf(NULL, 0, "%s/%s/%s", PROC_DEVTREE_PATH, node_path, prop)
-              + 1;
-    path = g_malloc(pathlen);
-
-    snprintf(path, pathlen, "%s/%s/%s", PROC_DEVTREE_PATH, node_path, prop);
-
-    f = fopen(path, "rb");
-    if (f == NULL) {
-        ret = errno;
-        goto free;
-    }
-
-    len = fread(val, len, 1, f);
-    if (len != 1) {
-        ret = ferror(f);
-        goto close;
-    }
-
-close:
-    fclose(f);
-free:
-    free(path);
-    return ret;
-}
-#endif
-
 static void kvmppc_timer_hack(void *opaque)
 {
     qemu_notify_event();
diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h
index 7c08c0f..0c659c8 100644
--- a/target-ppc/kvm_ppc.h
+++ b/target-ppc/kvm_ppc.h
@@ -10,17 +10,6 @@
 #define __KVM_PPC_H__
 
 void kvmppc_init(void);
-#ifndef CONFIG_KVM
-static inline int kvmppc_read_host_property(const char *node_path, const char *prop,
-                                            void *val, size_t len)
-{
-    assert(0);
-    return -ENOSYS;
-}
-#else
-int kvmppc_read_host_property(const char *node_path, const char *prop,
-                                     void *val, size_t len);
-#endif
 
 uint32_t kvmppc_get_tbfreq(void);
 uint64_t kvmppc_get_clockfreq(void);
commit 7dadd40c89837a9c61d6bb24164a6c6b660d70a4
Author: Alexander Graf <agraf at suse.de>
Date:   Thu Jul 21 02:44:53 2011 +0200

    PPC: bamboo: Use kvm api for freq and clock frequencies
    
    Now that we have nice and shiny APIs to read out the host's clock and timebase
    frequencies, let's use them in the bamboo code as well!
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c
index 65d4f0f..1523764 100644
--- a/hw/ppc440_bamboo.c
+++ b/hw/ppc440_bamboo.c
@@ -31,38 +31,6 @@
 #define FDT_ADDR     0x1800000
 #define RAMDISK_ADDR 0x1900000
 
-#ifdef CONFIG_FDT
-static int bamboo_copy_host_cell(void *fdt, const char *node, const char *prop)
-{
-    uint32_t cell;
-    int ret;
-
-    ret = kvmppc_read_host_property(node, prop, &cell, sizeof(cell));
-    if (ret < 0) {
-        fprintf(stderr, "couldn't read host %s/%s\n", node, prop);
-        goto out;
-    }
-
-    ret = qemu_devtree_setprop_cell(fdt, node, prop, cell);
-    if (ret < 0) {
-        fprintf(stderr, "couldn't set guest %s/%s\n", node, prop);
-        goto out;
-    }
-
-out:
-    return ret;
-}
-
-static void bamboo_fdt_update(void *fdt)
-{
-    /* Copy data from the host device tree into the guest. Since the guest can
-     * directly access the timebase without host involvement, we must expose
-     * the correct frequencies. */
-    bamboo_copy_host_cell(fdt, "/cpus/cpu at 0", "clock-frequency");
-    bamboo_copy_host_cell(fdt, "/cpus/cpu at 0", "timebase-frequency");
-}
-#endif
-
 static int bamboo_load_device_tree(target_phys_addr_t addr,
                                      uint32_t ramsize,
                                      target_phys_addr_t initrd_base,
@@ -75,6 +43,8 @@ static int bamboo_load_device_tree(target_phys_addr_t addr,
     char *filename;
     int fdt_size;
     void *fdt;
+    uint32_t tb_freq = 400000000;
+    uint32_t clock_freq = 400000000;
 
     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
     if (!filename) {
@@ -108,10 +78,19 @@ static int bamboo_load_device_tree(target_phys_addr_t addr,
     if (ret < 0)
         fprintf(stderr, "couldn't set /chosen/bootargs\n");
 
+    /* Copy data from the host device tree into the guest. Since the guest can
+     * directly access the timebase without host involvement, we must expose
+     * the correct frequencies. */
     if (kvm_enabled()) {
-        bamboo_fdt_update(fdt);
+        tb_freq = kvmppc_get_tbfreq();
+        clock_freq = kvmppc_get_clockfreq();
     }
 
+    qemu_devtree_setprop_cell(fdt, "/cpus/cpu at 0", "clock-frequency",
+                              clock_freq);
+    qemu_devtree_setprop_cell(fdt, "/cpus/cpu at 0", "timebase-frequency",
+                              tb_freq);
+
     ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
     g_free(fdt);
 
commit 66ae790247f1f6c19cc651b64272bbb9cbfc328d
Author: Alexander Graf <agraf at suse.de>
Date:   Thu Jul 21 02:35:28 2011 +0200

    PPC: E500: Remove mpc8544_copy_soc_cell
    
    We don't need mpc8544_copy_soc_cell anymore, since we're explicitly reading
    host values and writing guest values respectively.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 8748531..2c7c677 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -56,30 +56,6 @@ struct boot_info
     uint32_t entry;
 };
 
-#ifdef CONFIG_FDT
-static int mpc8544_copy_soc_cell(void *fdt, const char *node, const char *prop)
-{
-    uint32_t cell;
-    int ret;
-
-    ret = kvmppc_read_host_property(node, prop, &cell, sizeof(cell));
-    if (ret < 0) {
-        fprintf(stderr, "couldn't read host %s/%s\n", node, prop);
-        goto out;
-    }
-
-    ret = qemu_devtree_setprop_cell(fdt, "/cpus/PowerPC,8544 at 0",
-                                prop, cell);
-    if (ret < 0) {
-        fprintf(stderr, "couldn't set guest /cpus/PowerPC,8544 at 0/%s\n", prop);
-        goto out;
-    }
-
-out:
-    return ret;
-}
-#endif
-
 static int mpc8544_load_device_tree(CPUState *env,
                                     target_phys_addr_t addr,
                                     uint32_t ramsize,
commit 911d6e7ad12514652601ee579b2e1201c1545fa1
Author: Alexander Graf <agraf at suse.de>
Date:   Thu Jul 21 02:34:11 2011 +0200

    PPC: E500: Use generic kvm function for freq
    
    Now that we have generic KVM functions to read out the host tb and clock
    frequencies, let's use them in the e500 code!
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 9cb01f3..8748531 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -14,8 +14,6 @@
  * (at your option) any later version.
  */
 
-#include <dirent.h>
-
 #include "config.h"
 #include "qemu-common.h"
 #include "net.h"
@@ -96,6 +94,9 @@ static int mpc8544_load_device_tree(CPUState *env,
     int fdt_size;
     void *fdt;
     uint8_t hypercall[16];
+    char cpu_name[128] = "/cpus/PowerPC,8544 at 0";
+    uint32_t clock_freq = 400000000;
+    uint32_t tb_freq = 400000000;
 
     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
     if (!filename) {
@@ -133,32 +134,9 @@ static int mpc8544_load_device_tree(CPUState *env,
         fprintf(stderr, "couldn't set /chosen/bootargs\n");
 
     if (kvm_enabled()) {
-        struct dirent *dirp;
-        DIR *dp;
-        char buf[128];
-
-        if ((dp = opendir("/proc/device-tree/cpus/")) == NULL) {
-            printf("Can't open directory /proc/device-tree/cpus/\n");
-            ret = -1;
-            goto out;
-        }
-
-        buf[0] = '\0';
-        while ((dirp = readdir(dp)) != NULL) {
-            if (strncmp(dirp->d_name, "PowerPC", 7) == 0) {
-                snprintf(buf, 128, "/cpus/%s", dirp->d_name);
-                break;
-            }
-        }
-        closedir(dp);
-        if (buf[0] == '\0') {
-            printf("Unknow host!\n");
-            ret = -1;
-            goto out;
-        }
-
-        mpc8544_copy_soc_cell(fdt, buf, "clock-frequency");
-        mpc8544_copy_soc_cell(fdt, buf, "timebase-frequency");
+        /* Read out host's frequencies */
+        clock_freq = kvmppc_get_clockfreq();
+        tb_freq = kvmppc_get_tbfreq();
 
         /* indicate KVM hypercall interface */
         qemu_devtree_setprop_string(fdt, "/hypervisor", "compatible",
@@ -166,15 +144,11 @@ static int mpc8544_load_device_tree(CPUState *env,
         kvmppc_get_hypercall(env, hypercall, sizeof(hypercall));
         qemu_devtree_setprop(fdt, "/hypervisor", "hcall-instructions",
                              hypercall, sizeof(hypercall));
-    } else {
-        const uint32_t freq = 400000000;
-
-        qemu_devtree_setprop_cell(fdt, "/cpus/PowerPC,8544 at 0",
-                                  "clock-frequency", freq);
-        qemu_devtree_setprop_cell(fdt, "/cpus/PowerPC,8544 at 0",
-                                  "timebase-frequency", freq);
     }
 
+    qemu_devtree_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
+    qemu_devtree_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
+
     ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
     g_free(fdt);
 
commit eadaada1ceb74f152dc9fe196bdda1b79c86275c
Author: Alexander Graf <agraf at suse.de>
Date:   Thu Jul 21 02:29:15 2011 +0200

    PPC: KVM: Add generic function to read host clockfreq
    
    We need to find out the host's clock-frequency when running on KVM, so
    let's export a respective function.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    
    ---
    
    v1 -> v2:
    
      - enable 64bit values

diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index 21f35af..77b98c4 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -14,6 +14,7 @@
  *
  */
 
+#include <dirent.h>
 #include <sys/types.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
@@ -38,6 +39,8 @@
     do { } while (0)
 #endif
 
+#define PROC_DEVTREE_CPU      "/proc/device-tree/cpus/"
+
 const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
     KVM_CAP_LAST_INFO
 };
@@ -509,6 +512,70 @@ uint32_t kvmppc_get_tbfreq(void)
     return retval;
 }
 
+/* Try to find a device tree node for a CPU with clock-frequency property */
+static int kvmppc_find_cpu_dt(char *buf, int buf_len)
+{
+    struct dirent *dirp;
+    DIR *dp;
+
+    if ((dp = opendir(PROC_DEVTREE_CPU)) == NULL) {
+        printf("Can't open directory " PROC_DEVTREE_CPU "\n");
+        return -1;
+    }
+
+    buf[0] = '\0';
+    while ((dirp = readdir(dp)) != NULL) {
+        FILE *f;
+        snprintf(buf, buf_len, "%s%s/clock-frequency", PROC_DEVTREE_CPU,
+                 dirp->d_name);
+        f = fopen(buf, "r");
+        if (f) {
+            snprintf(buf, buf_len, "%s%s", PROC_DEVTREE_CPU, dirp->d_name);
+            fclose(f);
+            break;
+        }
+        buf[0] = '\0';
+    }
+    closedir(dp);
+    if (buf[0] == '\0') {
+        printf("Unknown host!\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+uint64_t kvmppc_get_clockfreq(void)
+{
+    char buf[512];
+    uint32_t tb[2];
+    FILE *f;
+    int len;
+
+    if (kvmppc_find_cpu_dt(buf, sizeof(buf))) {
+        return 0;
+    }
+
+    strncat(buf, "/clock-frequency", sizeof(buf) - strlen(buf));
+
+    f = fopen(buf, "rb");
+    if (!f) {
+        return -1;
+    }
+
+    len = fread(tb, sizeof(tb[0]), 2, f);
+    fclose(f);
+    switch (len) {
+    case 1:
+        /* freq is only a single cell */
+        return tb[0];
+    case 2:
+        return *(uint64_t*)tb;
+    }
+
+    return 0;
+}
+
 int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len)
 {
     uint32_t *hc = (uint32_t*)buf;
diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h
index 2f32249..7c08c0f 100644
--- a/target-ppc/kvm_ppc.h
+++ b/target-ppc/kvm_ppc.h
@@ -23,6 +23,7 @@ int kvmppc_read_host_property(const char *node_path, const char *prop,
 #endif
 
 uint32_t kvmppc_get_tbfreq(void);
+uint64_t kvmppc_get_clockfreq(void);
 int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len);
 int kvmppc_set_interrupt(CPUState *env, int irq, int level);
 
commit a489f7f7111fb2e8aaf6a152731a5f1fe7e0c4b3
Author: Alexander Graf <agraf at suse.de>
Date:   Thu Jul 21 02:08:10 2011 +0200

    PPC: bamboo: Move host fdt copy to target
    
    We have some code in generic kvm_ppc.c that is only used by 440. Move to
    the 440 specific device code.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c
index 1addb68..65d4f0f 100644
--- a/hw/ppc440_bamboo.c
+++ b/hw/ppc440_bamboo.c
@@ -31,6 +31,38 @@
 #define FDT_ADDR     0x1800000
 #define RAMDISK_ADDR 0x1900000
 
+#ifdef CONFIG_FDT
+static int bamboo_copy_host_cell(void *fdt, const char *node, const char *prop)
+{
+    uint32_t cell;
+    int ret;
+
+    ret = kvmppc_read_host_property(node, prop, &cell, sizeof(cell));
+    if (ret < 0) {
+        fprintf(stderr, "couldn't read host %s/%s\n", node, prop);
+        goto out;
+    }
+
+    ret = qemu_devtree_setprop_cell(fdt, node, prop, cell);
+    if (ret < 0) {
+        fprintf(stderr, "couldn't set guest %s/%s\n", node, prop);
+        goto out;
+    }
+
+out:
+    return ret;
+}
+
+static void bamboo_fdt_update(void *fdt)
+{
+    /* Copy data from the host device tree into the guest. Since the guest can
+     * directly access the timebase without host involvement, we must expose
+     * the correct frequencies. */
+    bamboo_copy_host_cell(fdt, "/cpus/cpu at 0", "clock-frequency");
+    bamboo_copy_host_cell(fdt, "/cpus/cpu at 0", "timebase-frequency");
+}
+#endif
+
 static int bamboo_load_device_tree(target_phys_addr_t addr,
                                      uint32_t ramsize,
                                      target_phys_addr_t initrd_base,
@@ -76,8 +108,9 @@ static int bamboo_load_device_tree(target_phys_addr_t addr,
     if (ret < 0)
         fprintf(stderr, "couldn't set /chosen/bootargs\n");
 
-    if (kvm_enabled())
-        kvmppc_fdt_update(fdt);
+    if (kvm_enabled()) {
+        bamboo_fdt_update(fdt);
+    }
 
     ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
     g_free(fdt);
diff --git a/target-ppc/kvm_ppc.c b/target-ppc/kvm_ppc.c
index c031fcb..26ecc9d 100644
--- a/target-ppc/kvm_ppc.c
+++ b/target-ppc/kvm_ppc.c
@@ -54,36 +54,6 @@ free:
     free(path);
     return ret;
 }
-
-static int kvmppc_copy_host_cell(void *fdt, const char *node, const char *prop)
-{
-    uint32_t cell;
-    int ret;
-
-    ret = kvmppc_read_host_property(node, prop, &cell, sizeof(cell));
-    if (ret < 0) {
-        fprintf(stderr, "couldn't read host %s/%s\n", node, prop);
-        goto out;
-    }
-
-    ret = qemu_devtree_setprop_cell(fdt, node, prop, cell);
-    if (ret < 0) {
-        fprintf(stderr, "couldn't set guest %s/%s\n", node, prop);
-        goto out;
-    }
-
-out:
-    return ret;
-}
-
-void kvmppc_fdt_update(void *fdt)
-{
-    /* Copy data from the host device tree into the guest. Since the guest can
-     * directly access the timebase without host involvement, we must expose
-     * the correct frequencies. */
-    kvmppc_copy_host_cell(fdt, "/cpus/cpu at 0", "clock-frequency");
-    kvmppc_copy_host_cell(fdt, "/cpus/cpu at 0", "timebase-frequency");
-}
 #endif
 
 static void kvmppc_timer_hack(void *opaque)
diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h
index 45a1373..2f32249 100644
--- a/target-ppc/kvm_ppc.h
+++ b/target-ppc/kvm_ppc.h
@@ -10,7 +10,6 @@
 #define __KVM_PPC_H__
 
 void kvmppc_init(void);
-void kvmppc_fdt_update(void *fdt);
 #ifndef CONFIG_KVM
 static inline int kvmppc_read_host_property(const char *node_path, const char *prop,
                                             void *val, size_t len)
commit d69a8e6387adcd79c29666930bc64fffd2a3f456
Author: Alexander Graf <agraf at suse.de>
Date:   Thu Jul 21 01:52:57 2011 +0200

    device tree: add nop_node
    
    We have a qemu internal abstraction layer on FDT. While I'm not fully convinced
    we need it at all, it's missing the nop_node functionality that we now need
    on e500. So let's add it and think about the general future of that API later.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/device_tree.c b/device_tree.c
index 3a224d1..23e89e3 100644
--- a/device_tree.c
+++ b/device_tree.c
@@ -107,3 +107,14 @@ int qemu_devtree_setprop_string(void *fdt, const char *node_path,
 
     return fdt_setprop_string(fdt, offset, property, string);
 }
+
+int qemu_devtree_nop_node(void *fdt, const char *node_path)
+{
+    int offset;
+
+    offset = fdt_path_offset(fdt, node_path);
+    if (offset < 0)
+        return offset;
+
+    return fdt_nop_node(fdt, offset);
+}
diff --git a/device_tree.h b/device_tree.h
index cecd98f..76fce5f 100644
--- a/device_tree.h
+++ b/device_tree.h
@@ -22,5 +22,6 @@ int qemu_devtree_setprop_cell(void *fdt, const char *node_path,
                               const char *property, uint32_t val);
 int qemu_devtree_setprop_string(void *fdt, const char *node_path,
                                 const char *property, const char *string);
+int qemu_devtree_nop_node(void *fdt, const char *node_path);
 
 #endif /* __DEVICE_TREE_H__ */
commit a915249fa1e0a59e9a893cd335fd31af39b01bde
Author: Alexander Graf <agraf at suse.de>
Date:   Thu Jul 21 01:42:58 2011 +0200

    PPC: E500: Generate IRQ lines for many CPUs
    
    Now that we can generate multiple envs for all our virtual CPUs, we
    also need to tell the MPIC that we have multiple CPUs connected and
    connect them all to the respective virtual interrupt lines.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 8d05587..9cb01f3 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -237,7 +237,7 @@ static void mpc8544ds_init(ram_addr_t ram_size,
     target_long initrd_size=0;
     int i=0;
     unsigned int pci_irq_nrs[4] = {1, 2, 3, 4};
-    qemu_irq *irqs, *mpic;
+    qemu_irq **irqs, *mpic;
     DeviceState *dev;
     struct boot_info *boot_info;
     CPUState *firstenv = NULL;
@@ -247,6 +247,8 @@ static void mpc8544ds_init(ram_addr_t ram_size,
         cpu_model = "e500v2_v30";
     }
 
+    irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
+    irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
     for (i = 0; i < smp_cpus; i++) {
         qemu_irq *input;
         env = cpu_ppc_init(cpu_model);
@@ -259,6 +261,10 @@ static void mpc8544ds_init(ram_addr_t ram_size,
             firstenv = env;
         }
 
+        irqs[i] = irqs[0] + (i * OPENPIC_OUTPUT_NB);
+        input = (qemu_irq *)env->irq_inputs;
+        irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
+        irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
         env->spr[SPR_BOOKE_PIR] = env->cpu_index = i;
 
         /* XXX register timer? */
@@ -283,10 +289,11 @@ static void mpc8544ds_init(ram_addr_t ram_size,
                                  "mpc8544ds.ram", ram_size));
 
     /* MPIC */
-    irqs = g_malloc0(sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
-    irqs[OPENPIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPCE500_INPUT_INT];
-    irqs[OPENPIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPCE500_INPUT_CINT];
-    mpic = mpic_init(MPC8544_MPIC_REGS_BASE, 1, &irqs, NULL);
+    mpic = mpic_init(MPC8544_MPIC_REGS_BASE, smp_cpus, irqs, NULL);
+
+    if (!mpic) {
+        cpu_abort(env, "MPIC failed to initialize\n");
+    }
 
     /* Serial */
     if (serial_hds[0]) {
commit e61c36d58d31d0ce7e1e7674bc8f1d1fc8efadd1
Author: Alexander Graf <agraf at suse.de>
Date:   Thu Jul 21 01:41:16 2011 +0200

    PPC: E500: create multiple envs
    
    When creating a VM, we should go through smp_cpus and create a virtual CPU for
    every CPU the user requested. This patch adds support for that and moves some
    code around to make that more convenient.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 1274a3e..8d05587 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -226,7 +226,7 @@ static void mpc8544ds_init(ram_addr_t ram_size,
                          const char *cpu_model)
 {
     PCIBus *pci_bus;
-    CPUState *env;
+    CPUState *env = NULL;
     uint64_t elf_entry;
     uint64_t elf_lowaddr;
     target_phys_addr_t entry=0;
@@ -240,24 +240,40 @@ static void mpc8544ds_init(ram_addr_t ram_size,
     qemu_irq *irqs, *mpic;
     DeviceState *dev;
     struct boot_info *boot_info;
+    CPUState *firstenv = NULL;
 
-    /* Setup CPU */
+    /* Setup CPUs */
     if (cpu_model == NULL) {
         cpu_model = "e500v2_v30";
     }
 
-    env = cpu_ppc_init(cpu_model);
-    if (!env) {
-        fprintf(stderr, "Unable to initialize CPU!\n");
-        exit(1);
-    }
+    for (i = 0; i < smp_cpus; i++) {
+        qemu_irq *input;
+        env = cpu_ppc_init(cpu_model);
+        if (!env) {
+            fprintf(stderr, "Unable to initialize CPU!\n");
+            exit(1);
+        }
+
+        if (!firstenv) {
+            firstenv = env;
+        }
 
-    /* XXX register timer? */
-    ppc_emb_timers_init(env, 400000000, PPC_INTERRUPT_DECR);
-    ppc_dcr_init(env, NULL, NULL);
+        env->spr[SPR_BOOKE_PIR] = env->cpu_index = i;
 
-    /* Register reset handler */
-    qemu_register_reset(mpc8544ds_cpu_reset, env);
+        /* XXX register timer? */
+        ppc_emb_timers_init(env, 400000000, PPC_INTERRUPT_DECR);
+        ppc_dcr_init(env, NULL, NULL);
+        /* XXX Enable DEC interrupts - probably wrong in the backend */
+        env->spr[SPR_40x_TCR] = 1 << 26;
+
+        /* Register reset handler */
+        boot_info = g_malloc0(sizeof(struct boot_info));
+        qemu_register_reset(mpc8544ds_cpu_reset, env);
+        env->load_info = boot_info;
+    }
+
+    env = firstenv;
 
     /* Fixup Memory size on a alignment boundary */
     ram_size &= ~(RAM_SIZES_ALIGN - 1);
@@ -336,8 +352,6 @@ static void mpc8544ds_init(ram_addr_t ram_size,
         }
     }
 
-    boot_info = g_malloc0(sizeof(struct boot_info));
-
     /* If we're loading a kernel directly, we must load the device tree too. */
     if (kernel_filename) {
 #ifndef CONFIG_FDT
@@ -350,10 +364,10 @@ static void mpc8544ds_init(ram_addr_t ram_size,
             exit(1);
         }
 
+        boot_info = env->load_info;
         boot_info->entry = entry;
         boot_info->dt_base = dt_base;
     }
-    env->load_info = boot_info;
 
     if (kvm_enabled()) {
         kvmppc_init();
commit bbc5842211cdd90103cfe52f2ca24afac880694f
Author: Alexander Graf <agraf at suse.de>
Date:   Thu Jul 21 01:39:46 2011 +0200

    PPC: Bump MPIC up to 32 supported CPUs
    
    The MPIC emulation is now capable of handling up to 32 CPUs. Reflect that in
    the code exporting the numbers out and fix an integer overflow while at it.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    
    ---
    
    v1 -> v2:
    
      - Max cpus is 15 due to cINT routing
      - Report nb_cpus not MAX_CPUS in MPIC capabilities

diff --git a/hw/openpic.c b/hw/openpic.c
index 109c1bc..03e442b 100644
--- a/hw/openpic.c
+++ b/hw/openpic.c
@@ -63,7 +63,7 @@
 
 #elif defined(USE_MPCxxx)
 
-#define MAX_CPU     2
+#define MAX_CPU    15
 #define MAX_IRQ   128
 #define MAX_DBL     0
 #define MAX_MBX     0
@@ -507,7 +507,7 @@ static inline void write_IRQreg (openpic_t *opp, int n_IRQ,
         break;
     case IRQ_IDE:
         tmp = val & 0xC0000000;
-        tmp |= val & ((1 << MAX_CPU) - 1);
+        tmp |= val & ((1ULL << MAX_CPU) - 1);
         opp->src[n_IRQ].ide = tmp;
         DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide);
         break;
@@ -1283,7 +1283,7 @@ static void mpic_reset (void *opaque)
 
     mpp->glbc = 0x80000000;
     /* Initialise controller registers */
-    mpp->frep = 0x004f0002;
+    mpp->frep = 0x004f0002 | ((mpp->nb_cpus - 1) << 8);
     mpp->veni = VENI;
     mpp->pint = 0x00000000;
     mpp->spve = 0x0000FFFF;
@@ -1684,10 +1684,6 @@ qemu_irq *mpic_init (target_phys_addr_t base, int nb_cpus,
         {mpic_cpu_read, mpic_cpu_write, MPIC_CPU_REG_START, MPIC_CPU_REG_SIZE},
     };
 
-    /* XXX: for now, only one CPU is supported */
-    if (nb_cpus != 1)
-        return NULL;
-
     mpp = g_malloc0(sizeof(openpic_t));
 
     for (i = 0; i < sizeof(list)/sizeof(list[0]); i++) {
commit 0d33defbe3e75db75599c52607da6fc3b4ce0f25
Author: Alexander Graf <agraf at suse.de>
Date:   Sat Jul 23 11:27:53 2011 +0200

    PPC: MPIC: Fix CI bit definitions
    
    The bit definitions for critical interrupt routing are in PowerPC order
    (most significant bit is 0), while we end up shifting it with normal bit
    order. Turn the numbers around so we actually end up fetching the
    right ones.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/openpic.c b/hw/openpic.c
index dfec52e..109c1bc 100644
--- a/hw/openpic.c
+++ b/hw/openpic.c
@@ -131,11 +131,11 @@ enum {
 #define MPIC_CPU_REG_SIZE         0x100 + ((MAX_CPU - 1) * 0x1000)
 
 enum mpic_ide_bits {
-    IDR_EP     = 0,
-    IDR_CI0     = 1,
-    IDR_CI1     = 2,
-    IDR_P1     = 30,
-    IDR_P0     = 31,
+    IDR_EP     = 31,
+    IDR_CI0     = 30,
+    IDR_CI1     = 29,
+    IDR_P1     = 1,
+    IDR_P0     = 0,
 };
 
 #else
commit 3ee82442c53e342883eb6f05b1776b05892e336f
Author: Alexander Graf <agraf at suse.de>
Date:   Sat Jul 23 11:09:23 2011 +0200

    PPC: MPIC: Remove read functionality for WO registers
    
    The IPI dispatch registers are write only according to every MPIC
    spec I have found. So instead of pretending you could read back something
    from them, better not handle them at all.
    
    Reported-by: Elie Richa <richa at adacore.com>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/openpic.c b/hw/openpic.c
index 31ad175..dfec52e 100644
--- a/hw/openpic.c
+++ b/hw/openpic.c
@@ -952,13 +952,6 @@ static uint32_t openpic_cpu_read_internal(void *opaque, target_phys_addr_t addr,
     case 0xB0: /* PEOI */
         retval = 0;
         break;
-#if MAX_IPI > 0
-    case 0x40: /* IDE */
-    case 0x50:
-        idx = (addr - 0x40) >> 4;
-        retval = read_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IDE);
-        break;
-#endif
     default:
         break;
     }
commit 9250fd24a98af75f196480a75aacf99291ef46a9
Author: Alexander Graf <agraf at suse.de>
Date:   Sat Jul 23 11:05:35 2011 +0200

    PPC: Set MPIC IDE for IPI to 0
    
    We use the IDE register with IPIs as a mask to keep track which processors
    have already acknowledged the respective interrupt. So we need to initialize
    it to 0 to make sure that it doesn't accidently fire an IPI on CPU0 when the
    first IPI is triggered.
    
    Reported-by: Elie Richa <richa at adacore.com>
    Signed-off-by: Alexander Graf <agraf at suse.de>
    
    ---
    
    v2 -> v3:
    
      - fix IDE IPI reset

diff --git a/hw/openpic.c b/hw/openpic.c
index 9710ac0..31ad175 100644
--- a/hw/openpic.c
+++ b/hw/openpic.c
@@ -1299,6 +1299,10 @@ static void mpic_reset (void *opaque)
         mpp->src[i].ipvp = 0x80800000;
         mpp->src[i].ide  = 0x00000001;
     }
+    /* Set IDE for IPIs to 0 so we don't get spurious interrupts */
+    for (i = mpp->irq_ipi0; i < (mpp->irq_ipi0 + MAX_IPI); i++) {
+        mpp->src[i].ide = 0;
+    }
     /* Initialise IRQ destinations */
     for (i = 0; i < MAX_CPU; i++) {
         mpp->dst[i].pctp      = 0x0000000F;
commit a675155e2d78b083b47774c118990041333308b5
Author: Alexander Graf <agraf at suse.de>
Date:   Thu Jul 21 01:36:44 2011 +0200

    PPC: Fix IPI support in MPIC
    
    The current IPI support in the MPIC code is incomplete and doesn't work. This
    code adds proper support for IPIs in MPIC by using the IDE register to remember
    which CPUs IPIs are still outstanding to. New triggers through the IPI trigger
    register only add to the list of CPUs we want to IPI.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    
    ---
    
    v1 -> v2:
    
      - Use MAX_IPI instead of hardcoded 4
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/openpic.c b/hw/openpic.c
index f7d5583..9710ac0 100644
--- a/hw/openpic.c
+++ b/hw/openpic.c
@@ -57,7 +57,7 @@
 #define MAX_MBX     4
 #define MAX_TMR     4
 #define VECTOR_BITS 8
-#define MAX_IPI     0
+#define MAX_IPI     4
 
 #define VID (0x00000000)
 
@@ -840,7 +840,9 @@ static void openpic_cpu_write_internal(void *opaque, target_phys_addr_t addr,
     case 0x60:
     case 0x70:
         idx = (addr - 0x40) >> 4;
-        write_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IDE, val);
+        /* we use IDE as mask which CPUs to deliver the IPI to still. */
+        write_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IDE,
+                     opp->src[opp->irq_ipi0 + idx].ide | val);
         openpic_set_irq(opp, opp->irq_ipi0 + idx, 1);
         openpic_set_irq(opp, opp->irq_ipi0 + idx, 0);
         break;
@@ -934,6 +936,17 @@ static uint32_t openpic_cpu_read_internal(void *opaque, target_phys_addr_t addr,
                 reset_bit(&src->ipvp, IPVP_ACTIVITY);
                 src->pending = 0;
             }
+
+            if ((n_IRQ >= opp->irq_ipi0) &&  (n_IRQ < (opp->irq_ipi0 + MAX_IPI))) {
+                src->ide &= ~(1 << idx);
+                if (src->ide && !test_bit(&src->ipvp, IPVP_SENSE)) {
+                    /* trigger on CPUs that didn't know about it yet */
+                    openpic_set_irq(opp, n_IRQ, 1);
+                    openpic_set_irq(opp, n_IRQ, 0);
+                    /* if all CPUs knew about it, set active bit again */
+                    set_bit(&src->ipvp, IPVP_ACTIVITY);
+                }
+            }
         }
         break;
     case 0xB0: /* PEOI */
commit bc59d9c9163abbe3646a70bca5ff59e73e07904a
Author: Alexander Graf <agraf at suse.de>
Date:   Thu Jul 21 01:35:15 2011 +0200

    PPC: Extend MPIC MMIO range
    
    The MPIC exports a page for each CPU that it controls. To support more than
    one CPU, we need to also reserve the MMIO space according to the amount of
    CPUs we want to support.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/openpic.c b/hw/openpic.c
index cf89f23..f7d5583 100644
--- a/hw/openpic.c
+++ b/hw/openpic.c
@@ -128,7 +128,7 @@ enum {
 #define MPIC_MSI_REG_START        0x11C00
 #define MPIC_MSI_REG_SIZE         0x100
 #define MPIC_CPU_REG_START        0x20000
-#define MPIC_CPU_REG_SIZE         0x100
+#define MPIC_CPU_REG_SIZE         0x100 + ((MAX_CPU - 1) * 0x1000)
 
 enum mpic_ide_bits {
     IDR_EP     = 0,
commit 704c7e5d0f473bf6f268b18fdaada40e4b7ca964
Author: Alexander Graf <agraf at suse.de>
Date:   Thu Jul 21 01:33:29 2011 +0200

    PPC: Add CPU local MMIO regions to MPIC
    
    The MPIC exports a register set for each CPU connected to it. They can all
    be accessed through specific registers or using a shadow page that is mapped
    differently depending on which CPU accesses it.
    
    This patch implements the shadow map, making it possible for guests to access
    the CPU local registers using the same address on each CPU.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/openpic.c b/hw/openpic.c
index 26c96e2..cf89f23 100644
--- a/hw/openpic.c
+++ b/hw/openpic.c
@@ -2,6 +2,7 @@
  * OpenPIC emulation
  *
  * Copyright (c) 2004 Jocelyn Mayer
+ *               2011 Alexander Graf
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -161,6 +162,16 @@ static inline int test_bit (uint32_t *field, int bit)
     return (field[bit >> 5] & 1 << (bit & 0x1F)) != 0;
 }
 
+static int get_current_cpu(void)
+{
+  return cpu_single_env->cpu_index;
+}
+
+static uint32_t openpic_cpu_read_internal(void *opaque, target_phys_addr_t addr,
+                                          int idx);
+static void openpic_cpu_write_internal(void *opaque, target_phys_addr_t addr,
+                                       uint32_t val, int idx);
+
 enum {
     IRQ_EXTERNAL = 0x01,
     IRQ_INTERNAL = 0x02,
@@ -590,18 +601,27 @@ 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;
-    addr &= 0xFF;
     switch (addr) {
-    case 0x00: /* FREP */
+    case 0x40:
+    case 0x50:
+    case 0x60:
+    case 0x70:
+    case 0x80:
+    case 0x90:
+    case 0xA0:
+    case 0xB0:
+        openpic_cpu_write_internal(opp, addr, val, get_current_cpu());
+        break;
+    case 0x1000: /* FREP */
         break;
-    case 0x20: /* GLBC */
+    case 0x1020: /* GLBC */
         if (val & 0x80000000 && opp->reset)
             opp->reset(opp);
         opp->glbc = val & ~0x80000000;
         break;
-    case 0x80: /* VENI */
+    case 0x1080: /* VENI */
         break;
-    case 0x90: /* PINT */
+    case 0x1090: /* PINT */
         for (idx = 0; idx < opp->nb_cpus; idx++) {
             if ((val & (1 << idx)) && !(opp->pint & (1 << idx))) {
                 DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx);
@@ -615,22 +635,20 @@ static void openpic_gbl_write (void *opaque, target_phys_addr_t addr, uint32_t v
         }
         opp->pint = val;
         break;
-#if MAX_IPI > 0
-    case 0xA0: /* IPI_IPVP */
-    case 0xB0:
-    case 0xC0:
-    case 0xD0:
+    case 0x10A0: /* IPI_IPVP */
+    case 0x10B0:
+    case 0x10C0:
+    case 0x10D0:
         {
             int idx;
-            idx = (addr - 0xA0) >> 4;
+            idx = (addr - 0x10A0) >> 4;
             write_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IPVP, val);
         }
         break;
-#endif
-    case 0xE0: /* SPVE */
+    case 0x10E0: /* SPVE */
         opp->spve = val & 0x000000FF;
         break;
-    case 0xF0: /* TIFR */
+    case 0x10F0: /* TIFR */
         opp->tifr = val;
         break;
     default:
@@ -647,36 +665,43 @@ static uint32_t openpic_gbl_read (void *opaque, target_phys_addr_t addr)
     retval = 0xFFFFFFFF;
     if (addr & 0xF)
         return retval;
-    addr &= 0xFF;
     switch (addr) {
-    case 0x00: /* FREP */
+    case 0x1000: /* FREP */
         retval = opp->frep;
         break;
-    case 0x20: /* GLBC */
+    case 0x1020: /* GLBC */
         retval = opp->glbc;
         break;
-    case 0x80: /* VENI */
+    case 0x1080: /* VENI */
         retval = opp->veni;
         break;
-    case 0x90: /* PINT */
+    case 0x1090: /* PINT */
         retval = 0x00000000;
         break;
-#if MAX_IPI > 0
-    case 0xA0: /* IPI_IPVP */
+    case 0x40:
+    case 0x50:
+    case 0x60:
+    case 0x70:
+    case 0x80:
+    case 0x90:
+    case 0xA0:
     case 0xB0:
-    case 0xC0:
-    case 0xD0:
+        retval = openpic_cpu_read_internal(opp, addr, get_current_cpu());
+        break;
+    case 0x10A0: /* IPI_IPVP */
+    case 0x10B0:
+    case 0x10C0:
+    case 0x10D0:
         {
             int idx;
-            idx = (addr - 0xA0) >> 4;
+            idx = (addr - 0x10A0) >> 4;
             retval = read_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IPVP);
         }
         break;
-#endif
-    case 0xE0: /* SPVE */
+    case 0x10E0: /* SPVE */
         retval = opp->spve;
         break;
-    case 0xF0: /* TIFR */
+    case 0x10F0: /* TIFR */
         retval = opp->tifr;
         break;
     default:
@@ -794,23 +819,23 @@ static uint32_t openpic_src_read (void *opaque, uint32_t addr)
     return retval;
 }
 
-static void openpic_cpu_write (void *opaque, target_phys_addr_t addr, uint32_t val)
+static void openpic_cpu_write_internal(void *opaque, target_phys_addr_t addr,
+                                       uint32_t val, int idx)
 {
     openpic_t *opp = opaque;
     IRQ_src_t *src;
     IRQ_dst_t *dst;
-    int idx, s_IRQ, n_IRQ;
+    int s_IRQ, n_IRQ;
 
-    DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
+    DPRINTF("%s: cpu %d addr " TARGET_FMT_plx " <= %08x\n", __func__, idx,
+            addr, val);
     if (addr & 0xF)
         return;
-    addr &= 0x1FFF0;
-    idx = addr / 0x1000;
     dst = &opp->dst[idx];
     addr &= 0xFF0;
     switch (addr) {
 #if MAX_IPI > 0
-    case 0x40: /* PIPD */
+    case 0x40: /* IPIDR */
     case 0x50:
     case 0x60:
     case 0x70:
@@ -852,20 +877,24 @@ static void openpic_cpu_write (void *opaque, target_phys_addr_t addr, uint32_t v
     }
 }
 
-static uint32_t openpic_cpu_read (void *opaque, target_phys_addr_t addr)
+static void openpic_cpu_write(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    openpic_cpu_write_internal(opaque, addr, val, (addr & 0x1f000) >> 12);
+}
+
+static uint32_t openpic_cpu_read_internal(void *opaque, target_phys_addr_t addr,
+                                          int idx)
 {
     openpic_t *opp = opaque;
     IRQ_src_t *src;
     IRQ_dst_t *dst;
     uint32_t retval;
-    int idx, n_IRQ;
+    int n_IRQ;
 
-    DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+    DPRINTF("%s: cpu %d addr " TARGET_FMT_plx "\n", __func__, idx, addr);
     retval = 0xFFFFFFFF;
     if (addr & 0xF)
         return retval;
-    addr &= 0x1FFF0;
-    idx = addr / 0x1000;
     dst = &opp->dst[idx];
     addr &= 0xFF0;
     switch (addr) {
@@ -925,6 +954,11 @@ static uint32_t openpic_cpu_read (void *opaque, target_phys_addr_t addr)
     return retval;
 }
 
+static uint32_t openpic_cpu_read(void *opaque, target_phys_addr_t addr)
+{
+    return openpic_cpu_read_internal(opaque, addr, (addr & 0x1f000) >> 12);
+}
+
 static void openpic_buggy_write (void *opaque,
                                  target_phys_addr_t addr, uint32_t val)
 {
commit d751dfb313d3fd4feca60e305dd9904fec189d3f
Author: Alexander Graf <agraf at suse.de>
Date:   Thu Jul 21 00:49:45 2011 +0200

    PPC: Move openpic to target specific code compilation
    
    The MPIC has some funny feature where it maps different registers to an MMIO
    region depending which CPU accesses them.
    
    To be able to reflect that, we need to make OpenPIC be compiled in the target
    code, so it can access cpu_single_env.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/Makefile.objs b/Makefile.objs
index 8d23fbb..c849e51 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -222,7 +222,6 @@ hw-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o
 hw-obj-$(CONFIG_USB_REDIR) += usb-redir.o
 
 # PPC devices
-hw-obj-$(CONFIG_OPENPIC) += openpic.o
 hw-obj-$(CONFIG_PREP_PCI) += prep_pci.o
 # Mac shared devices
 hw-obj-$(CONFIG_MACIO) += macio.o
diff --git a/Makefile.target b/Makefile.target
index 88d2f1f..8db9f37 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -252,6 +252,8 @@ obj-ppc-y += ppce500_mpc8544ds.o mpc8544_guts.o
 obj-ppc-y += virtex_ml507.o
 obj-ppc-$(CONFIG_KVM) += kvm_ppc.o
 obj-ppc-$(CONFIG_FDT) += device_tree.o
+# PowerPC OpenPIC
+obj-ppc-y += openpic.o
 
 # Xilinx PPC peripherals
 obj-ppc-y += xilinx_intc.o
commit 416343b144cb6a5d73b381e56f452fdbd5992522
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu May 26 11:52:46 2011 +0200

    spapr: make irq customizable via qdev
    
    This also lets the user see the irq in "info qtree".
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Cc: Alexander Graf <agraf at suse.de>
    Cc: David Gibson <david at gibson.dropbear.id.au>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index ba2e1c1..0546ccb 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -52,6 +52,10 @@
 static struct BusInfo spapr_vio_bus_info = {
     .name       = "spapr-vio",
     .size       = sizeof(VIOsPAPRBus),
+    .props = (Property[]) {
+        DEFINE_PROP_UINT32("irq", VIOsPAPRDevice, vio_irq_num, 0), \
+        DEFINE_PROP_END_OF_LIST(),
+    },
 };
 
 VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg)
@@ -604,7 +608,9 @@ static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo)
     }
 
     dev->qdev.id = id;
-    dev->vio_irq_num = bus->irq++;
+    if (!dev->vio_irq_num) {
+        dev->vio_irq_num = bus->irq++;
+    }
     dev->qirq = spapr_find_qirq(spapr, dev->vio_irq_num);
 
     rtce_init(dev);
commit 77c7ea5ebbcf494f36f243d786e5f8409d7a4b85
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu May 26 11:52:45 2011 +0200

    spapr: prepare for qdevification of irq
    
    Restructure common properties for sPAPR devices so that IRQ definitions
    can be added in one place.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Cc: Alexander Graf <agraf at suse.de>
    Cc: David Gibson <david at gibson.dropbear.id.au>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c
index 2597748..abe1297 100644
--- a/hw/spapr_llan.c
+++ b/hw/spapr_llan.c
@@ -495,9 +495,7 @@ static VIOsPAPRDeviceInfo spapr_vlan = {
     .qdev.name = "spapr-vlan",
     .qdev.size = sizeof(VIOsPAPRVLANDevice),
     .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("reg", VIOsPAPRDevice, reg, 0x1000),
-        DEFINE_PROP_UINT32("dma-window", VIOsPAPRDevice, rtce_window_size,
-                           0x10000000),
+        DEFINE_SPAPR_PROPERTIES(VIOsPAPRVLANDevice, sdev, 0x1000, 0x10000000),
         DEFINE_NIC_PROPERTIES(VIOsPAPRVLANDevice, nicconf),
         DEFINE_PROP_END_OF_LIST(),
     },
diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h
index faa5d94..7eb5367 100644
--- a/hw/spapr_vio.h
+++ b/hw/spapr_vio.h
@@ -60,6 +60,11 @@ typedef struct VIOsPAPRDevice {
     VIOsPAPR_CRQ crq;
 } VIOsPAPRDevice;
 
+#define DEFINE_SPAPR_PROPERTIES(type, field, default_reg, default_dma_window) \
+        DEFINE_PROP_UINT32("reg", type, field.reg, default_reg), \
+        DEFINE_PROP_UINT32("dma-window", type, field.rtce_window_size, \
+                           default_dma_window)
+
 typedef struct VIOsPAPRBus {
     BusState bus;
     int irq;
diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c
index d2d0415..6fc82f6 100644
--- a/hw/spapr_vscsi.c
+++ b/hw/spapr_vscsi.c
@@ -930,9 +930,7 @@ static VIOsPAPRDeviceInfo spapr_vscsi = {
     .qdev.name = "spapr-vscsi",
     .qdev.size = sizeof(VSCSIState),
     .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("reg", VIOsPAPRDevice, reg, 0x2000),
-        DEFINE_PROP_UINT32("dma-window", VIOsPAPRDevice,
-                           rtce_window_size, 0x10000000),
+        DEFINE_SPAPR_PROPERTIES(VSCSIState, vdev, 0x2000, 0x10000000),
         DEFINE_PROP_END_OF_LIST(),
     },
 };
diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c
index 607b81b..a9d4b03 100644
--- a/hw/spapr_vty.c
+++ b/hw/spapr_vty.c
@@ -140,7 +140,7 @@ static VIOsPAPRDeviceInfo spapr_vty = {
     .qdev.name = "spapr-vty",
     .qdev.size = sizeof(VIOsPAPRVTYDevice),
     .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT32("reg", VIOsPAPRDevice, reg, 0),
+        DEFINE_SPAPR_PROPERTIES(VIOsPAPRVTYDevice, sdev, 0, 0),
         DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev),
         DEFINE_PROP_END_OF_LIST(),
     },
commit 277f9acf79bbf3affb98200c92a4aedaa3234083
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu May 26 11:52:44 2011 +0200

    spapr: proper qdevification
    
    Right now the spapr devices cannot be instantiated with -device,
    because the IRQs need to be passed to the spapr_*_create functions.
    Do this instead in the bus's init wrapper.
    
    This is particularly important with the conversion from scsi-disk
    to scsi-{cd,hd} that Markus made.  After his patches, if you
    specify a scsi-cd device attached to an if=none drive, the default
    VSCSI controller will not be created and, without qdevification,
    you will not be able to add yours.
    
    NOTE from agraf: added small compile fix
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Cc: Alexander Graf <agraf at suse.de>
    Cc: David Gibson <david at gibson.dropbear.id.au>
    Signed-off-by: Alexander Graf <agraf at suse.de>

diff --git a/hw/spapr.c b/hw/spapr.c
index 1265cee..8cf93fe 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -298,7 +298,6 @@ static void ppc_spapr_init(ram_addr_t ram_size,
     long kernel_size, initrd_size, fw_size;
     long pteg_shift = 17;
     char *filename;
-    int irq = 16;
 
     spapr = g_malloc(sizeof(*spapr));
     cpu_ppc_hypercall = emulate_spapr_hypercall;
@@ -360,15 +359,14 @@ static void ppc_spapr_init(ram_addr_t ram_size,
     /* Set up VIO bus */
     spapr->vio_bus = spapr_vio_bus_init();
 
-    for (i = 0; i < MAX_SERIAL_PORTS; i++, irq++) {
+    for (i = 0; i < MAX_SERIAL_PORTS; i++) {
         if (serial_hds[i]) {
             spapr_vty_create(spapr->vio_bus, SPAPR_VTY_BASE_ADDRESS + i,
-                             serial_hds[i], xics_find_qirq(spapr->icp, irq),
-                             irq);
+                             serial_hds[i]);
         }
     }
 
-    for (i = 0; i < nb_nics; i++, irq++) {
+    for (i = 0; i < nb_nics; i++) {
         NICInfo *nd = &nd_table[i];
 
         if (!nd->model) {
@@ -376,8 +374,7 @@ static void ppc_spapr_init(ram_addr_t ram_size,
         }
 
         if (strcmp(nd->model, "ibmveth") == 0) {
-            spapr_vlan_create(spapr->vio_bus, 0x1000 + i, nd,
-                              xics_find_qirq(spapr->icp, irq), irq);
+            spapr_vlan_create(spapr->vio_bus, 0x1000 + i, nd);
         } else {
             fprintf(stderr, "pSeries (sPAPR) platform does not support "
                     "NIC model '%s' (only ibmveth is supported)\n",
@@ -387,9 +384,7 @@ static void ppc_spapr_init(ram_addr_t ram_size,
     }
 
     for (i = 0; i <= drive_get_max_bus(IF_SCSI); i++) {
-        spapr_vscsi_create(spapr->vio_bus, 0x2000 + i,
-                           xics_find_qirq(spapr->icp, irq), irq);
-        irq++;
+        spapr_vscsi_create(spapr->vio_bus, 0x2000 + i);
     }
 
     if (kernel_filename) {
diff --git a/hw/spapr.h b/hw/spapr.h
index 263691b..009c459 100644
--- a/hw/spapr.h
+++ b/hw/spapr.h
@@ -1,6 +1,8 @@
 #if !defined(__HW_SPAPR_H__)
 #define __HW_SPAPR_H__
 
+#include "hw/xics.h"
+
 struct VIOsPAPRBus;
 struct icp_state;
 
@@ -278,6 +280,12 @@ void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn);
 target_ulong spapr_hypercall(CPUState *env, target_ulong opcode,
                              target_ulong *args);
 
+static inline qemu_irq spapr_find_qirq(sPAPREnvironment *spapr,
+                                        int irq_num)
+{
+    return xics_find_qirq(spapr->icp, irq_num);
+}
+
 static inline uint32_t rtas_ld(target_ulong phys, int n)
 {
     return ldl_be_phys(phys + 4*n);
diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c
index c18efc7..2597748 100644
--- a/hw/spapr_llan.c
+++ b/hw/spapr_llan.c
@@ -195,11 +195,9 @@ static int spapr_vlan_init(VIOsPAPRDevice *sdev)
     return 0;
 }
 
-void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd,
-                       qemu_irq qirq, uint32_t vio_irq_num)
+void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd)
 {
     DeviceState *dev;
-    VIOsPAPRDevice *sdev;
 
     dev = qdev_create(&bus->bus, "spapr-vlan");
     qdev_prop_set_uint32(dev, "reg", reg);
@@ -207,9 +205,6 @@ void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd,
     qdev_set_nic_properties(dev, nd);
 
     qdev_init_nofail(dev);
-    sdev = (VIOsPAPRDevice *)dev;
-    sdev->qirq = qirq;
-    sdev->vio_irq_num = vio_irq_num;
 }
 
 static int spapr_vlan_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index ce6558b..ba2e1c1 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -32,6 +32,7 @@
 
 #include "hw/spapr.h"
 #include "hw/spapr_vio.h"
+#include "hw/xics.h"
 
 #ifdef CONFIG_FDT
 #include <libfdt.h>
@@ -595,6 +596,7 @@ static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo)
 {
     VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo;
     VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
+    VIOsPAPRBus *bus = DO_UPCAST(VIOsPAPRBus, bus, dev->qdev.parent_bus);
     char *id;
 
     if (asprintf(&id, "%s@%x", info->dt_name, dev->reg) < 0) {
@@ -602,6 +604,8 @@ static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo)
     }
 
     dev->qdev.id = id;
+    dev->vio_irq_num = bus->irq++;
+    dev->qirq = spapr_find_qirq(spapr, dev->vio_irq_num);
 
     rtce_init(dev);
 
@@ -656,6 +660,7 @@ VIOsPAPRBus *spapr_vio_bus_init(void)
 
     qbus = qbus_create(&spapr_vio_bus_info, dev, "spapr-vio");
     bus = DO_UPCAST(VIOsPAPRBus, bus, qbus);
+    bus->irq = 16;
 
     /* hcall-vio */
     spapr_register_hypercall(H_VIO_SIGNAL, h_vio_signal);
diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h
index 603a8c4..faa5d94 100644
--- a/hw/spapr_vio.h
+++ b/hw/spapr_vio.h
@@ -62,6 +62,7 @@ typedef struct VIOsPAPRDevice {
 
 typedef struct VIOsPAPRBus {
     BusState bus;
+    int irq;
 } VIOsPAPRBus;
 
 typedef struct {
@@ -98,15 +99,9 @@ uint64_t ldq_tce(VIOsPAPRDevice *dev, uint64_t taddr);
 int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq);
 
 void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len);
-void spapr_vty_create(VIOsPAPRBus *bus,
-                      uint32_t reg, CharDriverState *chardev,
-                      qemu_irq qirq, uint32_t vio_irq_num);
-
-void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd,
-                       qemu_irq qirq, uint32_t vio_irq_num);
-
-void spapr_vscsi_create(VIOsPAPRBus *bus, uint32_t reg,
-                        qemu_irq qirq, uint32_t vio_irq_num);
+void spapr_vty_create(VIOsPAPRBus *bus, uint32_t reg, CharDriverState *chardev);
+void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd);
+void spapr_vscsi_create(VIOsPAPRBus *bus, uint32_t reg);
 
 int spapr_tce_set_bypass(uint32_t unit, uint32_t enable);
 void spapr_vio_quiesce(void);
diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c
index fc9ac6a..d2d0415 100644
--- a/hw/spapr_vscsi.c
+++ b/hw/spapr_vscsi.c
@@ -893,20 +893,14 @@ static int spapr_vscsi_init(VIOsPAPRDevice *dev)
     return 0;
 }
 
-void spapr_vscsi_create(VIOsPAPRBus *bus, uint32_t reg,
-                        qemu_irq qirq, uint32_t vio_irq_num)
+void spapr_vscsi_create(VIOsPAPRBus *bus, uint32_t reg)
 {
     DeviceState *dev;
-    VIOsPAPRDevice *sdev;
 
     dev = qdev_create(&bus->bus, "spapr-vscsi");
     qdev_prop_set_uint32(dev, "reg", reg);
 
     qdev_init_nofail(dev);
-
-    sdev = (VIOsPAPRDevice *)dev;
-    sdev->qirq = qirq;
-    sdev->vio_irq_num = vio_irq_num;
 }
 
 static int spapr_vscsi_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c
index f5046d9..607b81b 100644
--- a/hw/spapr_vty.c
+++ b/hw/spapr_vty.c
@@ -115,20 +115,14 @@ static target_ulong h_get_term_char(CPUState *env, sPAPREnvironment *spapr,
     return H_SUCCESS;
 }
 
-void spapr_vty_create(VIOsPAPRBus *bus,
-                      uint32_t reg, CharDriverState *chardev,
-                      qemu_irq qirq, uint32_t vio_irq_num)
+void spapr_vty_create(VIOsPAPRBus *bus, uint32_t reg, CharDriverState *chardev)
 {
     DeviceState *dev;
-    VIOsPAPRDevice *sdev;
 
     dev = qdev_create(&bus->bus, "spapr-vty");
     qdev_prop_set_uint32(dev, "reg", reg);
     qdev_prop_set_chr(dev, "chardev", chardev);
     qdev_init_nofail(dev);
-    sdev = (VIOsPAPRDevice *)dev;
-    sdev->qirq = qirq;
-    sdev->vio_irq_num = vio_irq_num;
 }
 
 static void vty_hcalls(VIOsPAPRBus *bus)
commit e4fc8781db7c49b0c5ac5d24762e17c59dfe0871
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Fri Sep 30 11:39:11 2011 +0100

    qed: fix use-after-free during l2 cache commit
    
    QED's metadata caching strategy allows two parallel requests to race for
    metadata lookup.  The first one to complete will populate the metadata
    cache and the second one will drop the data it just read in favor of the
    cached data.
    
    There is a use-after-free in qed_read_l2_table_cb() and
    qed_commit_l2_update() where l2_table->offset was used after the
    l2_table may have been freed due to a metadata lookup race.  Fix this by
    keeping the l2_offset in a local variable and not reaching into the
    possibly freed l2_table.
    
    Reported-by: Amit Shah <amit.shah at redhat.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/block/qed-table.c b/block/qed-table.c
index d96afa8..f31f9ff 100644
--- a/block/qed-table.c
+++ b/block/qed-table.c
@@ -222,21 +222,21 @@ static void qed_read_l2_table_cb(void *opaque, int ret)
     QEDRequest *request = read_l2_table_cb->request;
     BDRVQEDState *s = read_l2_table_cb->s;
     CachedL2Table *l2_table = request->l2_table;
+    uint64_t l2_offset = read_l2_table_cb->l2_offset;
 
     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;
+        l2_table->offset = 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);
+        request->l2_table = qed_find_l2_cache_entry(&s->l2_cache, l2_offset);
         assert(request->l2_table != NULL);
     }
 
diff --git a/block/qed.c b/block/qed.c
index 624e261..e87dc4d 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -911,14 +911,14 @@ 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;
+    uint64_t l2_offset = l2_table->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.
      */
-    acb->request.l2_table = qed_find_l2_cache_entry(&s->l2_cache,
-                                                    l2_table->offset);
+    acb->request.l2_table = qed_find_l2_cache_entry(&s->l2_cache, l2_offset);
     assert(acb->request.l2_table != NULL);
 
     qed_aio_next_io(opaque, ret);
commit ca8a277ccc911ce8501b1bc984a09f988379d8c3
Author: Stefan Weil <sw at weilnetz.de>
Date:   Mon Oct 3 22:43:19 2011 +0200

    linux-user: Remove unused code
    
    The code is unused since 8 years, so remove it.
    
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/linux-user/signal.c b/linux-user/signal.c
index 89276eb..40c5eb1 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -1274,10 +1274,7 @@ setup_return(CPUState *env, struct target_sigaction *ka,
 
 		if (__put_user(retcodes[idx], rc))
 			return 1;
-#if 0
-		flush_icache_range((abi_ulong)rc,
-				   (abi_ulong)(rc + 1));
-#endif
+
 		retcode = rc_addr + thumb;
 	}
 
commit 5354d08312c1fdc752a498a9857e913a890c4e10
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Sun Oct 2 18:53:09 2011 +0200

    Fix mismatching allocation and deallocation
    
    This error was reported by cppcheck.
    
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/console.c b/console.c
index 6dfcc47..e43de92 100644
--- a/console.c
+++ b/console.c
@@ -1538,7 +1538,7 @@ int text_console_init(QemuOpts *opts, CharDriverState **_chr)
     }
 
     if (!s) {
-        free(chr);
+        g_free(chr);
         return -EBUSY;
     }
 
commit 297d1b4e9ddff27067e773d0945362622415fd76
Author: Andreas Färber <andreas.faerber at web.de>
Date:   Sun Oct 2 18:35:48 2011 +0200

    target-arm: Fix typo
    
    The command line option is called -kernel, not -kenrel.
    
    Cc: Paul Brook <paul at codesourcery.com>
    Reviewed-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Andreas Färber <andreas.faerber at web.de>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/target-arm/helper.c b/target-arm/helper.c
index d3a3ba2..e2428eb 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -298,7 +298,7 @@ void cpu_reset(CPUARMState *env)
         if (rom) {
             /* We should really use ldl_phys here, in case the guest
                modified flash and reset itself.  However images
-               loaded via -kenrel have not been copied yet, so load the
+               loaded via -kernel have not been copied yet, so load the
                values directly from there.  */
             env->regs[13] = ldl_p(rom);
             pc = ldl_p(rom + 4);
commit 4789bc39aafb56c0a30e74fc5848e8ae05ae015c
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Mon Sep 26 11:30:49 2011 +0200

    lsi: Fix tag reference in debug print
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index 75a03a7..e077ec0 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -697,7 +697,7 @@ static int lsi_queue_req(LSIState *s, SCSIRequest *req, uint32_t len)
         lsi_reselect(s, p);
         return 0;
     } else {
-        DPRINTF("Queueing IO tag=0x%x\n", tag);
+        DPRINTF("Queueing IO tag=0x%x\n", p->tag);
         p->pending = len;
         return 1;
     }
commit f6c610653799749cdb5bcd4799ca3ef61b974eb7
Author: Antony Pavlov <antonynpavlov at gmail.com>
Date:   Mon Sep 26 09:02:38 2011 +0400

    gt64xxx.c: remove reference to non-existing ISD_handle field
    
    The commit fc2bf44972349b078d8310466c3866615500e67f
    removed ISD_handle field from struct GT64120State,
    so remove the field from DPRINTF too.
    
    Signed-off-by: Antony Pavlov <antonynpavlov at gmail.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c
index 73454ff..432683a 100644
--- a/hw/gt64xxx.c
+++ b/hw/gt64xxx.c
@@ -275,8 +275,9 @@ static void gt64120_isd_mapping(GT64120State *s)
     check_reserved_space(&start, &length);
     length = 0x1000;
     /* Map new address */
-    DPRINTF("ISD: "TARGET_FMT_plx"@"TARGET_FMT_plx" -> "TARGET_FMT_plx"@"TARGET_FMT_plx", %x\n", s->ISD_length, s->ISD_start,
-            length, start, s->ISD_handle);
+    DPRINTF("ISD: "TARGET_FMT_plx"@"TARGET_FMT_plx
+        " -> "TARGET_FMT_plx"@"TARGET_FMT_plx"\n",
+        s->ISD_length, s->ISD_start, length, start);
     s->ISD_start = start;
     s->ISD_length = length;
     memory_region_add_subregion(get_system_memory(), s->ISD_start, &s->ISD_mem);
commit ce8d2800f7858a3847a585d23a3e5e56bedf4e65
Author: Antony Pavlov <antonynpavlov at gmail.com>
Date:   Mon Sep 26 09:02:37 2011 +0400

    gt64xxx.c: fix length modifier in DPRINTF format string
    
    The commit fc2bf44972349b078d8310466c3866615500e67f
    changed the type of val argument of the function gt64120_writel()
    from uint32_t to uint64_t, so we need to change the corresponding
    length modifier from "%x" to "%" PRIx64.
    
    Signed-off-by: Antony Pavlov <antonynpavlov at gmail.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c
index 1c34253..73454ff 100644
--- a/hw/gt64xxx.c
+++ b/hw/gt64xxx.c
@@ -543,19 +543,19 @@ static void gt64120_writel (void *opaque, target_phys_addr_t addr,
         /* not really implemented */
         s->regs[saddr] = ~(~(s->regs[saddr]) | ~(val & 0xfffffffe));
         s->regs[saddr] |= !!(s->regs[saddr] & 0xfffffffe);
-        DPRINTF("INTRCAUSE %x\n", val);
+        DPRINTF("INTRCAUSE %" PRIx64 "\n", val);
         break;
     case GT_INTRMASK:
         s->regs[saddr] = val & 0x3c3ffffe;
-        DPRINTF("INTRMASK %x\n", val);
+        DPRINTF("INTRMASK %" PRIx64 "\n", val);
         break;
     case GT_PCI0_ICMASK:
         s->regs[saddr] = val & 0x03fffffe;
-        DPRINTF("ICMASK %x\n", val);
+        DPRINTF("ICMASK %" PRIx64 "\n", val);
         break;
     case GT_PCI0_SERR0MASK:
         s->regs[saddr] = val & 0x0000003f;
-        DPRINTF("SERR0MASK %x\n", val);
+        DPRINTF("SERR0MASK %" PRIx64 "\n", val);
         break;
 
     /* Reserved when only PCI_0 is configured. */
commit 8cf28bcaf182a52be8890f4bceb88aca6f0b23cc
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Sep 22 19:08:47 2011 +0200

    makefile: extract tools-obj-y
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/Makefile b/Makefile
index 6ed3194..5723108 100644
--- a/Makefile
+++ b/Makefile
@@ -145,11 +145,12 @@ endif
 qemu-img.o: qemu-img-cmds.h
 qemu-img.o qemu-tool.o qemu-nbd.o qemu-io.o cmd.o qemu-ga.o: $(GENERATED_HEADERS)
 
-qemu-img$(EXESUF): qemu-img.o qemu-tool.o qemu-error.o $(oslib-obj-y) $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) qemu-timer-common.o
+tools-obj-y = qemu-tool.o qemu-error.o $(oslib-obj-y) $(trace-obj-y) \
+        $(block-obj-y) $(qobject-obj-y) $(version-obj-y) qemu-timer-common.o
 
-qemu-nbd$(EXESUF): qemu-nbd.o qemu-tool.o qemu-error.o $(oslib-obj-y) $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) qemu-timer-common.o
-
-qemu-io$(EXESUF): qemu-io.o cmd.o qemu-tool.o qemu-error.o $(oslib-obj-y) $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) qemu-timer-common.o
+qemu-img$(EXESUF): qemu-img.o $(tools-obj-y)
+qemu-nbd$(EXESUF): qemu-nbd.o $(tools-obj-y)
+qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y)
 
 qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
 	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"  GEN   $@")
commit 5bc465e4b1b6f4582a400c0a7033a1c841744278
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Wed Sep 28 11:06:15 2011 -0300

    qapi: Convert system_powerdown
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/hmp-commands.hx b/hmp-commands.hx
index b2f5cd1..07b493c 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -492,8 +492,7 @@ ETEXI
         .args_type  = "",
         .params     = "",
         .help       = "send system power down event",
-        .user_print = monitor_user_noop,
-        .mhandler.cmd_new = do_system_powerdown,
+        .mhandler.cmd = hmp_system_powerdown,
     },
 
 STEXI
diff --git a/hmp.c b/hmp.c
index 24f30bc..34416fc 100644
--- a/hmp.c
+++ b/hmp.c
@@ -109,3 +109,8 @@ void hmp_system_reset(Monitor *mon, const QDict *qdict)
 {
     qmp_system_reset(NULL);
 }
+
+void hmp_system_powerdown(Monitor *mon, const QDict *qdict)
+{
+    qmp_system_powerdown(NULL);
+}
diff --git a/hmp.h b/hmp.h
index a49a6e6..92433cf 100644
--- a/hmp.h
+++ b/hmp.h
@@ -26,5 +26,6 @@ void hmp_info_chardev(Monitor *mon);
 void hmp_quit(Monitor *mon, const QDict *qdict);
 void hmp_stop(Monitor *mon, const QDict *qdict);
 void hmp_system_reset(Monitor *mon, const QDict *qdict);
+void hmp_system_powerdown(Monitor *mon, const QDict *qdict);
 
 #endif
diff --git a/qapi-schema.json b/qapi-schema.json
index 02de4b5..5922c4a 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -257,3 +257,17 @@
 # Since: 0.14.0
 ##
 { 'command': 'system_reset' }
+
+##
+# @system_powerdown:
+#
+# Requests that a guest perform a powerdown operation.
+#
+# Since: 0.14.0
+#
+# Notes: A guest may or may not respond to this command.  This command
+#        returning does not indicate that a guest has accepted the request or
+#        that it has shut down.  Many guests will respond to this command by
+#        prompting the user in some way.
+##
+{ 'command': 'system_powerdown' }
diff --git a/qmp.c b/qmp.c
index 51d9383..bf58b05 100644
--- a/qmp.c
+++ b/qmp.c
@@ -85,3 +85,8 @@ void qmp_system_reset(Error **errp)
 {
     qemu_system_reset_request();
 }
+
+void qmp_system_powerdown(Error **erp)
+{
+    qemu_system_powerdown_request();
+}
commit 38d226535aeebda24f579446e168ae3385f4ebd6
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Thu Sep 15 14:41:46 2011 -0300

    qapi: Convert system_reset
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 3ad1ce7..b2f5cd1 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -477,8 +477,7 @@ ETEXI
         .args_type  = "",
         .params     = "",
         .help       = "reset the system",
-        .user_print = monitor_user_noop,
-        .mhandler.cmd_new = do_system_reset,
+        .mhandler.cmd = hmp_system_reset,
     },
 
 STEXI
diff --git a/hmp.c b/hmp.c
index efcb744..24f30bc 100644
--- a/hmp.c
+++ b/hmp.c
@@ -104,3 +104,8 @@ void hmp_stop(Monitor *mon, const QDict *qdict)
 {
     qmp_stop(NULL);
 }
+
+void hmp_system_reset(Monitor *mon, const QDict *qdict)
+{
+    qmp_system_reset(NULL);
+}
diff --git a/hmp.h b/hmp.h
index cb21cce..a49a6e6 100644
--- a/hmp.h
+++ b/hmp.h
@@ -25,5 +25,6 @@ void hmp_info_uuid(Monitor *mon);
 void hmp_info_chardev(Monitor *mon);
 void hmp_quit(Monitor *mon, const QDict *qdict);
 void hmp_stop(Monitor *mon, const QDict *qdict);
+void hmp_system_reset(Monitor *mon, const QDict *qdict);
 
 #endif
diff --git a/monitor.c b/monitor.c
index 2a5230c..c226879 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1930,16 +1930,6 @@ static void do_boot_set(Monitor *mon, const QDict *qdict)
 }
 
 /**
- * do_system_reset(): Issue a machine reset
- */
-static int do_system_reset(Monitor *mon, const QDict *qdict,
-                           QObject **ret_data)
-{
-    qemu_system_reset_request();
-    return 0;
-}
-
-/**
  * do_system_powerdown(): Issue a machine powerdown
  */
 static int do_system_powerdown(Monitor *mon, const QDict *qdict,
diff --git a/qapi-schema.json b/qapi-schema.json
index cd05034..02de4b5 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -248,3 +248,12 @@
 #         state
 ##
 { 'command': 'stop' }
+
+##
+# @system_reset:
+#
+# Performs a hard reset of a guest.
+#
+# Since: 0.14.0
+##
+{ 'command': 'system_reset' }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 2ccddee..ea96191 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -223,10 +223,7 @@ EQMP
     {
         .name       = "system_reset",
         .args_type  = "",
-        .params     = "",
-        .help       = "reset the system",
-        .user_print = monitor_user_noop,
-        .mhandler.cmd_new = do_system_reset,
+        .mhandler.cmd_new = qmp_marshal_input_system_reset,
     },
 
 SQMP
diff --git a/qmp.c b/qmp.c
index 6c46479..51d9383 100644
--- a/qmp.c
+++ b/qmp.c
@@ -81,3 +81,7 @@ void qmp_stop(Error **errp)
     vm_stop(RUN_STATE_PAUSED);
 }
 
+void qmp_system_reset(Error **errp)
+{
+    qemu_system_reset_request();
+}
commit 5f158f21f9b2ff129b5154bccf6212692ac9f6c1
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Thu Sep 15 14:34:39 2011 -0300

    qapi: Convert stop
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 2163e6f..3ad1ce7 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -290,8 +290,7 @@ ETEXI
         .args_type  = "",
         .params     = "",
         .help       = "stop emulation",
-        .user_print = monitor_user_noop,
-        .mhandler.cmd_new = do_stop,
+        .mhandler.cmd = hmp_stop,
     },
 
 STEXI
diff --git a/hmp.c b/hmp.c
index 7695dfc..efcb744 100644
--- a/hmp.c
+++ b/hmp.c
@@ -99,3 +99,8 @@ void hmp_quit(Monitor *mon, const QDict *qdict)
     monitor_suspend(mon);
     qmp_quit(NULL);
 }
+
+void hmp_stop(Monitor *mon, const QDict *qdict)
+{
+    qmp_stop(NULL);
+}
diff --git a/hmp.h b/hmp.h
index a3dfafd..cb21cce 100644
--- a/hmp.h
+++ b/hmp.h
@@ -24,5 +24,6 @@ void hmp_info_status(Monitor *mon);
 void hmp_info_uuid(Monitor *mon);
 void hmp_info_chardev(Monitor *mon);
 void hmp_quit(Monitor *mon, const QDict *qdict);
+void hmp_stop(Monitor *mon, const QDict *qdict);
 
 #endif
diff --git a/monitor.c b/monitor.c
index 6e13ef6..2a5230c 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1212,15 +1212,6 @@ static void do_singlestep(Monitor *mon, const QDict *qdict)
     }
 }
 
-/**
- * do_stop(): Stop VM execution
- */
-static int do_stop(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
-    vm_stop(RUN_STATE_PAUSED);
-    return 0;
-}
-
 static void encrypted_bdrv_it(void *opaque, BlockDriverState *bs);
 
 struct bdrv_iterate_context {
diff --git a/qapi-schema.json b/qapi-schema.json
index 3810463..cd05034 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -236,3 +236,15 @@
 # Since: 0.14.0
 ##
 { 'command': 'quit' }
+
+##
+# @stop:
+#
+# Stop all guest VCPU execution.
+#
+# Since:  0.14.0
+#
+# Notes:  This function will succeed even if the guest is already in the stopped
+#         state
+##
+{ 'command': 'stop' }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 151a5fa..2ccddee 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -178,10 +178,7 @@ EQMP
     {
         .name       = "stop",
         .args_type  = "",
-        .params     = "",
-        .help       = "stop emulation",
-        .user_print = monitor_user_noop,
-        .mhandler.cmd_new = do_stop,
+        .mhandler.cmd_new = qmp_marshal_input_stop,
     },
 
 SQMP
diff --git a/qmp.c b/qmp.c
index 1d380b6..6c46479 100644
--- a/qmp.c
+++ b/qmp.c
@@ -76,3 +76,8 @@ void qmp_quit(Error **err)
     qemu_system_shutdown_request();
 }
 
+void qmp_stop(Error **errp)
+{
+    vm_stop(RUN_STATE_PAUSED);
+}
+
commit 7a7f325e053c5079ce4b7b8e9e2b0f4c4c30ade8
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Thu Sep 15 14:20:28 2011 -0300

    qapi: Convert quit
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 9e1cca8..2163e6f 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -43,7 +43,7 @@ ETEXI
         .params     = "",
         .help       = "quit the emulator",
         .user_print = monitor_user_noop,
-        .mhandler.cmd_new = do_quit,
+        .mhandler.cmd = hmp_quit,
     },
 
 STEXI
diff --git a/hmp.c b/hmp.c
index 30c6cc9..7695dfc 100644
--- a/hmp.c
+++ b/hmp.c
@@ -93,3 +93,9 @@ void hmp_info_chardev(Monitor *mon)
 
     qapi_free_ChardevInfoList(char_info);
 }
+
+void hmp_quit(Monitor *mon, const QDict *qdict)
+{
+    monitor_suspend(mon);
+    qmp_quit(NULL);
+}
diff --git a/hmp.h b/hmp.h
index 7388f9a..a3dfafd 100644
--- a/hmp.h
+++ b/hmp.h
@@ -23,5 +23,6 @@ void hmp_info_kvm(Monitor *mon);
 void hmp_info_status(Monitor *mon);
 void hmp_info_uuid(Monitor *mon);
 void hmp_info_chardev(Monitor *mon);
+void hmp_quit(Monitor *mon, const QDict *qdict);
 
 #endif
diff --git a/monitor.c b/monitor.c
index 0c90506..6e13ef6 100644
--- a/monitor.c
+++ b/monitor.c
@@ -946,18 +946,6 @@ static void do_trace_print_events(Monitor *mon)
     trace_print_events((FILE *)mon, &monitor_fprintf);
 }
 
-/**
- * do_quit(): Quit QEMU execution
- */
-static int do_quit(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
-    monitor_suspend(mon);
-    no_shutdown = 0;
-    qemu_system_shutdown_request();
-
-    return 0;
-}
-
 #ifdef CONFIG_VNC
 static int change_vnc_password(const char *password)
 {
diff --git a/qapi-schema.json b/qapi-schema.json
index 35434c1..3810463 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -225,3 +225,14 @@
 ##
 { 'command': 'query-commands', 'returns': ['CommandInfo'] }
 
+##
+# @quit:
+#
+# This command will cause the QEMU process to exit gracefully.  While every
+# attempt is made to send the QMP response before terminating, this is not
+# guaranteed.  When using this interface, a premature EOF would not be
+# unexpected.
+#
+# Since: 0.14.0
+##
+{ 'command': 'quit' }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 0fda5c3..151a5fa 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -63,10 +63,7 @@ EQMP
     {
         .name       = "quit",
         .args_type  = "",
-        .params     = "",
-        .help       = "quit the emulator",
-        .user_print = monitor_user_noop,
-        .mhandler.cmd_new = do_quit,
+        .mhandler.cmd_new = qmp_marshal_input_quit,
     },
 
 SQMP
diff --git a/qmp.c b/qmp.c
index 58337c7..1d380b6 100644
--- a/qmp.c
+++ b/qmp.c
@@ -70,3 +70,9 @@ UuidInfo *qmp_query_uuid(Error **errp)
     return info;
 }
 
+void qmp_quit(Error **err)
+{
+    no_shutdown = 0;
+    qemu_system_shutdown_request();
+}
+
commit aa9b79bcd813b399ad13e13b5db4e8b2e8787e4c
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Wed Sep 21 14:31:51 2011 -0300

    qapi: Convert query-commands
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/monitor.c b/monitor.c
index 86a0dad..0c90506 100644
--- a/monitor.c
+++ b/monitor.c
@@ -731,39 +731,37 @@ help:
     help_cmd(mon, "info");
 }
 
-static QObject *get_cmd_dict(const char *name)
+static CommandInfoList *alloc_cmd_entry(const char *cmd_name)
 {
-    const char *p;
+    CommandInfoList *info;
 
-    /* Remove '|' from some commands */
-    p = strchr(name, '|');
-    if (p) {
-        p++;
-    } else {
-        p = name;
-    }
+    info = g_malloc0(sizeof(*info));
+    info->value = g_malloc0(sizeof(*info->value));
+    info->value->name = g_strdup(cmd_name);
 
-    return qobject_from_jsonf("{ 'name': %s }", p);
+    return info;
 }
 
-static void do_info_commands(Monitor *mon, QObject **ret_data)
+CommandInfoList *qmp_query_commands(Error **errp)
 {
-    QList *cmd_list;
+    CommandInfoList *info, *cmd_list = NULL;
     const mon_cmd_t *cmd;
 
-    cmd_list = qlist_new();
-
     for (cmd = qmp_cmds; cmd->name != NULL; cmd++) {
-        qlist_append_obj(cmd_list, get_cmd_dict(cmd->name));
+        info = alloc_cmd_entry(cmd->name);
+        info->next = cmd_list;
+        cmd_list = info;
     }
 
     for (cmd = qmp_query_cmds; cmd->name != NULL; cmd++) {
         char buf[128];
         snprintf(buf, sizeof(buf), "query-%s", cmd->name);
-        qlist_append_obj(cmd_list, get_cmd_dict(buf));
+        info = alloc_cmd_entry(buf);
+        info->next = cmd_list;
+        cmd_list = info;
     }
 
-    *ret_data = QOBJECT(cmd_list);
+    return cmd_list;
 }
 
 /* get the current CPU defined by the user */
@@ -3064,14 +3062,6 @@ static const mon_cmd_t qmp_cmds[] = {
 
 static const mon_cmd_t qmp_query_cmds[] = {
     {
-        .name       = "commands",
-        .args_type  = "",
-        .params     = "",
-        .help       = "list QMP available commands",
-        .user_print = monitor_user_noop,
-        .mhandler.info_new = do_info_commands,
-    },
-    {
         .name       = "block",
         .args_type  = "",
         .params     = "",
diff --git a/qapi-schema.json b/qapi-schema.json
index cf55504..35434c1 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -202,3 +202,26 @@
 # Since: 0.14.0
 ##
 { 'command': 'query-chardev', 'returns': ['ChardevInfo'] }
+
+##
+# @CommandInfo:
+#
+# Information about a QMP command
+#
+# @name: The command name
+#
+# Since: 0.14.0
+##
+{ 'type': 'CommandInfo', 'data': {'name': 'str'} }
+
+##
+# @query-commands:
+#
+# Return a list of supported QMP commands by this server
+#
+# Returns: A list of @CommandInfo for all supported commands
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-commands', 'returns': ['CommandInfo'] }
+
diff --git a/qmp-commands.hx b/qmp-commands.hx
index dfc02af..0fda5c3 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1090,6 +1090,12 @@ Note: This example has been shortened as the real response is too long.
 
 EQMP
 
+    {
+        .name       = "query-commands",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_commands,
+    },
+
 SQMP
 query-chardev
 -------------
commit c5a415a0afddbc217263b62a8e87d8ec9e7f760f
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Wed Sep 14 16:05:49 2011 -0300

    qapi: Convert query-chardev
    
    Reviewed-by: Michael Roth <mdroth at linux.vnet.ibm.com>
    Tested-by: Michael Roth <mdroth at linux.vnet.ibm.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/hmp.c b/hmp.c
index 25302f5..30c6cc9 100644
--- a/hmp.c
+++ b/hmp.c
@@ -80,3 +80,16 @@ void hmp_info_uuid(Monitor *mon)
     monitor_printf(mon, "%s\n", info->UUID);
     qapi_free_UuidInfo(info);
 }
+
+void hmp_info_chardev(Monitor *mon)
+{
+    ChardevInfoList *char_info, *info;
+
+    char_info = qmp_query_chardev(NULL);
+    for (info = char_info; info; info = info->next) {
+        monitor_printf(mon, "%s: filename=%s\n", info->value->label,
+                                                 info->value->filename);
+    }
+
+    qapi_free_ChardevInfoList(char_info);
+}
diff --git a/hmp.h b/hmp.h
index 49a5971..7388f9a 100644
--- a/hmp.h
+++ b/hmp.h
@@ -22,5 +22,6 @@ void hmp_info_version(Monitor *mon);
 void hmp_info_kvm(Monitor *mon);
 void hmp_info_status(Monitor *mon);
 void hmp_info_uuid(Monitor *mon);
+void hmp_info_chardev(Monitor *mon);
 
 #endif
diff --git a/monitor.c b/monitor.c
index 4e9ecdf..86a0dad 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2783,8 +2783,7 @@ static const mon_cmd_t info_cmds[] = {
         .args_type  = "",
         .params     = "",
         .help       = "show the character devices",
-        .user_print = qemu_chr_info_print,
-        .mhandler.info_new = qemu_chr_info,
+        .mhandler.info = hmp_info_chardev,
     },
     {
         .name       = "block",
@@ -3073,14 +3072,6 @@ static const mon_cmd_t qmp_query_cmds[] = {
         .mhandler.info_new = do_info_commands,
     },
     {
-        .name       = "chardev",
-        .args_type  = "",
-        .params     = "",
-        .help       = "show the character devices",
-        .user_print = qemu_chr_info_print,
-        .mhandler.info_new = qemu_chr_info,
-    },
-    {
         .name       = "block",
         .args_type  = "",
         .params     = "",
diff --git a/qapi-schema.json b/qapi-schema.json
index b717491..cf55504 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -176,3 +176,29 @@
 ##
 { 'command': 'query-uuid', 'returns': 'UuidInfo' }
 
+##
+# @ChardevInfo:
+#
+# Information about a character device.
+#
+# @label: the label of the character device
+#
+# @filename: the filename of the character device
+#
+# Notes: @filename is encoded using the QEMU command line character device
+#        encoding.  See the QEMU man page for details.
+#
+# Since: 0.14.0
+##
+{ 'type': 'ChardevInfo', 'data': {'label': 'str', 'filename': 'str'} }
+
+##
+# @query-chardev:
+#
+# Returns information about current character devices.
+#
+# Returns: a list of @ChardevInfo
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-chardev', 'returns': ['ChardevInfo'] }
diff --git a/qemu-char.c b/qemu-char.c
index 09d2309..8bdbcfd 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -31,7 +31,7 @@
 #include "hw/usb.h"
 #include "hw/baum.h"
 #include "hw/msmouse.h"
-#include "qemu-objects.h"
+#include "qmp-commands.h"
 
 #include <unistd.h>
 #include <fcntl.h>
@@ -2650,35 +2650,22 @@ void qemu_chr_delete(CharDriverState *chr)
     g_free(chr);
 }
 
-static void qemu_chr_qlist_iter(QObject *obj, void *opaque)
+ChardevInfoList *qmp_query_chardev(Error **errp)
 {
-    QDict *chr_dict;
-    Monitor *mon = opaque;
-
-    chr_dict = qobject_to_qdict(obj);
-    monitor_printf(mon, "%s: filename=%s\n", qdict_get_str(chr_dict, "label"),
-                                         qdict_get_str(chr_dict, "filename"));
-}
-
-void qemu_chr_info_print(Monitor *mon, const QObject *ret_data)
-{
-    qlist_iter(qobject_to_qlist(ret_data), qemu_chr_qlist_iter, mon);
-}
-
-void qemu_chr_info(Monitor *mon, QObject **ret_data)
-{
-    QList *chr_list;
+    ChardevInfoList *chr_list = NULL;
     CharDriverState *chr;
 
-    chr_list = qlist_new();
-
     QTAILQ_FOREACH(chr, &chardevs, next) {
-        QObject *obj = qobject_from_jsonf("{ 'label': %s, 'filename': %s }",
-                                          chr->label, chr->filename);
-        qlist_append_obj(chr_list, obj);
+        ChardevInfoList *info = g_malloc0(sizeof(*info));
+        info->value = g_malloc0(sizeof(*info->value));
+        info->value->label = g_strdup(chr->label);
+        info->value->filename = g_strdup(chr->filename);
+
+        info->next = chr_list;
+        chr_list = info;
     }
 
-    *ret_data = QOBJECT(chr_list);
+    return chr_list;
 }
 
 CharDriverState *qemu_chr_find(const char *name)
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 4fef25f..dfc02af 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1120,6 +1120,12 @@ Example:
 
 EQMP
 
+    {
+        .name       = "query-chardev",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_chardev,
+    },
+
 SQMP
 query-block
 -----------
commit efab767eaafe39a234e8244819d0969ff59a325a
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Tue Sep 13 17:16:25 2011 -0300

    qapi: Convert query-uuid
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/hmp.c b/hmp.c
index 30925b0..25302f5 100644
--- a/hmp.c
+++ b/hmp.c
@@ -72,3 +72,11 @@ void hmp_info_status(Monitor *mon)
     qapi_free_StatusInfo(info);
 }
 
+void hmp_info_uuid(Monitor *mon)
+{
+    UuidInfo *info;
+
+    info = qmp_query_uuid(NULL);
+    monitor_printf(mon, "%s\n", info->UUID);
+    qapi_free_UuidInfo(info);
+}
diff --git a/hmp.h b/hmp.h
index df4242f..49a5971 100644
--- a/hmp.h
+++ b/hmp.h
@@ -21,5 +21,6 @@ void hmp_info_name(Monitor *mon);
 void hmp_info_version(Monitor *mon);
 void hmp_info_kvm(Monitor *mon);
 void hmp_info_status(Monitor *mon);
+void hmp_info_uuid(Monitor *mon);
 
 #endif
diff --git a/monitor.c b/monitor.c
index e68f2e2..4e9ecdf 100644
--- a/monitor.c
+++ b/monitor.c
@@ -766,23 +766,6 @@ static void do_info_commands(Monitor *mon, QObject **ret_data)
     *ret_data = QOBJECT(cmd_list);
 }
 
-static void do_info_uuid_print(Monitor *mon, const QObject *data)
-{
-    monitor_printf(mon, "%s\n", qdict_get_str(qobject_to_qdict(data), "UUID"));
-}
-
-static void do_info_uuid(Monitor *mon, QObject **ret_data)
-{
-    char uuid[64];
-
-    snprintf(uuid, sizeof(uuid), UUID_FMT, qemu_uuid[0], qemu_uuid[1],
-                   qemu_uuid[2], qemu_uuid[3], qemu_uuid[4], qemu_uuid[5],
-                   qemu_uuid[6], qemu_uuid[7], qemu_uuid[8], qemu_uuid[9],
-                   qemu_uuid[10], qemu_uuid[11], qemu_uuid[12], qemu_uuid[13],
-                   qemu_uuid[14], qemu_uuid[15]);
-    *ret_data = qobject_from_jsonf("{ 'UUID': %s }", uuid);
-}
-
 /* get the current CPU defined by the user */
 static int mon_set_cpu(int cpu_index)
 {
@@ -2996,8 +2979,7 @@ static const mon_cmd_t info_cmds[] = {
         .args_type  = "",
         .params     = "",
         .help       = "show the current VM UUID",
-        .user_print = do_info_uuid_print,
-        .mhandler.info_new = do_info_uuid,
+        .mhandler.info = hmp_info_uuid,
     },
 #if defined(TARGET_PPC)
     {
@@ -3157,14 +3139,6 @@ static const mon_cmd_t qmp_query_cmds[] = {
     },
 #endif
     {
-        .name       = "uuid",
-        .args_type  = "",
-        .params     = "",
-        .help       = "show the current VM UUID",
-        .user_print = do_info_uuid_print,
-        .mhandler.info_new = do_info_uuid,
-    },
-    {
         .name       = "migrate",
         .args_type  = "",
         .params     = "",
diff --git a/qapi-schema.json b/qapi-schema.json
index 0e59c71..b717491 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -152,3 +152,27 @@
 ##
 { 'command': 'query-status', 'returns': 'StatusInfo' }
 
+##
+# @UuidInfo:
+#
+# Guest UUID information.
+#
+# @UUID: the UUID of the guest
+#
+# Since: 0.14.0
+#
+# Notes: If no UUID was specified for the guest, a null UUID is returned.
+##
+{ 'type': 'UuidInfo', 'data': {'UUID': 'str'} }
+
+##
+# @query-uuid:
+#
+# Query the guest UUID information.
+#
+# Returns: The @UuidInfo for the guest
+#
+# Since 0.14.0
+##
+{ 'command': 'query-uuid', 'returns': 'UuidInfo' }
+
diff --git a/qmp-commands.hx b/qmp-commands.hx
index afa95bd..4fef25f 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1821,6 +1821,12 @@ Example:
 
 EQMP
 
+    {
+        .name       = "query-uuid",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_uuid,
+    },
+
 SQMP
 query-migrate
 -------------
diff --git a/qmp.c b/qmp.c
index 8f7f666..58337c7 100644
--- a/qmp.c
+++ b/qmp.c
@@ -55,3 +55,18 @@ KvmInfo *qmp_query_kvm(Error **errp)
     return info;
 }
 
+UuidInfo *qmp_query_uuid(Error **errp)
+{
+    UuidInfo *info = g_malloc0(sizeof(*info));
+    char uuid[64];
+
+    snprintf(uuid, sizeof(uuid), UUID_FMT, qemu_uuid[0], qemu_uuid[1],
+                   qemu_uuid[2], qemu_uuid[3], qemu_uuid[4], qemu_uuid[5],
+                   qemu_uuid[6], qemu_uuid[7], qemu_uuid[8], qemu_uuid[9],
+                   qemu_uuid[10], qemu_uuid[11], qemu_uuid[12], qemu_uuid[13],
+                   qemu_uuid[14], qemu_uuid[15]);
+
+    info->UUID = g_strdup(uuid);
+    return info;
+}
+
commit 1fa9a5e4aea36b4d21e42323ae43879c908af576
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Mon Sep 12 17:54:20 2011 -0300

    qapi: Convert query-status
    
    Please, note that the RunState type as defined in sysemu.h and its
    runstate_as_string() function are being dropped in favor of the
    RunState type generated by the QAPI.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/hmp.c b/hmp.c
index 94a7f74..30925b0 100644
--- a/hmp.c
+++ b/hmp.c
@@ -53,3 +53,22 @@ void hmp_info_kvm(Monitor *mon)
     qapi_free_KvmInfo(info);
 }
 
+void hmp_info_status(Monitor *mon)
+{
+    StatusInfo *info;
+
+    info = qmp_query_status(NULL);
+
+    monitor_printf(mon, "VM status: %s%s",
+                   info->running ? "running" : "paused",
+                   info->singlestep ? " (single step mode)" : "");
+
+    if (!info->running && info->status != RUN_STATE_PAUSED) {
+        monitor_printf(mon, " (%s)", RunState_lookup[info->status]);
+    }
+
+    monitor_printf(mon, "\n");
+
+    qapi_free_StatusInfo(info);
+}
+
diff --git a/hmp.h b/hmp.h
index a93ac1f..df4242f 100644
--- a/hmp.h
+++ b/hmp.h
@@ -20,5 +20,6 @@
 void hmp_info_name(Monitor *mon);
 void hmp_info_version(Monitor *mon);
 void hmp_info_kvm(Monitor *mon);
+void hmp_info_status(Monitor *mon);
 
 #endif
diff --git a/monitor.c b/monitor.c
index da729ce..e68f2e2 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2550,36 +2550,6 @@ static int do_inject_nmi(Monitor *mon, const QDict *qdict, QObject **ret_data)
 }
 #endif
 
-static void do_info_status_print(Monitor *mon, const QObject *data)
-{
-    QDict *qdict;
-    const char *status;
-
-    qdict = qobject_to_qdict(data);
-
-    monitor_printf(mon, "VM status: ");
-    if (qdict_get_bool(qdict, "running")) {
-        monitor_printf(mon, "running");
-        if (qdict_get_bool(qdict, "singlestep")) {
-            monitor_printf(mon, " (single step mode)");
-        }
-    } else {
-        monitor_printf(mon, "paused");
-    }
-
-    status = qdict_get_str(qdict, "status");
-    if (strcmp(status, "paused") && strcmp(status, "running")) {
-        monitor_printf(mon, " (%s)", status);
-    }
-
-    monitor_printf(mon, "\n");
-}
-
-static void do_info_status(Monitor *mon, QObject **ret_data)
-{
-    *ret_data = qobject_from_jsonf("{ 'running': %i, 'singlestep': %i, 'status': %s }", runstate_is_running(), singlestep, runstate_as_string());
-}
-
 static qemu_acl *find_acl(Monitor *mon, const char *name)
 {
     qemu_acl *acl = qemu_acl_find(name);
@@ -2979,8 +2949,7 @@ static const mon_cmd_t info_cmds[] = {
         .args_type  = "",
         .params     = "",
         .help       = "show the current VM status (running|paused)",
-        .user_print = do_info_status_print,
-        .mhandler.info_new = do_info_status,
+        .mhandler.info = hmp_info_status,
     },
     {
         .name       = "pcmcia",
@@ -3162,14 +3131,6 @@ static const mon_cmd_t qmp_query_cmds[] = {
         .mhandler.info_new = do_pci_info,
     },
     {
-        .name       = "status",
-        .args_type  = "",
-        .params     = "",
-        .help       = "show the current VM status (running|paused)",
-        .user_print = do_info_status_print,
-        .mhandler.info_new = do_info_status,
-    },
-    {
         .name       = "mice",
         .args_type  = "",
         .params     = "",
diff --git a/qapi-schema.json b/qapi-schema.json
index 641f12d..0e59c71 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -85,3 +85,70 @@
 ##
 { 'command': 'query-kvm', 'returns': 'KvmInfo' }
 
+##
+# @RunState
+#
+# An enumation of VM run states.
+#
+# @debug: QEMU is running on a debugger
+#
+# @inmigrate: guest is paused waiting for an incoming migration
+#
+# @internal-error: An internal error that prevents further guest execution
+# has occurred
+#
+# @io-error: the last IOP has failed and the device is configured to pause
+# on I/O errors
+#
+# @paused: guest has been paused via the 'stop' command
+#
+# @postmigrate: guest is paused following a successful 'migrate'
+#
+# @prelaunch: QEMU was started with -S and guest has not started
+#
+# @finish-migrate: guest is paused to finish the migration process
+#
+# @restore-vm: guest is paused to restore VM state
+#
+# @running: guest is actively running
+#
+# @save-vm: guest is paused to save the VM state
+#
+# @shutdown: guest is shut down (and -no-shutdown is in use)
+#
+# @watchdog: the watchdog action is configured to pause and has been triggered
+##
+{ 'enum': 'RunState',
+  'data': [ 'debug', 'inmigrate', 'internal-error', 'io-error', 'paused',
+            'postmigrate', 'prelaunch', 'finish-migrate', 'restore-vm',
+            'running', 'save-vm', 'shutdown', 'watchdog' ] }
+
+##
+# @StatusInfo:
+#
+# Information about VCPU run state
+#
+# @running: true if all VCPUs are runnable, false if not runnable
+#
+# @singlestep: true if VCPUs are in single-step mode
+#
+# @status: the virtual machine @RunState
+#
+# Since:  0.14.0
+#
+# Notes: @singlestep is enabled through the GDB stub
+##
+{ 'type': 'StatusInfo',
+  'data': {'running': 'bool', 'singlestep': 'bool', 'status': 'RunState'} }
+
+##
+# @query-status:
+#
+# Query the run status of all VCPUs
+#
+# Returns: @StatusInfo reflecting all VCPUs
+#
+# Since:  0.14.0
+##
+{ 'command': 'query-status', 'returns': 'StatusInfo' }
+
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 9f9751d..afa95bd 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1609,6 +1609,12 @@ Example:
 <- { "return": { "running": true, "singlestep": false, "status": "running" } }
 
 EQMP
+    
+    {
+        .name       = "query-status",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_status,
+    },
 
 SQMP
 query-mice
diff --git a/sysemu.h b/sysemu.h
index 5d1fed2..a889d90 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -6,27 +6,11 @@
 #include "qemu-option.h"
 #include "qemu-queue.h"
 #include "qemu-timer.h"
+#include "qapi-types.h"
 #include "notify.h"
 
 /* vl.c */
 
-typedef enum {
-    RUN_STATE_DEBUG,          /* qemu is running under gdb */
-    RUN_STATE_INMIGRATE,     /* paused waiting for an incoming migration */
-    RUN_STATE_INTERNAL_ERROR,       /* paused due to an internal error */
-    RUN_STATE_IO_ERROR,       /* paused due to an I/O error */
-    RUN_STATE_PAUSED,         /* paused by the user (ie. the 'stop' command) */
-    RUN_STATE_POSTMIGRATE,   /* paused following a successful migration */
-    RUN_STATE_PRELAUNCH,     /* qemu was started with -S and haven't started */
-    RUN_STATE_FINISH_MIGRATE,    /* paused preparing to finish migrate */
-    RUN_STATE_RESTORE_VM,        /* paused restoring the VM state */
-    RUN_STATE_RUNNING,        /* qemu is running */
-    RUN_STATE_SAVE_VM,         /* paused saving VM state */
-    RUN_STATE_SHUTDOWN,       /* guest shut down and -no-shutdown is in use */
-    RUN_STATE_WATCHDOG,       /* watchdog fired and qemu is configured to pause */
-    RUN_STATE_MAX
-} RunState;
-
 extern const char *bios_name;
 
 extern const char *qemu_name;
@@ -38,7 +22,6 @@ void runstate_init(void);
 bool runstate_check(RunState state);
 void runstate_set(RunState new_state);
 int runstate_is_running(void);
-const char *runstate_as_string(void);
 typedef struct vm_change_state_entry VMChangeStateEntry;
 typedef void VMChangeStateHandler(void *opaque, int running, RunState state);
 
diff --git a/vl.c b/vl.c
index ba4a151..dbf7778 100644
--- a/vl.c
+++ b/vl.c
@@ -147,6 +147,7 @@ int main(int argc, char **argv)
 #include "qemu-config.h"
 #include "qemu-objects.h"
 #include "qemu-options.h"
+#include "qmp-commands.h"
 #ifdef CONFIG_VIRTFS
 #include "fsdev/qemu-fsdev.h"
 #endif
@@ -375,22 +376,6 @@ static const RunStateTransition runstate_transitions_def[] = {
 
 static bool runstate_valid_transitions[RUN_STATE_MAX][RUN_STATE_MAX];
 
-static const char *const runstate_name_tbl[RUN_STATE_MAX] = {
-    [RUN_STATE_DEBUG] = "debug",
-    [RUN_STATE_INMIGRATE] = "incoming-migration",
-    [RUN_STATE_INTERNAL_ERROR] = "internal-error",
-    [RUN_STATE_IO_ERROR] = "io-error",
-    [RUN_STATE_PAUSED] = "paused",
-    [RUN_STATE_POSTMIGRATE] = "post-migrate",
-    [RUN_STATE_PRELAUNCH] = "prelaunch",
-    [RUN_STATE_FINISH_MIGRATE] = "finish-migrate",
-    [RUN_STATE_RESTORE_VM] = "restore-vm",
-    [RUN_STATE_RUNNING] = "running",
-    [RUN_STATE_SAVE_VM] = "save-vm",
-    [RUN_STATE_SHUTDOWN] = "shutdown",
-    [RUN_STATE_WATCHDOG] = "watchdog",
-};
-
 bool runstate_check(RunState state)
 {
     return current_run_state == state;
@@ -419,15 +404,20 @@ void runstate_set(RunState new_state)
     current_run_state = new_state;
 }
 
-const char *runstate_as_string(void)
+int runstate_is_running(void)
 {
-    assert(current_run_state < RUN_STATE_MAX);
-    return runstate_name_tbl[current_run_state];
+    return runstate_check(RUN_STATE_RUNNING);
 }
 
-int runstate_is_running(void)
+StatusInfo *qmp_query_status(Error **errp)
 {
-    return runstate_check(RUN_STATE_RUNNING);
+    StatusInfo *info = g_malloc0(sizeof(*info));
+
+    info->running = runstate_is_running();
+    info->singlestep = singlestep;
+    info->status = current_run_state;
+
+    return info;
 }
 
 /***********************************************************/
commit 0461d5a699cb8825039400b76839115e35b73d65
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Fri Sep 30 14:45:27 2011 -0300

    RunState: Rename enum values as generated by the QAPI
    
    Next commit will convert the query-status command to use the
    RunState type as generated by the QAPI.
    
    In order to "transparently" replace the current enum by the QAPI
    one, we have to make some changes to some enum values.
    
    As the changes are simple renames, I'll do them in one shot. The
    changes are:
    
     - Rename the prefix from RSTATE_ to RUN_STATE_
     - RUN_STATE_SAVEVM to RUN_STATE_SAVE_VM
     - RUN_STATE_IN_MIGRATE to RUN_STATE_INMIGRATE
     - RUN_STATE_PANICKED to RUN_STATE_INTERNAL_ERROR
     - RUN_STATE_POST_MIGRATE to RUN_STATE_POSTMIGRATE
     - RUN_STATE_PRE_LAUNCH to RUN_STATE_PRELAUNCH
     - RUN_STATE_PRE_MIGRATE to RUN_STATE_PREMIGRATE
     - RUN_STATE_RESTORE to RUN_STATE_RESTORE_VM
     - RUN_STATE_PRE_MIGRATE to RUN_STATE_FINISH_MIGRATE
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/gdbstub.c b/gdbstub.c
index 12dd100..31ecad2 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -2385,7 +2385,7 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
         return;
     }
     switch (state) {
-    case RSTATE_DEBUG:
+    case RUN_STATE_DEBUG:
         if (env->watchpoint_hit) {
             switch (env->watchpoint_hit->flags & BP_MEM_ACCESS) {
             case BP_MEM_READ:
@@ -2408,25 +2408,25 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
         tb_flush(env);
         ret = GDB_SIGNAL_TRAP;
         break;
-    case RSTATE_PAUSED:
+    case RUN_STATE_PAUSED:
         ret = GDB_SIGNAL_INT;
         break;
-    case RSTATE_SHUTDOWN:
+    case RUN_STATE_SHUTDOWN:
         ret = GDB_SIGNAL_QUIT;
         break;
-    case RSTATE_IO_ERROR:
+    case RUN_STATE_IO_ERROR:
         ret = GDB_SIGNAL_IO;
         break;
-    case RSTATE_WATCHDOG:
+    case RUN_STATE_WATCHDOG:
         ret = GDB_SIGNAL_ALRM;
         break;
-    case RSTATE_PANICKED:
+    case RUN_STATE_INTERNAL_ERROR:
         ret = GDB_SIGNAL_ABRT;
         break;
-    case RSTATE_SAVEVM:
-    case RSTATE_RESTORE:
+    case RUN_STATE_SAVE_VM:
+    case RUN_STATE_RESTORE_VM:
         return;
-    case RSTATE_PRE_MIGRATE:
+    case RUN_STATE_FINISH_MIGRATE:
         ret = GDB_SIGNAL_XCPU;
         break;
     default:
@@ -2463,7 +2463,7 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...)
     gdb_current_syscall_cb = cb;
     s->state = RS_SYSCALL;
 #ifndef CONFIG_USER_ONLY
-    vm_stop(RSTATE_DEBUG);
+    vm_stop(RUN_STATE_DEBUG);
 #endif
     s->state = RS_IDLE;
     va_start(va, fmt);
@@ -2537,7 +2537,7 @@ static void gdb_read_byte(GDBState *s, int ch)
     if (runstate_is_running()) {
         /* when the CPU is running, we cannot do anything except stop
            it when receiving a char */
-        vm_stop(RSTATE_PAUSED);
+        vm_stop(RUN_STATE_PAUSED);
     } else
 #endif
     {
@@ -2799,7 +2799,7 @@ static void gdb_chr_event(void *opaque, int event)
 {
     switch (event) {
     case CHR_EVENT_OPENED:
-        vm_stop(RSTATE_PAUSED);
+        vm_stop(RUN_STATE_PAUSED);
         gdb_has_xml = 0;
         break;
     default:
@@ -2840,7 +2840,7 @@ static int gdb_monitor_write(CharDriverState *chr, const uint8_t *buf, int len)
 static void gdb_sigterm_handler(int signal)
 {
     if (runstate_is_running()) {
-        vm_stop(RSTATE_PAUSED);
+        vm_stop(RUN_STATE_PAUSED);
     }
 }
 #endif
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 4e76fc7..b71a356 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -527,7 +527,7 @@ static int ide_handle_rw_error(IDEState *s, int error, int op)
         s->bus->dma->ops->set_unit(s->bus->dma, s->unit);
         s->bus->error_status = op;
         bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read);
-        vm_stop(RSTATE_IO_ERROR);
+        vm_stop(RUN_STATE_IO_ERROR);
     } else {
         if (op & BM_STATUS_DMA_RETRY) {
             dma_buf_commit(s, 0);
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index e843f71..4f681ef 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -227,7 +227,7 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type)
         r->status |= SCSI_REQ_STATUS_RETRY | type;
 
         bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read);
-        vm_stop(RSTATE_IO_ERROR);
+        vm_stop(RUN_STATE_IO_ERROR);
     } else {
         switch (error) {
         case ENOMEM:
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index daa8e42..03878bf 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -77,7 +77,7 @@ static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
         req->next = s->rq;
         s->rq = req;
         bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read);
-        vm_stop(RSTATE_IO_ERROR);
+        vm_stop(RUN_STATE_IO_ERROR);
     } else {
         virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
         bdrv_acct_done(s->bs, &req->acct);
diff --git a/hw/watchdog.c b/hw/watchdog.c
index 71c6c7d..4c18965 100644
--- a/hw/watchdog.c
+++ b/hw/watchdog.c
@@ -132,7 +132,7 @@ void watchdog_perform_action(void)
 
     case WDT_PAUSE:             /* same as 'stop' command in monitor */
         watchdog_mon_event("pause");
-        vm_stop(RSTATE_WATCHDOG);
+        vm_stop(RUN_STATE_WATCHDOG);
         break;
 
     case WDT_DEBUG:
diff --git a/kvm-all.c b/kvm-all.c
index 228655b..e7faf5c 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -1014,7 +1014,7 @@ int kvm_cpu_exec(CPUState *env)
 
     if (ret < 0) {
         cpu_dump_state(env, stderr, fprintf, CPU_DUMP_CODE);
-        vm_stop(RSTATE_PANICKED);
+        vm_stop(RUN_STATE_INTERNAL_ERROR);
     }
 
     env->exit_request = 0;
diff --git a/migration.c b/migration.c
index 7dd8f4e..77a51ad 100644
--- a/migration.c
+++ b/migration.c
@@ -73,7 +73,7 @@ void process_incoming_migration(QEMUFile *f)
     if (autostart) {
         vm_start();
     } else {
-        runstate_set(RSTATE_PRE_LAUNCH);
+        runstate_set(RUN_STATE_PRELAUNCH);
     }
 }
 
@@ -375,7 +375,7 @@ void migrate_fd_put_ready(void *opaque)
         int old_vm_running = runstate_is_running();
 
         DPRINTF("done iterating\n");
-        vm_stop(RSTATE_PRE_MIGRATE);
+        vm_stop(RUN_STATE_FINISH_MIGRATE);
 
         if ((qemu_savevm_state_complete(s->mon, s->file)) < 0) {
             if (old_vm_running) {
@@ -392,7 +392,7 @@ void migrate_fd_put_ready(void *opaque)
             state = MIG_STATE_ERROR;
         }
         if (state == MIG_STATE_COMPLETED) {
-            runstate_set(RSTATE_POST_MIGRATE);
+            runstate_set(RUN_STATE_POSTMIGRATE);
         }
         s->state = state;
         notifier_list_notify(&migration_state_notifiers, NULL);
diff --git a/monitor.c b/monitor.c
index dad4221..da729ce 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1248,7 +1248,7 @@ static void do_singlestep(Monitor *mon, const QDict *qdict)
  */
 static int do_stop(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
-    vm_stop(RSTATE_PAUSED);
+    vm_stop(RUN_STATE_PAUSED);
     return 0;
 }
 
@@ -1266,11 +1266,11 @@ static int do_cont(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     struct bdrv_iterate_context context = { mon, 0 };
 
-    if (runstate_check(RSTATE_IN_MIGRATE)) {
+    if (runstate_check(RUN_STATE_INMIGRATE)) {
         qerror_report(QERR_MIGRATION_EXPECTED);
         return -1;
-    } else if (runstate_check(RSTATE_PANICKED) ||
-               runstate_check(RSTATE_SHUTDOWN)) {
+    } else if (runstate_check(RUN_STATE_INTERNAL_ERROR) ||
+               runstate_check(RUN_STATE_SHUTDOWN)) {
         qerror_report(QERR_RESET_REQUIRED);
         return -1;
     }
@@ -2773,7 +2773,7 @@ static void do_loadvm(Monitor *mon, const QDict *qdict)
     int saved_vm_running  = runstate_is_running();
     const char *name = qdict_get_str(qdict, "name");
 
-    vm_stop(RSTATE_RESTORE);
+    vm_stop(RUN_STATE_RESTORE_VM);
 
     if (load_vmstate(name) == 0 && saved_vm_running) {
         vm_start();
diff --git a/savevm.c b/savevm.c
index 46f2447..bf4d0e7 100644
--- a/savevm.c
+++ b/savevm.c
@@ -1603,7 +1603,7 @@ static int qemu_savevm_state(Monitor *mon, QEMUFile *f)
     int ret;
 
     saved_vm_running = runstate_is_running();
-    vm_stop(RSTATE_SAVEVM);
+    vm_stop(RUN_STATE_SAVE_VM);
 
     if (qemu_savevm_state_blocked(mon)) {
         ret = -EINVAL;
@@ -1932,7 +1932,7 @@ void do_savevm(Monitor *mon, const QDict *qdict)
     }
 
     saved_vm_running = runstate_is_running();
-    vm_stop(RSTATE_SAVEVM);
+    vm_stop(RUN_STATE_SAVE_VM);
 
     memset(sn, 0, sizeof(*sn));
 
diff --git a/sysemu.h b/sysemu.h
index 41ccc02..5d1fed2 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -11,20 +11,20 @@
 /* vl.c */
 
 typedef enum {
-    RSTATE_DEBUG,          /* qemu is running under gdb */
-    RSTATE_IN_MIGRATE,     /* paused waiting for an incoming migration */
-    RSTATE_PANICKED,       /* paused due to an internal error */
-    RSTATE_IO_ERROR,       /* paused due to an I/O error */
-    RSTATE_PAUSED,         /* paused by the user (ie. the 'stop' command) */
-    RSTATE_POST_MIGRATE,   /* paused following a successful migration */
-    RSTATE_PRE_LAUNCH,     /* qemu was started with -S and haven't started */
-    RSTATE_PRE_MIGRATE,    /* paused preparing to finish migrate */
-    RSTATE_RESTORE,        /* paused restoring the VM state */
-    RSTATE_RUNNING,        /* qemu is running */
-    RSTATE_SAVEVM,         /* paused saving VM state */
-    RSTATE_SHUTDOWN,       /* guest shut down and -no-shutdown is in use */
-    RSTATE_WATCHDOG,       /* watchdog fired and qemu is configured to pause */
-    RSTATE_MAX
+    RUN_STATE_DEBUG,          /* qemu is running under gdb */
+    RUN_STATE_INMIGRATE,     /* paused waiting for an incoming migration */
+    RUN_STATE_INTERNAL_ERROR,       /* paused due to an internal error */
+    RUN_STATE_IO_ERROR,       /* paused due to an I/O error */
+    RUN_STATE_PAUSED,         /* paused by the user (ie. the 'stop' command) */
+    RUN_STATE_POSTMIGRATE,   /* paused following a successful migration */
+    RUN_STATE_PRELAUNCH,     /* qemu was started with -S and haven't started */
+    RUN_STATE_FINISH_MIGRATE,    /* paused preparing to finish migrate */
+    RUN_STATE_RESTORE_VM,        /* paused restoring the VM state */
+    RUN_STATE_RUNNING,        /* qemu is running */
+    RUN_STATE_SAVE_VM,         /* paused saving VM state */
+    RUN_STATE_SHUTDOWN,       /* guest shut down and -no-shutdown is in use */
+    RUN_STATE_WATCHDOG,       /* watchdog fired and qemu is configured to pause */
+    RUN_STATE_MAX
 } RunState;
 
 extern const char *bios_name;
diff --git a/vl.c b/vl.c
index bc61494..ba4a151 100644
--- a/vl.c
+++ b/vl.c
@@ -323,7 +323,7 @@ static int default_driver_check(QemuOpts *opts, void *opaque)
 /***********************************************************/
 /* QEMU state */
 
-static RunState current_run_state = RSTATE_PRE_LAUNCH;
+static RunState current_run_state = RUN_STATE_PRELAUNCH;
 
 typedef struct {
     RunState from;
@@ -332,63 +332,63 @@ typedef struct {
 
 static const RunStateTransition runstate_transitions_def[] = {
     /*     from      ->     to      */
-    { RSTATE_DEBUG, RSTATE_RUNNING },
+    { RUN_STATE_DEBUG, RUN_STATE_RUNNING },
 
-    { RSTATE_IN_MIGRATE, RSTATE_RUNNING },
-    { RSTATE_IN_MIGRATE, RSTATE_PRE_LAUNCH },
+    { RUN_STATE_INMIGRATE, RUN_STATE_RUNNING },
+    { RUN_STATE_INMIGRATE, RUN_STATE_PRELAUNCH },
 
-    { RSTATE_PANICKED, RSTATE_PAUSED },
+    { RUN_STATE_INTERNAL_ERROR, RUN_STATE_PAUSED },
 
-    { RSTATE_IO_ERROR, RSTATE_RUNNING },
+    { RUN_STATE_IO_ERROR, RUN_STATE_RUNNING },
 
-    { RSTATE_PAUSED, RSTATE_RUNNING },
+    { RUN_STATE_PAUSED, RUN_STATE_RUNNING },
 
-    { RSTATE_POST_MIGRATE, RSTATE_RUNNING },
+    { RUN_STATE_POSTMIGRATE, RUN_STATE_RUNNING },
 
-    { RSTATE_PRE_LAUNCH, RSTATE_RUNNING },
-    { RSTATE_PRE_LAUNCH, RSTATE_IN_MIGRATE },
-    { RSTATE_PRE_LAUNCH, RSTATE_POST_MIGRATE },
+    { RUN_STATE_PRELAUNCH, RUN_STATE_RUNNING },
+    { RUN_STATE_PRELAUNCH, RUN_STATE_INMIGRATE },
+    { RUN_STATE_PRELAUNCH, RUN_STATE_POSTMIGRATE },
 
-    { RSTATE_PRE_MIGRATE, RSTATE_RUNNING },
-    { RSTATE_PRE_MIGRATE, RSTATE_POST_MIGRATE },
+    { RUN_STATE_FINISH_MIGRATE, RUN_STATE_RUNNING },
+    { RUN_STATE_FINISH_MIGRATE, RUN_STATE_POSTMIGRATE },
 
-    { RSTATE_RESTORE, RSTATE_RUNNING },
+    { RUN_STATE_RESTORE_VM, RUN_STATE_RUNNING },
 
-    { RSTATE_RUNNING, RSTATE_DEBUG },
-    { RSTATE_RUNNING, RSTATE_PANICKED },
-    { RSTATE_RUNNING, RSTATE_IO_ERROR },
-    { RSTATE_RUNNING, RSTATE_PAUSED },
-    { RSTATE_RUNNING, RSTATE_PRE_MIGRATE },
-    { RSTATE_RUNNING, RSTATE_RESTORE },
-    { RSTATE_RUNNING, RSTATE_SAVEVM },
-    { RSTATE_RUNNING, RSTATE_SHUTDOWN },
-    { RSTATE_RUNNING, RSTATE_WATCHDOG },
+    { RUN_STATE_RUNNING, RUN_STATE_DEBUG },
+    { RUN_STATE_RUNNING, RUN_STATE_INTERNAL_ERROR },
+    { RUN_STATE_RUNNING, RUN_STATE_IO_ERROR },
+    { RUN_STATE_RUNNING, RUN_STATE_PAUSED },
+    { RUN_STATE_RUNNING, RUN_STATE_FINISH_MIGRATE },
+    { RUN_STATE_RUNNING, RUN_STATE_RESTORE_VM },
+    { RUN_STATE_RUNNING, RUN_STATE_SAVE_VM },
+    { RUN_STATE_RUNNING, RUN_STATE_SHUTDOWN },
+    { RUN_STATE_RUNNING, RUN_STATE_WATCHDOG },
 
-    { RSTATE_SAVEVM, RSTATE_RUNNING },
+    { RUN_STATE_SAVE_VM, RUN_STATE_RUNNING },
 
-    { RSTATE_SHUTDOWN, RSTATE_PAUSED },
+    { RUN_STATE_SHUTDOWN, RUN_STATE_PAUSED },
 
-    { RSTATE_WATCHDOG, RSTATE_RUNNING },
+    { RUN_STATE_WATCHDOG, RUN_STATE_RUNNING },
 
-    { RSTATE_MAX, RSTATE_MAX },
+    { RUN_STATE_MAX, RUN_STATE_MAX },
 };
 
-static bool runstate_valid_transitions[RSTATE_MAX][RSTATE_MAX];
-
-static const char *const runstate_name_tbl[RSTATE_MAX] = {
-    [RSTATE_DEBUG] = "debug",
-    [RSTATE_IN_MIGRATE] = "incoming-migration",
-    [RSTATE_PANICKED] = "internal-error",
-    [RSTATE_IO_ERROR] = "io-error",
-    [RSTATE_PAUSED] = "paused",
-    [RSTATE_POST_MIGRATE] = "post-migrate",
-    [RSTATE_PRE_LAUNCH] = "prelaunch",
-    [RSTATE_PRE_MIGRATE] = "finish-migrate",
-    [RSTATE_RESTORE] = "restore-vm",
-    [RSTATE_RUNNING] = "running",
-    [RSTATE_SAVEVM] = "save-vm",
-    [RSTATE_SHUTDOWN] = "shutdown",
-    [RSTATE_WATCHDOG] = "watchdog",
+static bool runstate_valid_transitions[RUN_STATE_MAX][RUN_STATE_MAX];
+
+static const char *const runstate_name_tbl[RUN_STATE_MAX] = {
+    [RUN_STATE_DEBUG] = "debug",
+    [RUN_STATE_INMIGRATE] = "incoming-migration",
+    [RUN_STATE_INTERNAL_ERROR] = "internal-error",
+    [RUN_STATE_IO_ERROR] = "io-error",
+    [RUN_STATE_PAUSED] = "paused",
+    [RUN_STATE_POSTMIGRATE] = "post-migrate",
+    [RUN_STATE_PRELAUNCH] = "prelaunch",
+    [RUN_STATE_FINISH_MIGRATE] = "finish-migrate",
+    [RUN_STATE_RESTORE_VM] = "restore-vm",
+    [RUN_STATE_RUNNING] = "running",
+    [RUN_STATE_SAVE_VM] = "save-vm",
+    [RUN_STATE_SHUTDOWN] = "shutdown",
+    [RUN_STATE_WATCHDOG] = "watchdog",
 };
 
 bool runstate_check(RunState state)
@@ -402,7 +402,7 @@ void runstate_init(void)
 
     memset(&runstate_valid_transitions, 0, sizeof(runstate_valid_transitions));
 
-    for (p = &runstate_transitions_def[0]; p->from != RSTATE_MAX; p++) {
+    for (p = &runstate_transitions_def[0]; p->from != RUN_STATE_MAX; p++) {
         runstate_valid_transitions[p->from][p->to] = true;
     }
 }
@@ -410,7 +410,7 @@ void runstate_init(void)
 /* This function will abort() on invalid state transitions */
 void runstate_set(RunState new_state)
 {
-    if (new_state >= RSTATE_MAX ||
+    if (new_state >= RUN_STATE_MAX ||
         !runstate_valid_transitions[current_run_state][new_state]) {
         fprintf(stderr, "invalid runstate transition\n");
         abort();
@@ -421,13 +421,13 @@ void runstate_set(RunState new_state)
 
 const char *runstate_as_string(void)
 {
-    assert(current_run_state < RSTATE_MAX);
+    assert(current_run_state < RUN_STATE_MAX);
     return runstate_name_tbl[current_run_state];
 }
 
 int runstate_is_running(void)
 {
-    return runstate_check(RSTATE_RUNNING);
+    return runstate_check(RUN_STATE_RUNNING);
 }
 
 /***********************************************************/
@@ -1268,8 +1268,8 @@ void vm_start(void)
 {
     if (!runstate_is_running()) {
         cpu_enable_ticks();
-        runstate_set(RSTATE_RUNNING);
-        vm_state_notify(1, RSTATE_RUNNING);
+        runstate_set(RUN_STATE_RUNNING);
+        vm_state_notify(1, RUN_STATE_RUNNING);
         resume_all_vcpus();
         monitor_protocol_event(QEVENT_RESUME, NULL);
     }
@@ -1290,7 +1290,7 @@ static int shutdown_requested, shutdown_signal = -1;
 static pid_t shutdown_pid;
 static int powerdown_requested;
 static int debug_requested;
-static RunState vmstop_requested = RSTATE_MAX;
+static RunState vmstop_requested = RUN_STATE_MAX;
 
 int qemu_shutdown_requested_get(void)
 {
@@ -1346,12 +1346,12 @@ static int qemu_debug_requested(void)
     return r;
 }
 
-/* We use RSTATE_MAX but any invalid value will do */
+/* We use RUN_STATE_MAX but any invalid value will do */
 static bool qemu_vmstop_requested(RunState *r)
 {
-    if (vmstop_requested < RSTATE_MAX) {
+    if (vmstop_requested < RUN_STATE_MAX) {
         *r = vmstop_requested;
-        vmstop_requested = RSTATE_MAX;
+        vmstop_requested = RUN_STATE_MAX;
         return true;
     }
 
@@ -1583,13 +1583,13 @@ static void main_loop(void)
 #endif
 
         if (qemu_debug_requested()) {
-            vm_stop(RSTATE_DEBUG);
+            vm_stop(RUN_STATE_DEBUG);
         }
         if (qemu_shutdown_requested()) {
             qemu_kill_report();
             monitor_protocol_event(QEVENT_SHUTDOWN, NULL);
             if (no_shutdown) {
-                vm_stop(RSTATE_SHUTDOWN);
+                vm_stop(RUN_STATE_SHUTDOWN);
             } else
                 break;
         }
@@ -1598,9 +1598,9 @@ static void main_loop(void)
             cpu_synchronize_all_states();
             qemu_system_reset(VMRESET_REPORT);
             resume_all_vcpus();
-            if (runstate_check(RSTATE_PANICKED) ||
-                runstate_check(RSTATE_SHUTDOWN)) {
-                runstate_set(RSTATE_PAUSED);
+            if (runstate_check(RUN_STATE_INTERNAL_ERROR) ||
+                runstate_check(RUN_STATE_SHUTDOWN)) {
+                runstate_set(RUN_STATE_PAUSED);
             }
         }
         if (qemu_powerdown_requested()) {
@@ -3557,7 +3557,7 @@ int main(int argc, char **argv, char **envp)
     }
 
     if (incoming) {
-        runstate_set(RSTATE_IN_MIGRATE);
+        runstate_set(RUN_STATE_INMIGRATE);
         int ret = qemu_start_incoming_migration(incoming);
         if (ret < 0) {
             fprintf(stderr, "Migration failed. Exit code %s(%d), exiting.\n",
commit c4d11e38bd475f33d5fa9ceba5292304727f3113
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Fri Sep 30 14:40:07 2011 -0300

    RunState: Drop the RSTATE_NO_STATE value
    
    The QAPI framework won't generate it, so we need to get rid of it.
    
    In order to do that, this commit makes RSTATE_PRE_LAUNCH the initial
    state and change qemu_vmstop_requested() to use RSTATE_MAX.
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/sysemu.h b/sysemu.h
index 43ff546..41ccc02 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -11,7 +11,6 @@
 /* vl.c */
 
 typedef enum {
-    RSTATE_NO_STATE,
     RSTATE_DEBUG,          /* qemu is running under gdb */
     RSTATE_IN_MIGRATE,     /* paused waiting for an incoming migration */
     RSTATE_PANICKED,       /* paused due to an internal error */
diff --git a/vl.c b/vl.c
index 4db58bd..bc61494 100644
--- a/vl.c
+++ b/vl.c
@@ -323,7 +323,7 @@ static int default_driver_check(QemuOpts *opts, void *opaque)
 /***********************************************************/
 /* QEMU state */
 
-static RunState current_run_state = RSTATE_NO_STATE;
+static RunState current_run_state = RSTATE_PRE_LAUNCH;
 
 typedef struct {
     RunState from;
@@ -332,10 +332,6 @@ typedef struct {
 
 static const RunStateTransition runstate_transitions_def[] = {
     /*     from      ->     to      */
-    { RSTATE_NO_STATE, RSTATE_RUNNING },
-    { RSTATE_NO_STATE, RSTATE_IN_MIGRATE },
-    { RSTATE_NO_STATE, RSTATE_PRE_LAUNCH },
-
     { RSTATE_DEBUG, RSTATE_RUNNING },
 
     { RSTATE_IN_MIGRATE, RSTATE_RUNNING },
@@ -350,6 +346,7 @@ static const RunStateTransition runstate_transitions_def[] = {
     { RSTATE_POST_MIGRATE, RSTATE_RUNNING },
 
     { RSTATE_PRE_LAUNCH, RSTATE_RUNNING },
+    { RSTATE_PRE_LAUNCH, RSTATE_IN_MIGRATE },
     { RSTATE_PRE_LAUNCH, RSTATE_POST_MIGRATE },
 
     { RSTATE_PRE_MIGRATE, RSTATE_RUNNING },
@@ -424,8 +421,7 @@ void runstate_set(RunState new_state)
 
 const char *runstate_as_string(void)
 {
-    assert(current_run_state > RSTATE_NO_STATE &&
-           current_run_state < RSTATE_MAX);
+    assert(current_run_state < RSTATE_MAX);
     return runstate_name_tbl[current_run_state];
 }
 
@@ -1294,7 +1290,7 @@ static int shutdown_requested, shutdown_signal = -1;
 static pid_t shutdown_pid;
 static int powerdown_requested;
 static int debug_requested;
-static RunState vmstop_requested = RSTATE_NO_STATE;
+static RunState vmstop_requested = RSTATE_MAX;
 
 int qemu_shutdown_requested_get(void)
 {
@@ -1350,11 +1346,12 @@ static int qemu_debug_requested(void)
     return r;
 }
 
+/* We use RSTATE_MAX but any invalid value will do */
 static bool qemu_vmstop_requested(RunState *r)
 {
-    if (vmstop_requested != RSTATE_NO_STATE) {
+    if (vmstop_requested < RSTATE_MAX) {
         *r = vmstop_requested;
-        vmstop_requested = RSTATE_NO_STATE;
+        vmstop_requested = RSTATE_MAX;
         return true;
     }
 
@@ -3569,8 +3566,6 @@ int main(int argc, char **argv, char **envp)
         }
     } else if (autostart) {
         vm_start();
-    } else {
-        runstate_set(RSTATE_PRE_LAUNCH);
     }
 
     os_setup_post();
commit 0d45b702918f855c24bfd13c0f91b31f89c2e097
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Fri Sep 30 14:27:11 2011 -0300

    vl: Change qemu_vmstop_requested() to return a bool
    
    The stop reason is returned in the RunState argument. This is a
    preparation for a future commit which will convert the query-status
    command to the QAPI.
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/vl.c b/vl.c
index bd4a5ce..4db58bd 100644
--- a/vl.c
+++ b/vl.c
@@ -1350,11 +1350,15 @@ static int qemu_debug_requested(void)
     return r;
 }
 
-static RunState qemu_vmstop_requested(void)
+static bool qemu_vmstop_requested(RunState *r)
 {
-    RunState s = vmstop_requested;
-    vmstop_requested = RSTATE_NO_STATE;
-    return s;
+    if (vmstop_requested != RSTATE_NO_STATE) {
+        *r = vmstop_requested;
+        vmstop_requested = RSTATE_NO_STATE;
+        return true;
+    }
+
+    return false;
 }
 
 void qemu_register_reset(QEMUResetHandler *func, void *opaque)
@@ -1567,7 +1571,7 @@ static void main_loop(void)
 #ifdef CONFIG_PROFILER
     int64_t ti;
 #endif
-    int r;
+    RunState r;
 
     qemu_main_loop_start();
 
@@ -1606,7 +1610,7 @@ static void main_loop(void)
             monitor_protocol_event(QEVENT_POWERDOWN, NULL);
             qemu_irq_raise(qemu_system_powerdown);
         }
-        if ((r = qemu_vmstop_requested())) {
+        if (qemu_vmstop_requested(&r)) {
             vm_stop(r);
         }
     }
commit 292a26027c8567556795dde771e46d87306bd013
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Mon Sep 12 15:10:53 2011 -0300

    qapi: Convert query-kvm
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/hmp.c b/hmp.c
index bb6c86f..94a7f74 100644
--- a/hmp.c
+++ b/hmp.c
@@ -37,3 +37,19 @@ void hmp_info_version(Monitor *mon)
 
     qapi_free_VersionInfo(info);
 }
+
+void hmp_info_kvm(Monitor *mon)
+{
+    KvmInfo *info;
+
+    info = qmp_query_kvm(NULL);
+    monitor_printf(mon, "kvm support: ");
+    if (info->present) {
+        monitor_printf(mon, "%s\n", info->enabled ? "enabled" : "disabled");
+    } else {
+        monitor_printf(mon, "not compiled\n");
+    }
+
+    qapi_free_KvmInfo(info);
+}
+
diff --git a/hmp.h b/hmp.h
index 2aa75a2..a93ac1f 100644
--- a/hmp.h
+++ b/hmp.h
@@ -19,5 +19,6 @@
 
 void hmp_info_name(Monitor *mon);
 void hmp_info_version(Monitor *mon);
+void hmp_info_kvm(Monitor *mon);
 
 #endif
diff --git a/monitor.c b/monitor.c
index 483ea71..dad4221 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2430,31 +2430,6 @@ static void do_info_mtree(Monitor *mon)
     mtree_info((fprintf_function)monitor_printf, mon);
 }
 
-static void do_info_kvm_print(Monitor *mon, const QObject *data)
-{
-    QDict *qdict;
-
-    qdict = qobject_to_qdict(data);
-
-    monitor_printf(mon, "kvm support: ");
-    if (qdict_get_bool(qdict, "present")) {
-        monitor_printf(mon, "%s\n", qdict_get_bool(qdict, "enabled") ?
-                                    "enabled" : "disabled");
-    } else {
-        monitor_printf(mon, "not compiled\n");
-    }
-}
-
-static void do_info_kvm(Monitor *mon, QObject **ret_data)
-{
-#ifdef CONFIG_KVM
-    *ret_data = qobject_from_jsonf("{ 'enabled': %i, 'present': true }",
-                                   kvm_enabled());
-#else
-    *ret_data = qobject_from_jsonf("{ 'enabled': false, 'present': false }");
-#endif
-}
-
 static void do_info_numa(Monitor *mon)
 {
     int i;
@@ -2955,8 +2930,7 @@ static const mon_cmd_t info_cmds[] = {
         .args_type  = "",
         .params     = "",
         .help       = "show KVM information",
-        .user_print = do_info_kvm_print,
-        .mhandler.info_new = do_info_kvm,
+        .mhandler.info = hmp_info_kvm,
     },
     {
         .name       = "numa",
@@ -3188,14 +3162,6 @@ static const mon_cmd_t qmp_query_cmds[] = {
         .mhandler.info_new = do_pci_info,
     },
     {
-        .name       = "kvm",
-        .args_type  = "",
-        .params     = "",
-        .help       = "show KVM information",
-        .user_print = do_info_kvm_print,
-        .mhandler.info_new = do_info_kvm,
-    },
-    {
         .name       = "status",
         .args_type  = "",
         .params     = "",
diff --git a/qapi-schema.json b/qapi-schema.json
index 3c0ac4e..641f12d 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -60,3 +60,28 @@
 # Since: 0.14.0
 ##
 { 'command': 'query-version', 'returns': 'VersionInfo' }
+
+##
+# @KvmInfo:
+#
+# Information about support for KVM acceleration
+#
+# @enabled: true if KVM acceleration is active
+#
+# @present: true if KVM acceleration is built into this executable
+#
+# Since: 0.14.0
+##
+{ 'type': 'KvmInfo', 'data': {'enabled': 'bool', 'present': 'bool'} }
+
+##
+# @query-kvm:
+#
+# Returns information about KVM acceleration
+#
+# Returns: @KvmInfo
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-kvm', 'returns': 'KvmInfo' }
+
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 9f067ea..9f9751d 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1570,6 +1570,12 @@ Example:
 
 EQMP
 
+    {
+        .name       = "query-kvm",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_kvm,
+    },
+
 SQMP
 query-status
 ------------
diff --git a/qmp.c b/qmp.c
index f978ea4..8f7f666 100644
--- a/qmp.c
+++ b/qmp.c
@@ -14,6 +14,8 @@
 #include "qemu-common.h"
 #include "sysemu.h"
 #include "qmp-commands.h"
+#include "kvm.h"
+#include "arch_init.h"
 
 NameInfo *qmp_query_name(Error **errp)
 {
@@ -42,3 +44,14 @@ VersionInfo *qmp_query_version(Error **err)
 
     return info;
 }
+
+KvmInfo *qmp_query_kvm(Error **errp)
+{
+    KvmInfo *info = g_malloc0(sizeof(*info));
+
+    info->enabled = kvm_enabled();
+    info->present = kvm_available();
+
+    return info;
+}
+
commit b9c15f16d702306aeb984f30490cddb8b418a231
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Fri Aug 26 17:38:13 2011 -0300

    qapi: Convert query-version
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/hmp.c b/hmp.c
index 47e1ff7..bb6c86f 100644
--- a/hmp.c
+++ b/hmp.c
@@ -24,3 +24,16 @@ void hmp_info_name(Monitor *mon)
     }
     qapi_free_NameInfo(info);
 }
+
+void hmp_info_version(Monitor *mon)
+{
+    VersionInfo *info;
+
+    info = qmp_query_version(NULL);
+
+    monitor_printf(mon, "%" PRId64 ".%" PRId64 ".%" PRId64 "%s\n",
+                   info->qemu.major, info->qemu.minor, info->qemu.micro,
+                   info->package);
+
+    qapi_free_VersionInfo(info);
+}
diff --git a/hmp.h b/hmp.h
index 5fe73f1..2aa75a2 100644
--- a/hmp.h
+++ b/hmp.h
@@ -18,5 +18,6 @@
 #include "qapi-types.h"
 
 void hmp_info_name(Monitor *mon);
+void hmp_info_version(Monitor *mon);
 
 #endif
diff --git a/monitor.c b/monitor.c
index 83b4fa7..483ea71 100644
--- a/monitor.c
+++ b/monitor.c
@@ -731,37 +731,6 @@ help:
     help_cmd(mon, "info");
 }
 
-static void do_info_version_print(Monitor *mon, const QObject *data)
-{
-    QDict *qdict;
-    QDict *qemu;
-
-    qdict = qobject_to_qdict(data);
-    qemu = qdict_get_qdict(qdict, "qemu");
-
-    monitor_printf(mon, "%" PRId64 ".%" PRId64 ".%" PRId64 "%s\n",
-                  qdict_get_int(qemu, "major"),
-                  qdict_get_int(qemu, "minor"),
-                  qdict_get_int(qemu, "micro"),
-                  qdict_get_str(qdict, "package"));
-}
-
-static void do_info_version(Monitor *mon, QObject **ret_data)
-{
-    const char *version = QEMU_VERSION;
-    int major = 0, minor = 0, micro = 0;
-    char *tmp;
-
-    major = strtol(version, &tmp, 10);
-    tmp++;
-    minor = strtol(tmp, &tmp, 10);
-    tmp++;
-    micro = strtol(tmp, &tmp, 10);
-
-    *ret_data = qobject_from_jsonf("{ 'qemu': { 'major': %d, 'minor': %d, \
-        'micro': %d }, 'package': %s }", major, minor, micro, QEMU_PKGVERSION);
-}
-
 static QObject *get_cmd_dict(const char *name)
 {
     const char *p;
@@ -2872,8 +2841,7 @@ static const mon_cmd_t info_cmds[] = {
         .args_type  = "",
         .params     = "",
         .help       = "show the version of QEMU",
-        .user_print = do_info_version_print,
-        .mhandler.info_new = do_info_version,
+        .mhandler.info = hmp_info_version,
     },
     {
         .name       = "network",
@@ -3172,14 +3140,6 @@ static const mon_cmd_t qmp_cmds[] = {
 
 static const mon_cmd_t qmp_query_cmds[] = {
     {
-        .name       = "version",
-        .args_type  = "",
-        .params     = "",
-        .help       = "show the version of QEMU",
-        .user_print = do_info_version_print,
-        .mhandler.info_new = do_info_version,
-    },
-    {
         .name       = "commands",
         .args_type  = "",
         .params     = "",
@@ -5185,9 +5145,9 @@ void monitor_resume(Monitor *mon)
 
 static QObject *get_qmp_greeting(void)
 {
-    QObject *ver;
+    QObject *ver = NULL;
 
-    do_info_version(NULL, &ver);
+    qmp_marshal_input_query_version(NULL, NULL, &ver);
     return qobject_from_jsonf("{'QMP':{'version': %p,'capabilities': []}}",ver);
 }
 
diff --git a/qapi-schema.json b/qapi-schema.json
index 3585324..3c0ac4e 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -23,3 +23,40 @@
 # Since 0.14.0
 ##
 { 'command': 'query-name', 'returns': 'NameInfo' }
+
+##
+# @VersionInfo:
+#
+# A description of QEMU's version.
+#
+# @qemu.major:  The major version of QEMU
+#
+# @qemu.minor:  The minor version of QEMU
+#
+# @qemu.micro:  The micro version of QEMU.  By current convention, a micro
+#               version of 50 signifies a development branch.  A micro version
+#               greater than or equal to 90 signifies a release candidate for
+#               the next minor version.  A micro version of less than 50
+#               signifies a stable release.
+#
+# @package:     QEMU will always set this field to an empty string.  Downstream
+#               versions of QEMU should set this to a non-empty string.  The
+#               exact format depends on the downstream however it highly
+#               recommended that a unique name is used.
+#
+# Since: 0.14.0
+##
+{ 'type': 'VersionInfo',
+  'data': {'qemu': {'major': 'int', 'minor': 'int', 'micro': 'int'},
+           'package': 'str'} }
+
+##
+# @query-version:
+#
+# Returns the current version of QEMU.
+#
+# Returns:  A @VersionInfo object describing the current version of QEMU.
+#
+# Since: 0.14.0
+##
+{ 'command': 'query-version', 'returns': 'VersionInfo' }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 7b3839e..9f067ea 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1053,6 +1053,12 @@ Example:
 
 EQMP
 
+    {
+        .name       = "query-version",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_version,
+    },
+
 SQMP
 query-commands
 --------------
diff --git a/qmp.c b/qmp.c
index 8aa9c66..f978ea4 100644
--- a/qmp.c
+++ b/qmp.c
@@ -26,3 +26,19 @@ NameInfo *qmp_query_name(Error **errp)
 
     return info;
 }
+
+VersionInfo *qmp_query_version(Error **err)
+{
+    VersionInfo *info = g_malloc0(sizeof(*info));
+    const char *version = QEMU_VERSION;
+    char *tmp;
+
+    info->qemu.major = strtol(version, &tmp, 10);
+    tmp++;
+    info->qemu.minor = strtol(tmp, &tmp, 10);
+    tmp++;
+    info->qemu.micro = strtol(tmp, &tmp, 10);
+    info->package = g_strdup(QEMU_PKGVERSION);
+
+    return info;
+}
commit 48a32bedfed0ea5b30bdbb470c0520acdadc3bf2
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Sep 2 12:34:48 2011 -0500

    qapi: convert query-name
    
    A simple example conversion 'info name'.  This also adds the new files for
    QMP and HMP.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/Makefile.objs b/Makefile.objs
index 587ec36..a669c62 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -407,6 +407,7 @@ qapi-nested-y += qmp-registry.o qmp-dispatch.o
 qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
 
 common-obj-y += qmp-marshal.o qapi-visit.o qapi-types.o $(qapi-obj-y)
+common-obj-y += qmp.o hmp.o
 
 ######################################################################
 # guest agent
diff --git a/hmp.c b/hmp.c
new file mode 100644
index 0000000..47e1ff7
--- /dev/null
+++ b/hmp.c
@@ -0,0 +1,26 @@
+/*
+ * Human Monitor Interface
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "hmp.h"
+#include "qmp-commands.h"
+
+void hmp_info_name(Monitor *mon)
+{
+    NameInfo *info;
+
+    info = qmp_query_name(NULL);
+    if (info->has_name) {
+        monitor_printf(mon, "%s\n", info->name);
+    }
+    qapi_free_NameInfo(info);
+}
diff --git a/hmp.h b/hmp.h
new file mode 100644
index 0000000..5fe73f1
--- /dev/null
+++ b/hmp.h
@@ -0,0 +1,22 @@
+/*
+ * Human Monitor Interface
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef HMP_H
+#define HMP_H
+
+#include "qemu-common.h"
+#include "qapi-types.h"
+
+void hmp_info_name(Monitor *mon);
+
+#endif
diff --git a/monitor.c b/monitor.c
index e267d58..83b4fa7 100644
--- a/monitor.c
+++ b/monitor.c
@@ -64,6 +64,8 @@
 #include "trace/control.h"
 #include "ui/qemu-spice.h"
 #include "memory.h"
+#include "qmp-commands.h"
+#include "hmp.h"
 
 //#define DEBUG
 //#define DEBUG_COMPLETION
@@ -760,24 +762,6 @@ static void do_info_version(Monitor *mon, QObject **ret_data)
         'micro': %d }, 'package': %s }", major, minor, micro, QEMU_PKGVERSION);
 }
 
-static void do_info_name_print(Monitor *mon, const QObject *data)
-{
-    QDict *qdict;
-
-    qdict = qobject_to_qdict(data);
-    if (qdict_size(qdict) == 0) {
-        return;
-    }
-
-    monitor_printf(mon, "%s\n", qdict_get_str(qdict, "name"));
-}
-
-static void do_info_name(Monitor *mon, QObject **ret_data)
-{
-    *ret_data = qemu_name ? qobject_from_jsonf("{'name': %s }", qemu_name) :
-                            qobject_from_jsonf("{}");
-}
-
 static QObject *get_cmd_dict(const char *name)
 {
     const char *p;
@@ -3094,8 +3078,7 @@ static const mon_cmd_t info_cmds[] = {
         .args_type  = "",
         .params     = "",
         .help       = "show the current VM name",
-        .user_print = do_info_name_print,
-        .mhandler.info_new = do_info_name,
+        .mhandler.info = hmp_info_name,
     },
     {
         .name       = "uuid",
@@ -3287,14 +3270,6 @@ static const mon_cmd_t qmp_query_cmds[] = {
     },
 #endif
     {
-        .name       = "name",
-        .args_type  = "",
-        .params     = "",
-        .help       = "show the current VM name",
-        .user_print = do_info_name_print,
-        .mhandler.info_new = do_info_name,
-    },
-    {
         .name       = "uuid",
         .args_type  = "",
         .params     = "",
diff --git a/qapi-schema.json b/qapi-schema.json
index 7fcefdb..3585324 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1,3 +1,25 @@
 # -*- Mode: Python -*-
 #
 # QAPI Schema
+
+##
+# @NameInfo:
+#
+# Guest name information.
+#
+# @name: #optional The name of the guest
+#
+# Since 0.14.0
+##
+{ 'type': 'NameInfo', 'data': {'*name': 'str'} }
+
+##
+# @query-name:
+#
+# Return the name information of a guest.
+#
+# Returns: @NameInfo of the guest
+#
+# Since 0.14.0
+##
+{ 'command': 'query-name', 'returns': 'NameInfo' }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index d83bce5..7b3839e 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1780,6 +1780,12 @@ Example:
 
 EQMP
 
+    {
+        .name       = "query-name",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_name,
+    },
+
 SQMP
 query-uuid
 ----------
diff --git a/qmp.c b/qmp.c
new file mode 100644
index 0000000..8aa9c66
--- /dev/null
+++ b/qmp.c
@@ -0,0 +1,28 @@
+/*
+ * QEMU Management Protocol
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "sysemu.h"
+#include "qmp-commands.h"
+
+NameInfo *qmp_query_name(Error **errp)
+{
+    NameInfo *info = g_malloc0(sizeof(*info));
+
+    if (qemu_name) {
+        info->has_name = true;
+        info->name = g_strdup(qemu_name);
+    }
+
+    return info;
+}
commit 303b54b1a2611eda47abb28546869c49b5664f59
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Fri Sep 30 12:43:27 2011 -0300

    qapi: Automatically generate a _MAX value for enums
    
    It's the last value in the enum and is very useful for the C
    implementation.
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 3bacc0c..f64d84c 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -91,8 +91,11 @@ typedef enum %(name)s
 ''',
                 name=name)
 
+    # append automatically generated _MAX value
+    enum_values = values + [ 'MAX' ]
+
     i = 0
-    for value in values:
+    for value in enum_values:
         enum_decl += mcgen('''
     %(abbrev)s_%(value)s = %(i)d,
 ''',
commit d2a80d6bb3fdf319d28f25eb034b32a9f3da7334
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Wed Sep 28 16:56:56 2011 -0300

    qapi: Don't use c_var() on enum strings
    
    Otherwise if we have something like 'foo-bar' in the schema,
    it will be generated as 'foo_bar' in the string lookup table.
    
    c_var() is good for C variables, but not for enum strings.
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 4797a70..3bacc0c 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -70,7 +70,7 @@ const char *%(name)s_lookup[] = {
         ret += mcgen('''
     "%(value)s",
 ''',
-                     value=c_var(value).lower())
+                     value=value.lower())
 
     ret += mcgen('''
     NULL,
commit e1bc2f7b3fb19ab2abcec3d5b15e045b00ae9da1
Author: Michael Roth <mdroth at linux.vnet.ibm.com>
Date:   Mon Sep 19 19:03:11 2011 -0500

    qapi: modify visitor code generation for list iteration
    
    Modify logic such that we never assign values to the list head argument
    to progress through the list on subsequent iterations, instead rely only
    on having our return value passed back in as an argument on the next
    call. Also update QMP I/O visitors and test cases accordingly, and add a
    missing test case for QmpOutputVisitor.
    
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Michael Roth <mdroth at linux.vnet.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c
index fcf8bf9..8cbc0ab 100644
--- a/qapi/qmp-input-visitor.c
+++ b/qapi/qmp-input-visitor.c
@@ -144,8 +144,6 @@ static GenericList *qmp_input_next_list(Visitor *v, GenericList **list,
         }
         (*list)->next = entry;
     }
-    *list = entry;
-
 
     return entry;
 }
@@ -240,9 +238,11 @@ static void qmp_input_type_enum(Visitor *v, int *obj, const char *strings[],
 
     if (strings[value] == NULL) {
         error_set(errp, QERR_INVALID_PARAMETER, name ? name : "null");
+        g_free(enum_str);
         return;
     }
 
+    g_free(enum_str);
     *obj = value;
 }
 
diff --git a/qapi/qmp-output-visitor.c b/qapi/qmp-output-visitor.c
index 4419a31..d67724e 100644
--- a/qapi/qmp-output-visitor.c
+++ b/qapi/qmp-output-visitor.c
@@ -20,6 +20,7 @@
 typedef struct QStackEntry
 {
     QObject *value;
+    bool is_list_head;
     QTAILQ_ENTRY(QStackEntry) node;
 } QStackEntry;
 
@@ -45,6 +46,9 @@ static void qmp_output_push_obj(QmpOutputVisitor *qov, QObject *value)
     QStackEntry *e = g_malloc0(sizeof(*e));
 
     e->value = value;
+    if (qobject_type(e->value) == QTYPE_QLIST) {
+        e->is_list_head = true;
+    }
     QTAILQ_INSERT_HEAD(&qov->stack, e, node);
 }
 
@@ -122,12 +126,20 @@ static void qmp_output_start_list(Visitor *v, const char *name, Error **errp)
     qmp_output_push(qov, list);
 }
 
-static GenericList *qmp_output_next_list(Visitor *v, GenericList **list,
+static GenericList *qmp_output_next_list(Visitor *v, GenericList **listp,
                                          Error **errp)
 {
-    GenericList *retval = *list;
-    *list = retval->next;
-    return retval;
+    GenericList *list = *listp;
+    QmpOutputVisitor *qov = to_qov(v);
+    QStackEntry *e = QTAILQ_FIRST(&qov->stack);
+
+    assert(e);
+    if (e->is_list_head) {
+        e->is_list_head = false;
+        return list;
+    }
+
+    return list ? list->next : NULL;
 }
 
 static void qmp_output_end_list(Visitor *v, Error **errp)
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 252230e..62de83d 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -79,11 +79,11 @@ def generate_visit_list(name, members):
 
 void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp)
 {
-    GenericList *i;
+    GenericList *i, **head = (GenericList **)obj;
 
     visit_start_list(m, name, errp);
 
-    for (i = visit_next_list(m, (GenericList **)obj, errp); i; i = visit_next_list(m, &i, errp)) {
+    for (*head = i = visit_next_list(m, head, errp); i; i = visit_next_list(m, &i, errp)) {
         %(name)sList *native_i = (%(name)sList *)i;
         visit_type_%(name)s(m, &native_i->value, NULL, errp);
     }
diff --git a/test-visitor.c b/test-visitor.c
index b7717de..847ce14 100644
--- a/test-visitor.c
+++ b/test-visitor.c
@@ -27,11 +27,11 @@ static void visit_type_TestStruct(Visitor *v, TestStruct **obj, const char *name
 
 static void visit_type_TestStructList(Visitor *m, TestStructList ** obj, const char *name, Error **errp)
 {
-    GenericList *i;
+    GenericList *i, **head = (GenericList **)obj;
 
     visit_start_list(m, name, errp);
 
-    for (i = visit_next_list(m, (GenericList **)obj, errp); i; i = visit_next_list(m, &i, errp)) {
+    for (*head = i = visit_next_list(m, head, errp); i; i = visit_next_list(m, &i, errp)) {
         TestStructList *native_i = (TestStructList *)i;
         visit_type_TestStruct(m, &native_i->value, NULL, errp);
     }
@@ -50,6 +50,8 @@ static void test_visitor_core(void)
     TestStructList *lts = NULL;
     Error *err = NULL;
     QObject *obj;
+    QList *qlist;
+    QDict *qdict;
     QString *str;
     int64_t value = 0;
 
@@ -96,7 +98,9 @@ static void test_visitor_core(void)
     g_assert(pts->y == 84);
 
     qobject_decref(obj);
+    g_free(pts);
 
+    /* test list input visitor */
     obj = qobject_from_json("[{'x': 42, 'y': 84}, {'x': 12, 'y': 24}]");
     mi = qmp_input_visitor_new(obj);
     v = qmp_input_get_visitor(mi);
@@ -110,14 +114,41 @@ static void test_visitor_core(void)
     g_assert(lts->value->x == 42);
     g_assert(lts->value->y == 84);
 
-    lts = lts->next;
-    g_assert(lts != NULL);
-    g_assert(lts->value->x == 12);
-    g_assert(lts->value->y == 24);
+    g_assert(lts->next != NULL);
+    g_assert(lts->next->value->x == 12);
+    g_assert(lts->next->value->y == 24);
+    g_assert(lts->next->next == NULL);
 
-    g_assert(lts->next == NULL);
+    qobject_decref(obj);
 
+    /* test list output visitor */
+    mo = qmp_output_visitor_new();
+    v = qmp_output_get_visitor(mo);
+    visit_type_TestStructList(v, &lts, NULL, &err);
+    if (err) {
+        g_error("%s", error_get_pretty(err));
+    }
+    obj = qmp_output_get_qobject(mo);
+    g_print("obj: %s\n", qstring_get_str(qobject_to_json(obj)));
+
+    qlist = qobject_to_qlist(obj);
+    assert(qlist);
+    obj = qlist_pop(qlist);
+    qdict = qobject_to_qdict(obj);
+    assert(qdict);
+    assert(qdict_get_int(qdict, "x") == 42);
+    assert(qdict_get_int(qdict, "y") == 84);
+    qobject_decref(obj);
+
+    obj = qlist_pop(qlist);
+    qdict = qobject_to_qdict(obj);
+    assert(qdict);
+    assert(qdict_get_int(qdict, "x") == 12);
+    assert(qdict_get_int(qdict, "y") == 24);
     qobject_decref(obj);
+
+    qmp_output_visitor_cleanup(mo);
+    QDECREF(qlist);
 }
 
 /* test deep nesting with refs to other user-defined types */
@@ -286,7 +317,8 @@ static void test_nested_enums(void)
     g_assert(nested_enums_cpy->has_enum2 == false);
     g_assert(nested_enums_cpy->has_enum4 == true);
 
-    qobject_decref(obj);
+    qmp_output_visitor_cleanup(mo);
+    qmp_input_visitor_cleanup(mi);
     qapi_free_NestedEnumsOne(nested_enums);
     qapi_free_NestedEnumsOne(nested_enums_cpy);
 }
commit 0b9d854230737b214c01e89f0b679ea36fd59e5e
Author: Michael Roth <mdroth at linux.vnet.ibm.com>
Date:   Mon Sep 19 19:03:10 2011 -0500

    qapi: dealloc visitor, support freeing of nested lists
    
    Previously our logic for keeping track of when we're visiting the head
    of a list was done via a global bool. This can be overwritten if dealing
    with nested lists, so use stack entries to track this instead.
    
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Michael Roth <mdroth at linux.vnet.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/qapi/qapi-dealloc-visitor.c b/qapi/qapi-dealloc-visitor.c
index 6b586ad..a154523 100644
--- a/qapi/qapi-dealloc-visitor.c
+++ b/qapi/qapi-dealloc-visitor.c
@@ -19,6 +19,7 @@
 typedef struct StackEntry
 {
     void *value;
+    bool is_list_head;
     QTAILQ_ENTRY(StackEntry) node;
 } StackEntry;
 
@@ -39,6 +40,11 @@ static void qapi_dealloc_push(QapiDeallocVisitor *qov, void *value)
     StackEntry *e = g_malloc0(sizeof(*e));
 
     e->value = value;
+
+    /* see if we're just pushing a list head tracker */
+    if (value == NULL) {
+        e->is_list_head = true;
+    }
     QTAILQ_INSERT_HEAD(&qov->stack, e, node);
 }
 
@@ -72,7 +78,7 @@ static void qapi_dealloc_end_struct(Visitor *v, Error **errp)
 static void qapi_dealloc_start_list(Visitor *v, const char *name, Error **errp)
 {
     QapiDeallocVisitor *qov = to_qov(v);
-    qov->is_list_head = true;
+    qapi_dealloc_push(qov, NULL);
 }
 
 static GenericList *qapi_dealloc_next_list(Visitor *v, GenericList **listp,
@@ -80,19 +86,27 @@ static GenericList *qapi_dealloc_next_list(Visitor *v, GenericList **listp,
 {
     GenericList *list = *listp;
     QapiDeallocVisitor *qov = to_qov(v);
+    StackEntry *e = QTAILQ_FIRST(&qov->stack);
 
-    if (!qov->is_list_head) {
-        *listp = list->next;
-        g_free(list);
-        return *listp;
+    if (e && e->is_list_head) {
+        e->is_list_head = false;
+        return list;
     }
 
-    qov->is_list_head = false;
-    return list;
+    if (list) {
+        list = list->next;
+        g_free(*listp);
+        return list;
+    }
+
+    return NULL;
 }
 
 static void qapi_dealloc_end_list(Visitor *v, Error **errp)
 {
+    QapiDeallocVisitor *qov = to_qov(v);
+    void *obj = qapi_dealloc_pop(qov);
+    assert(obj == NULL); /* should've been list head tracker with no payload */
 }
 
 static void qapi_dealloc_type_str(Visitor *v, char **obj, const char *name,
commit 5cd5f0d059ecb9ce8cc214b5e7b8b6d473b50964
Author: Michael Roth <mdroth at linux.vnet.ibm.com>
Date:   Thu Sep 15 14:39:54 2011 -0500

    qapi: add test cases for generated free functions
    
    Signed-off-by: Michael Roth <mdroth at linux.vnet.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/test-qmp-commands.c b/test-qmp-commands.c
index f142cc6..fa5a7bd 100644
--- a/test-qmp-commands.c
+++ b/test-qmp-commands.c
@@ -98,6 +98,34 @@ static void test_dispatch_cmd_io(void)
     QDECREF(req);
 }
 
+/* test generated dealloc functions for generated types */
+static void test_dealloc_types(void)
+{
+    UserDefOne *ud1test, *ud1a, *ud1b;
+    UserDefOneList *ud1list;
+
+    ud1test = g_malloc0(sizeof(UserDefOne));
+    ud1test->integer = 42;
+    ud1test->string = g_strdup("hi there 42");
+
+    qapi_free_UserDefOne(ud1test);
+
+    ud1a = g_malloc0(sizeof(UserDefOne));
+    ud1a->integer = 43;
+    ud1a->string = g_strdup("hi there 43");
+
+    ud1b = g_malloc0(sizeof(UserDefOne));
+    ud1b->integer = 44;
+    ud1b->string = g_strdup("hi there 44");
+
+    ud1list = g_malloc0(sizeof(UserDefOneList));
+    ud1list->value = ud1a;
+    ud1list->next = g_malloc0(sizeof(UserDefOneList));
+    ud1list->next->value = ud1b;
+
+    qapi_free_UserDefOneList(ud1list);
+}
+
 int main(int argc, char **argv)
 {
     g_test_init(&argc, &argv, NULL);
@@ -105,6 +133,7 @@ int main(int argc, char **argv)
     g_test_add_func("/0.15/dispatch_cmd", test_dispatch_cmd);
     g_test_add_func("/0.15/dispatch_cmd_error", test_dispatch_cmd_error);
     g_test_add_func("/0.15/dispatch_cmd_io", test_dispatch_cmd_io);
+    g_test_add_func("/0.15/dealloc_types", test_dealloc_types);
 
     module_call_init(MODULE_INIT_QAPI);
     g_test_run();
commit 75b96aca6ff53c7e782efe670045376df4f7d199
Author: Michael Roth <mdroth at linux.vnet.ibm.com>
Date:   Thu Sep 15 14:39:53 2011 -0500

    qapi: generate qapi_free_* functions for *List types
    
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Michael Roth <mdroth at linux.vnet.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index fc0f7af..4797a70 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -254,6 +254,8 @@ for expr in exprs:
     ret = "\n"
     if expr.has_key('type'):
         ret += generate_struct(expr['type'], "", expr['data']) + "\n"
+        ret += generate_type_cleanup_decl(expr['type'] + "List")
+        fdef.write(generate_type_cleanup(expr['type'] + "List") + "\n")
         ret += generate_type_cleanup_decl(expr['type'])
         fdef.write(generate_type_cleanup(expr['type']) + "\n")
     elif expr.has_key('union'):
commit 5666dd19dd95d966be00d0c3e7efdfaecc096ff3
Author: Michael Roth <mdroth at linux.vnet.ibm.com>
Date:   Thu Sep 15 14:39:52 2011 -0500

    qapi: dealloc visitor, fix premature free and iteration logic
    
    Currently we do 3 things wrong:
    
    1) The list iterator, in practice, is used in a manner where the pointer
    we pass in is the same as the pointer we assign the output to from
    visit_next_list(). This causes an infinite loop where we keep freeing
    the same structures.
    
    2) We attempt to free list->value rather than list. visit_type_<type>
    handles this. We should only be concerned with the containing list.
    
    3) We free prematurely: iterator function will continue accessing values
    we've already freed.
    
    This patch should fix all of these issues. QmpOutputVisitor also suffers
    from 1).
    
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Michael Roth <mdroth at linux.vnet.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/qapi/qapi-dealloc-visitor.c b/qapi/qapi-dealloc-visitor.c
index f629061..6b586ad 100644
--- a/qapi/qapi-dealloc-visitor.c
+++ b/qapi/qapi-dealloc-visitor.c
@@ -26,6 +26,7 @@ struct QapiDeallocVisitor
 {
     Visitor visitor;
     QTAILQ_HEAD(, StackEntry) stack;
+    bool is_list_head;
 };
 
 static QapiDeallocVisitor *to_qov(Visitor *v)
@@ -70,15 +71,24 @@ static void qapi_dealloc_end_struct(Visitor *v, Error **errp)
 
 static void qapi_dealloc_start_list(Visitor *v, const char *name, Error **errp)
 {
+    QapiDeallocVisitor *qov = to_qov(v);
+    qov->is_list_head = true;
 }
 
-static GenericList *qapi_dealloc_next_list(Visitor *v, GenericList **list,
+static GenericList *qapi_dealloc_next_list(Visitor *v, GenericList **listp,
                                            Error **errp)
 {
-    GenericList *retval = *list;
-    g_free(retval->value);
-    *list = retval->next;
-    return retval;
+    GenericList *list = *listp;
+    QapiDeallocVisitor *qov = to_qov(v);
+
+    if (!qov->is_list_head) {
+        *listp = list->next;
+        g_free(list);
+        return *listp;
+    }
+
+    qov->is_list_head = false;
+    return list;
 }
 
 static void qapi_dealloc_end_list(Visitor *v, Error **errp)
commit 15e43e64b6bac61811e829634ee048e8de4c976d
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Wed Sep 14 14:30:00 2011 -0500

    qapi: fixup command generation for functions that return list types
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index 2776804..c947ba4 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -17,12 +17,18 @@ import os
 import getopt
 import errno
 
+def type_visitor(name):
+    if type(name) == list:
+        return 'visit_type_%sList' % name[0]
+    else:
+        return 'visit_type_%s' % name
+
 def generate_decl_enum(name, members, genlist=True):
     return mcgen('''
 
-void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp);
+void %(visitor)s(Visitor *m, %(name)s * obj, const char *name, Error **errp);
 ''',
-                name=name)
+                 visitor=type_visitor(name))
 
 def generate_command_decl(name, args, ret_type):
     arglist=""
@@ -146,9 +152,10 @@ if (has_%(c_name)s) {
                          c_name=c_var(argname), name=argname)
             push_indent()
         ret += mcgen('''
-visit_type_%(argtype)s(v, &%(c_name)s, "%(name)s", errp);
+%(visitor)s(v, &%(c_name)s, "%(name)s", errp);
 ''',
-                      c_name=c_var(argname), name=argname, argtype=argtype)
+                     c_name=c_var(argname), name=argname, argtype=argtype,
+                     visitor=type_visitor(argtype))
         if optional:
             pop_indent()
             ret += mcgen('''
@@ -179,18 +186,18 @@ static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_o
     Visitor *v;
 
     v = qmp_output_get_visitor(mo);
-    visit_type_%(ret_type)s(v, &ret_in, "unused", errp);
+    %(visitor)s(v, &ret_in, "unused", errp);
     if (!error_is_set(errp)) {
         *ret_out = qmp_output_get_qobject(mo);
     }
     qmp_output_visitor_cleanup(mo);
     v = qapi_dealloc_get_visitor(md);
-    visit_type_%(ret_type)s(v, &ret_in, "unused", errp);
+    %(visitor)s(v, &ret_in, "unused", errp);
     qapi_dealloc_visitor_cleanup(md);
 }
 ''',
-                 c_ret_type=c_type(ret_type), c_name=c_var(name),
-                 ret_type=ret_type)
+                c_ret_type=c_type(ret_type), c_name=c_var(name),
+                visitor=type_visitor(ret_type))
 
     return ret
 
commit e3193601c84558c303b1773379da76fce80c0a56
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Sep 2 12:34:47 2011 -0500

    qapi: use middle mode in QMP server
    
    Use the new middle mode within the existing QMP server.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/Makefile b/Makefile
index 6ed3194..55ee79c 100644
--- a/Makefile
+++ b/Makefile
@@ -7,6 +7,7 @@ GENERATED_HEADERS = config-host.h trace.h qemu-options.def
 ifeq ($(TRACE_BACKEND),dtrace)
 GENERATED_HEADERS += trace-dtrace.h
 endif
+GENERATED_HEADERS += qmp-commands.h qapi-types.h qapi-visit.h
 
 ifneq ($(wildcard config-host.mak),)
 # Put the all: rule here so that config-host.mak can contain dependencies.
@@ -187,9 +188,20 @@ $(qapi-dir)/qga-qapi-types.h: $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scr
 $(qapi-dir)/qga-qapi-visit.c: $(qapi-dir)/qga-qapi-visit.h
 $(qapi-dir)/qga-qapi-visit.h: $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-visit.py
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py -o "$(qapi-dir)" -p "qga-" < $<, "  GEN   $@")
+$(qapi-dir)/qga-qmp-commands.h: $(qapi-dir)/qga-qmp-marshal.c
 $(qapi-dir)/qga-qmp-marshal.c: $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-commands.py
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py -o "$(qapi-dir)" -p "qga-" < $<, "  GEN   $@")
 
+qapi-types.c: qapi-types.h
+qapi-types.h: $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py -o "." < $<, "  GEN   $@")
+qapi-visit.c: qapi-visit.h
+qapi-visit.h: $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py -o "."  < $<, "  GEN   $@")
+qmp-commands.h: qmp-marshal.c
+qmp-marshal.c: $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py -m -o "." < $<, "  GEN   $@")
+
 test-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
 test-visitor: test-visitor.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o $(qapi-obj-y) error.o osdep.o $(oslib-obj-y) qjson.o json-streamer.o json-lexer.o json-parser.o qerror.o qemu-error.o qemu-tool.o $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
 
diff --git a/Makefile.objs b/Makefile.objs
index 8d23fbb..587ec36 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -406,6 +406,8 @@ qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o qmp-output-visitor.o qapi-
 qapi-nested-y += qmp-registry.o qmp-dispatch.o
 qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
 
+common-obj-y += qmp-marshal.o qapi-visit.o qapi-types.o $(qapi-obj-y)
+
 ######################################################################
 # guest agent
 
diff --git a/Makefile.target b/Makefile.target
index 88d2f1f..b5ed5df 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -375,7 +375,7 @@ obj-xtensa-y += xtensa-semi.o
 
 main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
 
-monitor.o: hmp-commands.h qmp-commands.h
+monitor.o: hmp-commands.h qmp-commands-old.h
 
 $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y): $(GENERATED_HEADERS)
 
@@ -407,13 +407,13 @@ gdbstub-xml.c: $(TARGET_XML_FILES) $(SRC_PATH)/scripts/feature_to_c.sh
 hmp-commands.h: $(SRC_PATH)/hmp-commands.hx
 	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"  GEN   $(TARGET_DIR)$@")
 
-qmp-commands.h: $(SRC_PATH)/qmp-commands.hx
+qmp-commands-old.h: $(SRC_PATH)/qmp-commands.hx
 	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"  GEN   $(TARGET_DIR)$@")
 
 clean:
 	rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o
 	rm -f *.d */*.d tcg/*.o ide/*.o 9pfs/*.o
-	rm -f hmp-commands.h qmp-commands.h gdbstub-xml.c
+	rm -f hmp-commands.h qmp-commands-old.h gdbstub-xml.c
 ifdef CONFIG_TRACE_SYSTEMTAP
 	rm -f *.stp
 endif
diff --git a/monitor.c b/monitor.c
index d323ea5..e267d58 100644
--- a/monitor.c
+++ b/monitor.c
@@ -122,6 +122,7 @@ typedef struct mon_cmd_t {
         int  (*cmd_async)(Monitor *mon, const QDict *params,
                           MonitorCompletion *cb, void *opaque);
     } mhandler;
+    bool qapi;
     int flags;
 } mon_cmd_t;
 
@@ -3182,7 +3183,7 @@ static const mon_cmd_t info_cmds[] = {
 };
 
 static const mon_cmd_t qmp_cmds[] = {
-#include "qmp-commands.h"
+#include "qmp-commands-old.h"
     { /* NULL */ },
 };
 
@@ -5107,12 +5108,10 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
         goto err_out;
     }
 
-    if (strstart(cmd_name, "query-", &query_cmd)) {
+    cmd = qmp_find_cmd(cmd_name);
+    if (!cmd && strstart(cmd_name, "query-", &query_cmd)) {
         cmd = qmp_find_query_cmd(query_cmd);
-    } else {
-        cmd = qmp_find_cmd(cmd_name);
     }
-
     if (!cmd) {
         qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name);
         goto err_out;
diff --git a/qapi-schema.json b/qapi-schema.json
new file mode 100644
index 0000000..7fcefdb
--- /dev/null
+++ b/qapi-schema.json
@@ -0,0 +1,3 @@
+# -*- Mode: Python -*-
+#
+# QAPI Schema
commit 776574d6417cf623fb071987cdd2c6bc13271dc2
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Sep 2 12:34:46 2011 -0500

    qapi: add code generation support for middle mode
    
    To get the ball rolling merging QAPI, this patch introduces a "middle mode" to
    the code generator.  In middle mode, the code generator generates marshalling
    functions that are compatible with the current QMP server.  We absolutely need
    to replace the current QMP server in order to support proper asynchronous
    commands but using a middle mode provides a middle-ground that lets us start
    converting commands in tree.
    
    Note that all of the commands have been converted already in my glib branch.
    Middle mode only exists until we finish merging them from my branch into the
    main tree.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/qapi/qapi-types-core.h b/qapi/qapi-types-core.h
index a79bc2b..27e6be0 100644
--- a/qapi/qapi-types-core.h
+++ b/qapi/qapi-types-core.h
@@ -17,4 +17,7 @@
 #include "qemu-common.h"
 #include "error.h"
 
+/* FIXME this is temporary until we remove middle mode */
+#include "monitor.h"
+
 #endif
diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index bf61740..2776804 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -167,9 +167,10 @@ qmp_input_visitor_cleanup(mi);
     pop_indent()
     return ret.rstrip()
 
-def gen_marshal_output(name, args, ret_type):
+def gen_marshal_output(name, args, ret_type, middle_mode):
     if not ret_type:
         return ""
+
     ret = mcgen('''
 static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_out, Error **errp)
 {
@@ -188,16 +189,34 @@ static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_o
     qapi_dealloc_visitor_cleanup(md);
 }
 ''',
-            c_ret_type=c_type(ret_type), c_name=c_var(name), ret_type=ret_type)
+                 c_ret_type=c_type(ret_type), c_name=c_var(name),
+                 ret_type=ret_type)
 
     return ret
 
-def gen_marshal_input(name, args, ret_type):
+def gen_marshal_input_decl(name, args, ret_type, middle_mode):
+    if middle_mode:
+        return 'int qmp_marshal_input_%s(Monitor *mon, const QDict *qdict, QObject **ret)' % c_var(name)
+    else:
+        return 'static void qmp_marshal_input_%s(QDict *args, QObject **ret, Error **errp)' % c_var(name)
+
+
+
+def gen_marshal_input(name, args, ret_type, middle_mode):
+    hdr = gen_marshal_input_decl(name, args, ret_type, middle_mode)
+
     ret = mcgen('''
-static void qmp_marshal_input_%(c_name)s(QDict *args, QObject **ret, Error **errp)
+%(header)s
 {
 ''',
-                c_name=c_var(name))
+                header=hdr)
+
+    if middle_mode:
+        ret += mcgen('''
+    Error *local_err = NULL;
+    Error **errp = &local_err;
+    QDict *args = (QDict *)qdict;
+''')
 
     if ret_type:
         if c_type(ret_type).endswith("*"):
@@ -220,6 +239,10 @@ static void qmp_marshal_input_%(c_name)s(QDict *args, QObject **ret, Error **err
                      visitor_input_containers_decl=gen_visitor_input_containers_decl(args),
                      visitor_input_vars_decl=gen_visitor_input_vars_decl(args),
                      visitor_input_block=gen_visitor_input_block(args, "QOBJECT(args)"))
+    else:
+        ret += mcgen('''
+    (void)args;
+''')
 
     ret += mcgen('''
     if (error_is_set(errp)) {
@@ -234,10 +257,29 @@ out:
 ''')
     ret += mcgen('''
 %(visitor_input_block_cleanup)s
+''',
+                 visitor_input_block_cleanup=gen_visitor_input_block(args, None,
+                                                                     dealloc=True))
+
+    if middle_mode:
+        ret += mcgen('''
+
+    if (local_err) {
+        qerror_report_err(local_err);
+        error_free(local_err);
+        return -1;
+    }
+    return 0;
+''')
+    else:
+        ret += mcgen('''
     return;
+''')
+
+    ret += mcgen('''
 }
-''',
-                 visitor_input_block_cleanup=gen_visitor_input_block(args, None, dealloc=True))
+''')
+
     return ret
 
 def gen_registry(commands):
@@ -284,7 +326,7 @@ def gen_command_decl_prologue(header, guard, prefix=""):
 #include "error.h"
 
 ''',
-                 header=basename(h_file), guard=guardname(h_file), prefix=prefix)
+                 header=basename(header), guard=guardname(header), prefix=prefix)
     return ret
 
 def gen_command_def_prologue(prefix="", proxy=False):
@@ -317,11 +359,11 @@ def gen_command_def_prologue(prefix="", proxy=False):
                 prefix=prefix)
     if not proxy:
         ret += '#include "%sqmp-commands.h"' % prefix
-    return ret + "\n"
+    return ret + "\n\n"
 
 
 try:
-    opts, args = getopt.gnu_getopt(sys.argv[1:], "p:o:", ["prefix=", "output-dir=", "type="])
+    opts, args = getopt.gnu_getopt(sys.argv[1:], "p:o:m", ["prefix=", "output-dir=", "type=", "middle"])
 except getopt.GetoptError, err:
     print str(err)
     sys.exit(1)
@@ -331,6 +373,7 @@ prefix = ""
 dispatch_type = "sync"
 c_file = 'qmp-marshal.c'
 h_file = 'qmp-commands.h'
+middle_mode = False
 
 for o, a in opts:
     if o in ("-p", "--prefix"):
@@ -339,6 +382,8 @@ for o, a in opts:
         output_dir = a + "/"
     elif o in ("-t", "--type"):
         dispatch_type = a
+    elif o in ("-m", "--middle"):
+        middle_mode = True
 
 c_file = output_dir + prefix + c_file
 h_file = output_dir + prefix + h_file
@@ -370,14 +415,20 @@ if dispatch_type == "sync":
         ret = generate_command_decl(cmd['command'], arglist, ret_type) + "\n"
         fdecl.write(ret)
         if ret_type:
-            ret = gen_marshal_output(cmd['command'], arglist, ret_type) + "\n"
+            ret = gen_marshal_output(cmd['command'], arglist, ret_type, middle_mode) + "\n"
             fdef.write(ret)
-        ret = gen_marshal_input(cmd['command'], arglist, ret_type) + "\n"
+
+        if middle_mode:
+            fdecl.write('%s;\n' % gen_marshal_input_decl(cmd['command'], arglist, ret_type, middle_mode))
+
+        ret = gen_marshal_input(cmd['command'], arglist, ret_type, middle_mode) + "\n"
         fdef.write(ret)
 
     fdecl.write("\n#endif\n");
-    ret = gen_registry(commands)
-    fdef.write(ret)
+
+    if not middle_mode:
+        ret = gen_registry(commands)
+        fdef.write(ret)
 
     fdef.flush()
     fdef.close()
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index cece325..fc0f7af 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -268,3 +268,6 @@ fdecl.write('''
 
 fdecl.flush()
 fdecl.close()
+
+fdef.flush()
+fdef.close()
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 56af232..5299976 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -200,4 +200,6 @@ def basename(filename):
     return filename.split("/")[-1]
 
 def guardname(filename):
-    return filename.replace("/", "_").replace("-", "_").split(".")[0].upper()
+    if filename.startswith('./'):
+        filename = filename[2:]
+    return filename.replace("/", "_").replace("-", "_").split(".")[0].upper() + '_H'
commit 2a82d936a2bda9cb01d05fc91845e82001b78632
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Sep 2 12:34:45 2011 -0500

    qerror: add qerror_report_err()
    
    This provides a bridge between Error (new error mechanism) and QError (old error
    mechanism).  Errors can be propagated whereas QError cannot.
    
    The minor evilness avoids layering violations.  Since QError should go away RSN,
    it seems like a reasonable hack.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/qerror.c b/qerror.c
index c591a54..68998d4 100644
--- a/qerror.c
+++ b/qerror.c
@@ -482,6 +482,39 @@ void qerror_report_internal(const char *file, int linenr, const char *func,
     }
 }
 
+/* Evil... */
+struct Error
+{
+    QDict *obj;
+    const char *fmt;
+    char *msg;
+};
+
+void qerror_report_err(Error *err)
+{
+    QError *qerr;
+    int i;
+
+    qerr = qerror_new();
+    loc_save(&qerr->loc);
+    QINCREF(err->obj);
+    qerr->error = err->obj;
+
+    for (i = 0; qerror_table[i].error_fmt; i++) {
+        if (strcmp(qerror_table[i].error_fmt, err->fmt) == 0) {
+            qerr->entry = &qerror_table[i];
+            break;
+        }
+    }
+
+    if (monitor_cur_is_qmp()) {
+        monitor_set_error(cur_mon, qerr);
+    } else {
+        qerror_print(qerr);
+        QDECREF(qerr);
+    }
+}
+
 /**
  * qobject_to_qerror(): Convert a QObject into a QError
  */
diff --git a/qerror.h b/qerror.h
index d407001..d4bfcfd 100644
--- a/qerror.h
+++ b/qerror.h
@@ -15,6 +15,7 @@
 #include "qdict.h"
 #include "qstring.h"
 #include "qemu-error.h"
+#include "error.h"
 #include <stdarg.h>
 
 typedef struct QErrorStringTable {
@@ -39,6 +40,7 @@ QString *qerror_human(const QError *qerror);
 void qerror_print(QError *qerror);
 void qerror_report_internal(const char *file, int linenr, const char *func,
                             const char *fmt, ...) GCC_FMT_ATTR(4, 5);
+void qerror_report_err(Error *err);
 QString *qerror_format(const char *fmt, QDict *error);
 #define qerror_report(fmt, ...) \
     qerror_report_internal(__FILE__, __LINE__, __func__, fmt, ## __VA_ARGS__)
commit acceb4d99fcdabded6ba432402365adb63205196
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Sep 2 12:34:44 2011 -0500

    error: let error_is_type take a NULL error
    
    Reported-by: Luiz Capitulino <lcapitulino at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/error.c b/error.c
index b802752..68c0039 100644
--- a/error.c
+++ b/error.c
@@ -97,6 +97,10 @@ bool error_is_type(Error *err, const char *fmt)
     char *ptr;
     char *end;
 
+    if (!err) {
+        return false;
+    }
+
     ptr = strstr(fmt, "'class': '");
     assert(ptr != NULL);
     ptr += strlen("'class': '");
commit bfc2455ddbb41148494a084d15777e6bed7533c3
Author: Liu, Jinsong <jinsong.liu at intel.com>
Date:   Sun Sep 25 16:10:48 2011 +0800

    kvm: support TSC deadline MSR
    
    KVM add emulation of lapic tsc deadline timer for guest.
    This patch is co-operation work at qemu side.
    
    Signed-off-by: Liu, Jinsong <jinsong.liu at intel.com>
    Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>

diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index ae36489..a973f2e 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -283,6 +283,7 @@
 #define MSR_IA32_APICBASE_BSP           (1<<8)
 #define MSR_IA32_APICBASE_ENABLE        (1<<11)
 #define MSR_IA32_APICBASE_BASE          (0xfffff<<12)
+#define MSR_IA32_TSCDEADLINE            0x6e0
 
 #define MSR_MTRRcap			0xfe
 #define MSR_MTRRcap_VCNT		8
@@ -687,6 +688,7 @@ typedef struct CPUX86State {
     uint64_t async_pf_en_msr;
 
     uint64_t tsc;
+    uint64_t tsc_deadline;
 
     uint64_t mcg_status;
 
@@ -947,7 +949,7 @@ uint64_t cpu_get_tsc(CPUX86State *env);
 #define cpu_list_id x86_cpu_list
 #define cpudef_setup	x86_cpudef_setup
 
-#define CPU_SAVE_VERSION 12
+#define CPU_SAVE_VERSION 13
 
 /* MMU modes definitions */
 #define MMU_MODE0_SUFFIX _kernel
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index b6eef04..90a6ffb 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -59,6 +59,7 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
 
 static bool has_msr_star;
 static bool has_msr_hsave_pa;
+static bool has_msr_tsc_deadline;
 static bool has_msr_async_pf_en;
 static int lm_capable_kernel;
 
@@ -568,6 +569,10 @@ static int kvm_get_supported_msrs(KVMState *s)
                     has_msr_hsave_pa = true;
                     continue;
                 }
+                if (kvm_msr_list->indices[i] == MSR_IA32_TSCDEADLINE) {
+                    has_msr_tsc_deadline = true;
+                    continue;
+                }
             }
         }
 
@@ -881,6 +886,9 @@ static int kvm_put_msrs(CPUState *env, int level)
     if (has_msr_hsave_pa) {
         kvm_msr_entry_set(&msrs[n++], MSR_VM_HSAVE_PA, env->vm_hsave);
     }
+    if (has_msr_tsc_deadline) {
+        kvm_msr_entry_set(&msrs[n++], MSR_IA32_TSCDEADLINE, env->tsc_deadline);
+    }
 #ifdef TARGET_X86_64
     if (lm_capable_kernel) {
         kvm_msr_entry_set(&msrs[n++], MSR_CSTAR, env->cstar);
@@ -1127,6 +1135,9 @@ static int kvm_get_msrs(CPUState *env)
     if (has_msr_hsave_pa) {
         msrs[n++].index = MSR_VM_HSAVE_PA;
     }
+    if (has_msr_tsc_deadline) {
+        msrs[n++].index = MSR_IA32_TSCDEADLINE;
+    }
 
     if (!env->tsc_valid) {
         msrs[n++].index = MSR_IA32_TSC;
@@ -1195,6 +1206,9 @@ static int kvm_get_msrs(CPUState *env)
         case MSR_IA32_TSC:
             env->tsc = msrs[i].data;
             break;
+        case MSR_IA32_TSCDEADLINE:
+            env->tsc_deadline = msrs[i].data;
+            break;
         case MSR_VM_HSAVE_PA:
             env->vm_hsave = msrs[i].data;
             break;
diff --git a/target-i386/machine.c b/target-i386/machine.c
index 9aca8e0..25fa97d 100644
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -410,6 +410,7 @@ static const VMStateDescription vmstate_cpu = {
         VMSTATE_UINT64_V(xcr0, CPUState, 12),
         VMSTATE_UINT64_V(xstate_bv, CPUState, 12),
         VMSTATE_YMMH_REGS_VARS(ymmh_regs, CPUState, CPU_NB_REGS, 12),
+        VMSTATE_UINT64_V(tsc_deadline, CPUState, 13),
         VMSTATE_END_OF_LIST()
         /* The above list is not sorted /wrt version numbers, watch out! */
     },
commit 779277cab4ab748dea3dfc8c8e035c7a40523e1b
Author: Michael Walle <michael at walle.cc>
Date:   Fri Sep 16 00:48:34 2011 +0200

    milkymist: new interrupt map
    
    Due to the new uart core version the interrupt mapping has changed.
    
    Signed-off-by: Michael Walle <michael at walle.cc>

diff --git a/hw/milkymist.c b/hw/milkymist.c
index 6d99260..b7a8c1c 100644
--- a/hw/milkymist.c
+++ b/hw/milkymist.c
@@ -147,16 +147,16 @@ milkymist_init(ram_addr_t ram_size_not_used,
     }
 
     milkymist_uart_create(0x60000000, irq[0]);
-    milkymist_sysctl_create(0x60001000, irq[2], irq[3], irq[4],
+    milkymist_sysctl_create(0x60001000, irq[1], irq[2], irq[3],
             80000000, 0x10014d31, 0x0000041f, 0x00000001);
     milkymist_hpdmc_create(0x60002000);
     milkymist_vgafb_create(0x60003000, 0x40000000, 0x0fffffff);
     milkymist_memcard_create(0x60004000);
-    milkymist_ac97_create(0x60005000, irq[5], irq[6], irq[7], irq[8]);
-    milkymist_pfpu_create(0x60006000, irq[9]);
-    milkymist_tmu2_create(0x60007000, irq[10]);
-    milkymist_minimac2_create(0x60008000, 0x30000000, irq[11], irq[12]);
-    milkymist_softusb_create(0x6000f000, irq[17],
+    milkymist_ac97_create(0x60005000, irq[4], irq[5], irq[6], irq[7]);
+    milkymist_pfpu_create(0x60006000, irq[8]);
+    milkymist_tmu2_create(0x60007000, irq[9]);
+    milkymist_minimac2_create(0x60008000, 0x30000000, irq[10], irq[11]);
+    milkymist_softusb_create(0x6000f000, irq[15],
             0x20000000, 0x1000, 0x20020000, 0x2000);
 
     /* make sure juart isn't the first chardev */
commit fcfa339778a624dd67bb2def664ec6aabb497ba8
Author: Michael Walle <michael at walle.cc>
Date:   Thu Aug 11 00:13:23 2011 +0200

    milkymist_uart: support new core version
    
    The new version of the uart core introduces status and control bits.
    
    Signed-off-by: Michael Walle <michael at walle.cc>

diff --git a/hw/milkymist-hw.h b/hw/milkymist-hw.h
index 20de68e..9f358a7 100644
--- a/hw/milkymist-hw.h
+++ b/hw/milkymist-hw.h
@@ -5,15 +5,14 @@
 #include "qdev-addr.h"
 
 static inline DeviceState *milkymist_uart_create(target_phys_addr_t base,
-        qemu_irq rx_irq, qemu_irq tx_irq)
+        qemu_irq irq)
 {
     DeviceState *dev;
 
     dev = qdev_create(NULL, "milkymist-uart");
     qdev_init_nofail(dev);
     sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
-    sysbus_connect_irq(sysbus_from_qdev(dev), 0, rx_irq);
-    sysbus_connect_irq(sysbus_from_qdev(dev), 1, tx_irq);
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
 
     return dev;
 }
diff --git a/hw/milkymist-uart.c b/hw/milkymist-uart.c
index e8e309d..d836462 100644
--- a/hw/milkymist-uart.c
+++ b/hw/milkymist-uart.c
@@ -30,19 +30,53 @@
 enum {
     R_RXTX = 0,
     R_DIV,
+    R_STAT,
+    R_CTRL,
+    R_DBG,
     R_MAX
 };
 
+enum {
+    STAT_THRE   = (1<<0),
+    STAT_RX_EVT = (1<<1),
+    STAT_TX_EVT = (1<<2),
+};
+
+enum {
+    CTRL_RX_IRQ_EN = (1<<0),
+    CTRL_TX_IRQ_EN = (1<<1),
+    CTRL_THRU_EN   = (1<<2),
+};
+
+enum {
+    DBG_BREAK_EN = (1<<0),
+};
+
 struct MilkymistUartState {
     SysBusDevice busdev;
     CharDriverState *chr;
-    qemu_irq rx_irq;
-    qemu_irq tx_irq;
+    qemu_irq irq;
 
     uint32_t regs[R_MAX];
 };
 typedef struct MilkymistUartState MilkymistUartState;
 
+static void uart_update_irq(MilkymistUartState *s)
+{
+    int rx_event = s->regs[R_STAT] & STAT_RX_EVT;
+    int tx_event = s->regs[R_STAT] & STAT_TX_EVT;
+    int rx_irq_en = s->regs[R_CTRL] & CTRL_RX_IRQ_EN;
+    int tx_irq_en = s->regs[R_CTRL] & CTRL_TX_IRQ_EN;
+
+    if ((rx_irq_en && rx_event) || (tx_irq_en && tx_event)) {
+        trace_milkymist_uart_raise_irq();
+        qemu_irq_raise(s->irq);
+    } else {
+        trace_milkymist_uart_lower_irq();
+        qemu_irq_lower(s->irq);
+    }
+}
+
 static uint32_t uart_read(void *opaque, target_phys_addr_t addr)
 {
     MilkymistUartState *s = opaque;
@@ -51,7 +85,12 @@ static uint32_t uart_read(void *opaque, target_phys_addr_t addr)
     addr >>= 2;
     switch (addr) {
     case R_RXTX:
+        r = s->regs[addr];
+        break;
     case R_DIV:
+    case R_STAT:
+    case R_CTRL:
+    case R_DBG:
         r = s->regs[addr];
         break;
 
@@ -79,18 +118,26 @@ static void uart_write(void *opaque, target_phys_addr_t addr, uint32_t value)
         if (s->chr) {
             qemu_chr_fe_write(s->chr, &ch, 1);
         }
-        trace_milkymist_uart_pulse_irq_tx();
-        qemu_irq_pulse(s->tx_irq);
+        s->regs[R_STAT] |= STAT_TX_EVT;
         break;
     case R_DIV:
+    case R_CTRL:
+    case R_DBG:
         s->regs[addr] = value;
         break;
 
+    case R_STAT:
+        /* write one to clear bits */
+        s->regs[addr] &= ~(value & (STAT_RX_EVT | STAT_TX_EVT));
+        break;
+
     default:
         error_report("milkymist_uart: write access to unknown register 0x"
                 TARGET_FMT_plx, addr << 2);
         break;
     }
+
+    uart_update_irq(s);
 }
 
 static CPUReadMemoryFunc * const uart_read_fn[] = {
@@ -109,14 +156,19 @@ static void uart_rx(void *opaque, const uint8_t *buf, int size)
 {
     MilkymistUartState *s = opaque;
 
+    assert(!(s->regs[R_STAT] & STAT_RX_EVT));
+
+    s->regs[R_STAT] |= STAT_RX_EVT;
     s->regs[R_RXTX] = *buf;
-    trace_milkymist_uart_pulse_irq_rx();
-    qemu_irq_pulse(s->rx_irq);
+
+    uart_update_irq(s);
 }
 
 static int uart_can_rx(void *opaque)
 {
-    return 1;
+    MilkymistUartState *s = opaque;
+
+    return !(s->regs[R_STAT] & STAT_RX_EVT);
 }
 
 static void uart_event(void *opaque, int event)
@@ -131,6 +183,9 @@ static void milkymist_uart_reset(DeviceState *d)
     for (i = 0; i < R_MAX; i++) {
         s->regs[i] = 0;
     }
+
+    /* THRE is always set */
+    s->regs[R_STAT] = STAT_THRE;
 }
 
 static int milkymist_uart_init(SysBusDevice *dev)
@@ -138,8 +193,7 @@ static int milkymist_uart_init(SysBusDevice *dev)
     MilkymistUartState *s = FROM_SYSBUS(typeof(*s), dev);
     int uart_regs;
 
-    sysbus_init_irq(dev, &s->rx_irq);
-    sysbus_init_irq(dev, &s->tx_irq);
+    sysbus_init_irq(dev, &s->irq);
 
     uart_regs = cpu_register_io_memory(uart_read_fn, uart_write_fn, s,
             DEVICE_NATIVE_ENDIAN);
diff --git a/hw/milkymist.c b/hw/milkymist.c
index bca0a58..6d99260 100644
--- a/hw/milkymist.c
+++ b/hw/milkymist.c
@@ -146,7 +146,7 @@ milkymist_init(ram_addr_t ram_size_not_used,
         exit(1);
     }
 
-    milkymist_uart_create(0x60000000, irq[0], irq[1]);
+    milkymist_uart_create(0x60000000, irq[0]);
     milkymist_sysctl_create(0x60001000, irq[2], irq[3], irq[4],
             80000000, 0x10014d31, 0x0000041f, 0x00000001);
     milkymist_hpdmc_create(0x60002000);
diff --git a/trace-events b/trace-events
index b7ddf14..1fc1858 100644
--- a/trace-events
+++ b/trace-events
@@ -444,8 +444,8 @@ milkymist_tmu2_pulse_irq(void) "Pulse IRQ"
 # hw/milkymist-uart.c
 milkymist_uart_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
 milkymist_uart_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
-milkymist_uart_pulse_irq_rx(void) "Pulse IRQ RX"
-milkymist_uart_pulse_irq_tx(void) "Pulse IRQ TX"
+milkymist_uart_raise_irq(void) "Raise IRQ"
+milkymist_uart_lower_irq(void) "Lower IRQ"
 
 # hw/milkymist-vgafb.c
 milkymist_vgafb_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
commit 27f930c5f0c26fbb845d8071e3bca5f127891ecd
Author: Michael Walle <michael at walle.cc>
Date:   Fri Sep 16 00:26:05 2011 +0200

    lm32: add missing qemu_init_vcpu() call
    
    Signed-off-by: Michael Walle <michael at walle.cc>

diff --git a/target-lm32/helper.c b/target-lm32/helper.c
index 014fd8d..fc0b444 100644
--- a/target-lm32/helper.c
+++ b/target-lm32/helper.c
@@ -218,6 +218,7 @@ CPUState *cpu_lm32_init(const char *cpu_model)
 
     cpu_exec_init(env);
     cpu_reset(env);
+    qemu_init_vcpu(env);
 
     if (!tcg_initialized) {
         tcg_initialized = 1;
commit 59370aaa5693d57c350074e537f2627d5b9d446c
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Fri Sep 30 17:34:58 2011 +0100

    trace: add arguments to bdrv_co_io_em() trace event
    
    It is useful to know the BlockDriverState as well as the
    sector_num/nb_sectors of an emulated .bdrv_co_*() request.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/block.c b/block.c
index 1ae22d5..e865fab 100644
--- a/block.c
+++ b/block.c
@@ -2999,7 +2999,7 @@ static int coroutine_fn bdrv_co_io_em(BlockDriverState *bs, int64_t sector_num,
                              bdrv_co_io_em_complete, &co);
     }
 
-    trace_bdrv_co_io(is_write, acb);
+    trace_bdrv_co_io_em(bs, sector_num, nb_sectors, is_write, acb);
     if (!acb) {
         return -EIO;
     }
diff --git a/trace-events b/trace-events
index c9fd8e5..9528c04 100644
--- a/trace-events
+++ b/trace-events
@@ -67,7 +67,7 @@ bdrv_aio_writev(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs
 bdrv_lock_medium(void *bs, bool locked) "bs %p locked %d"
 bdrv_co_readv(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
 bdrv_co_writev(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
-bdrv_co_io(int is_write, void *acb) "is_write %d acb %p"
+bdrv_co_io_em(void *bs, int64_t sector_num, int nb_sectors, int is_write, void *acb) "bs %p sector_num %"PRId64" nb_sectors %d is_write %d acb %p"
 
 # hw/virtio-blk.c
 virtio_blk_req_complete(void *req, int status) "req %p status %d"
commit 89bd820acb477b2c41f13977a3ceb4538fadcd02
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Fri Sep 23 08:23:06 2011 +0100

    trace: trace monitor qmp dispatch/completion
    
    Add trace events for handle_qmp_command(), which dispatches qmp
    commands, and monitor_protocol_emitter(), which produces the reply to a
    qmp command.
    
    Also remove duplicate #include "trace/control.h".
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/monitor.c b/monitor.c
index 08f6197..cf59442 100644
--- a/monitor.c
+++ b/monitor.c
@@ -57,11 +57,11 @@
 #include "json-parser.h"
 #include "osdep.h"
 #include "cpu.h"
+#include "trace.h"
 #include "trace/control.h"
 #ifdef CONFIG_TRACE_SIMPLE
 #include "trace/simple.h"
 #endif
-#include "trace/control.h"
 #include "ui/qemu-spice.h"
 #include "memory.h"
 
@@ -370,6 +370,8 @@ static void monitor_protocol_emitter(Monitor *mon, QObject *data)
 {
     QDict *qmp;
 
+    trace_monitor_protocol_emitter(mon);
+
     qmp = qdict_new();
 
     if (!monitor_has_error(mon)) {
@@ -5102,6 +5104,7 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
     qobject_incref(mon->mc->id);
 
     cmd_name = qdict_get_str(input, "execute");
+    trace_handle_qmp_command(mon, cmd_name);
     if (invalid_qmp_mode(mon, cmd_name)) {
         qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name);
         goto err_out;
diff --git a/trace-events b/trace-events
index f408564..c9fd8e5 100644
--- a/trace-events
+++ b/trace-events
@@ -534,3 +534,7 @@ esp_mem_writeb_cmd_sel(uint32_t val) "Select without ATN (%2.2x)"
 esp_mem_writeb_cmd_selatn(uint32_t val) "Select with ATN (%2.2x)"
 esp_mem_writeb_cmd_selatns(uint32_t val) "Select with ATN & stop (%2.2x)"
 esp_mem_writeb_cmd_ensel(uint32_t val) "Enable selection (%2.2x)"
+
+# monitor.c
+handle_qmp_command(void *mon, const char *cmd_name) "mon %p cmd_name \"%s\""
+monitor_protocol_emitter(void *mon) "mon %p"
commit 28dcee10c54984449259a13c6f27bf98c4770f3c
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Thu Sep 22 20:14:12 2011 +0100

    trace: trace bdrv_open_common()
    
    bdrv_open_common() is a useful point to trace since it reveals the
    filename and block driver for a given BlockDriverState.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/block.c b/block.c
index e3fe97f..1ae22d5 100644
--- a/block.c
+++ b/block.c
@@ -475,6 +475,8 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename,
 
     assert(drv != NULL);
 
+    trace_bdrv_open_common(bs, filename, flags, drv->format_name);
+
     bs->file = NULL;
     bs->total_sectors = 0;
     bs->encrypted = 0;
diff --git a/trace-events b/trace-events
index b7ddf14..f408564 100644
--- a/trace-events
+++ b/trace-events
@@ -56,6 +56,7 @@ virtio_console_chr_read(unsigned int port, int size) "port %u, size %d"
 virtio_console_chr_event(unsigned int port, int event) "port %u, event %d"
 
 # block.c
+bdrv_open_common(void *bs, const char *filename, int flags, const char *format_name) "bs %p filename \"%s\" flags %#x format_name \"%s\""
 multiwrite_cb(void *mcb, int ret) "mcb %p ret %d"
 bdrv_aio_multiwrite(void *mcb, int num_callbacks, int num_reqs) "mcb %p num_callbacks %d num_reqs %d"
 bdrv_aio_multiwrite_earlyfail(void *mcb) "mcb %p"
commit c45a81682d6d15b7ec82ed90c34a537de66dea55
Author: Michael Roth <mdroth at linux.vnet.ibm.com>
Date:   Sun Oct 2 08:44:37 2011 -0500

    hmp: re-enable trace-file command
    
    Commit 31965ae27bc11e90674be12584bb201b83df5aef reverted a previous
    renaming of CONFIG_SIMPLE_TRACE->CONFIG_TRACE_SIMPLE in a couple spots,
    leading to trace-file currently being unavailable.
    
    Signed-off-by: Michael Roth <mdroth at linux.vnet.ibm.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 9e1cca8..844e6c9 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -194,7 +194,7 @@ STEXI
 changes status of a trace event
 ETEXI
 
-#if defined(CONFIG_SIMPLE_TRACE)
+#if defined(CONFIG_TRACE_SIMPLE)
     {
         .name       = "trace-file",
         .args_type  = "op:s?,arg:F?",
diff --git a/monitor.c b/monitor.c
index d323ea5..08f6197 100644
--- a/monitor.c
+++ b/monitor.c
@@ -606,7 +606,7 @@ static void do_trace_event_set_state(Monitor *mon, const QDict *qdict)
     }
 }
 
-#ifdef CONFIG_SIMPLE_TRACE
+#ifdef CONFIG_TRACE_SIMPLE
 static void do_trace_file(Monitor *mon, const QDict *qdict)
 {
     const char *op = qdict_get_try_str(qdict, "op");
commit d11cf8cc80d946dfc9a23597cd9a0bb1c487cfa7
Author: Edgar E. Iglesias <edgar.iglesias at gmail.com>
Date:   Mon Oct 3 10:20:13 2011 +0200

    etrax-dma: Remove bogus if statement
    
    Reported-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Edgar E. Iglesias <edgar.iglesias at gmail.com>

diff --git a/hw/etraxfs_dma.c b/hw/etraxfs_dma.c
index d3082ac..5ca8253 100644
--- a/hw/etraxfs_dma.c
+++ b/hw/etraxfs_dma.c
@@ -599,12 +599,10 @@ dma_winvalid (void *opaque, target_phys_addr_t addr, uint32_t value)
 static void
 dma_update_state(struct fs_dma_ctrl *ctrl, int c)
 {
-	if ((ctrl->channels[c].regs[RW_CFG] & 1) != 3) {
-		if (ctrl->channels[c].regs[RW_CFG] & 2)
-			ctrl->channels[c].state = STOPPED;
-		if (!(ctrl->channels[c].regs[RW_CFG] & 1))
-			ctrl->channels[c].state = RST;
-	}
+	if (ctrl->channels[c].regs[RW_CFG] & 2)
+		ctrl->channels[c].state = STOPPED;
+	if (!(ctrl->channels[c].regs[RW_CFG] & 1))
+		ctrl->channels[c].state = RST;
 }
 
 static void
commit 9479c57a8c1e6c33f171ca7c93fea84567045833
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Tue Sep 27 15:00:41 2011 +0200

    memory: Print regions in ascending order
    
    Makes reading the output more user friendly.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/memory.c b/memory.c
index 19f1d36..f46e626 100644
--- a/memory.c
+++ b/memory.c
@@ -1285,12 +1285,13 @@ typedef QTAILQ_HEAD(queue, MemoryRegionList) MemoryRegionListHead;
 static void mtree_print_mr(fprintf_function mon_printf, void *f,
                            const MemoryRegion *mr, unsigned int level,
                            target_phys_addr_t base,
-                           MemoryRegionListHead *print_queue)
+                           MemoryRegionListHead *alias_print_queue)
 {
+    MemoryRegionList *new_ml, *ml, *next_ml;
+    MemoryRegionListHead submr_print_queue;
     const MemoryRegion *submr;
     unsigned int i;
 
-
     if (!mr) {
         return;
     }
@@ -1304,7 +1305,7 @@ static void mtree_print_mr(fprintf_function mon_printf, void *f,
         bool found = false;
 
         /* check if the alias is already in the queue */
-        QTAILQ_FOREACH(ml, print_queue, queue) {
+        QTAILQ_FOREACH(ml, alias_print_queue, queue) {
             if (ml->mr == mr->alias && !ml->printed) {
                 found = true;
             }
@@ -1314,7 +1315,7 @@ static void mtree_print_mr(fprintf_function mon_printf, void *f,
             ml = g_new(MemoryRegionList, 1);
             ml->mr = mr->alias;
             ml->printed = false;
-            QTAILQ_INSERT_TAIL(print_queue, ml, queue);
+            QTAILQ_INSERT_TAIL(alias_print_queue, ml, queue);
         }
         mon_printf(f, TARGET_FMT_plx "-" TARGET_FMT_plx " (prio %d): alias %s @%s "
                    TARGET_FMT_plx "-" TARGET_FMT_plx "\n",
@@ -1332,9 +1333,33 @@ static void mtree_print_mr(fprintf_function mon_printf, void *f,
                    mr->priority,
                    mr->name);
     }
+
+    QTAILQ_INIT(&submr_print_queue);
+
     QTAILQ_FOREACH(submr, &mr->subregions, subregions_link) {
-        mtree_print_mr(mon_printf, f, submr, level + 1, base + mr->addr,
-                       print_queue);
+        new_ml = g_new(MemoryRegionList, 1);
+        new_ml->mr = submr;
+        QTAILQ_FOREACH(ml, &submr_print_queue, queue) {
+            if (new_ml->mr->addr < ml->mr->addr ||
+                (new_ml->mr->addr == ml->mr->addr &&
+                 new_ml->mr->priority > ml->mr->priority)) {
+                QTAILQ_INSERT_BEFORE(ml, new_ml, queue);
+                new_ml = NULL;
+                break;
+            }
+        }
+        if (new_ml) {
+            QTAILQ_INSERT_TAIL(&submr_print_queue, new_ml, queue);
+        }
+    }
+
+    QTAILQ_FOREACH(ml, &submr_print_queue, queue) {
+        mtree_print_mr(mon_printf, f, ml->mr, level + 1, base + mr->addr,
+                       alias_print_queue);
+    }
+
+    QTAILQ_FOREACH_SAFE(next_ml, &submr_print_queue, queue, ml) {
+        g_free(ml);
     }
 }
 
commit 066318109fa2f377e5097f115a23f85c53f1a674
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Tue Sep 27 15:00:38 2011 +0200

    memory: Do not print empty PIO root
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/memory.c b/memory.c
index eae67be..19f1d36 100644
--- a/memory.c
+++ b/memory.c
@@ -1360,7 +1360,10 @@ void mtree_info(fprintf_function mon_printf, void *f)
         g_free(ml2);
     }
 
-    QTAILQ_INIT(&ml_head);
-    mon_printf(f, "I/O\n");
-    mtree_print_mr(mon_printf, f, address_space_io.root, 0, 0, &ml_head);
+    if (address_space_io.root &&
+        !QTAILQ_EMPTY(&address_space_io.root->subregions)) {
+        QTAILQ_INIT(&ml_head);
+        mon_printf(f, "I/O\n");
+        mtree_print_mr(mon_printf, f, address_space_io.root, 0, 0, &ml_head);
+    }
 }
commit 4b474ba7a1a96aabcf3482eb5b23ad5361a38750
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Tue Sep 27 15:00:31 2011 +0200

    memory: Print region priority
    
    Useful to discover eclipses.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/memory.c b/memory.c
index a85d118..eae67be 100644
--- a/memory.c
+++ b/memory.c
@@ -1316,18 +1316,20 @@ static void mtree_print_mr(fprintf_function mon_printf, void *f,
             ml->printed = false;
             QTAILQ_INSERT_TAIL(print_queue, ml, queue);
         }
-        mon_printf(f, TARGET_FMT_plx "-" TARGET_FMT_plx " : alias %s @%s "
+        mon_printf(f, TARGET_FMT_plx "-" TARGET_FMT_plx " (prio %d): alias %s @%s "
                    TARGET_FMT_plx "-" TARGET_FMT_plx "\n",
                    base + mr->addr,
                    base + mr->addr + (target_phys_addr_t)mr->size - 1,
+                   mr->priority,
                    mr->name,
                    mr->alias->name,
                    mr->alias_offset,
                    mr->alias_offset + (target_phys_addr_t)mr->size - 1);
     } else {
-        mon_printf(f, TARGET_FMT_plx "-" TARGET_FMT_plx " : %s\n",
+        mon_printf(f, TARGET_FMT_plx "-" TARGET_FMT_plx " (prio %d): %s\n",
                    base + mr->addr,
                    base + mr->addr + (target_phys_addr_t)mr->size - 1,
+                   mr->priority,
                    mr->name);
     }
     QTAILQ_FOREACH(submr, &mr->subregions, subregions_link) {
commit 314e298735903035ba2b7b0f3cf39981f4171546
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Sep 11 20:22:05 2011 +0000

    memory: simple memory tree printer
    
    Add a monitor command 'info mtree' to show the memory hierarchy
    much like /proc/iomem in Linux.
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/memory.c b/memory.c
index 71e769e..a85d118 100644
--- a/memory.c
+++ b/memory.c
@@ -1271,3 +1271,94 @@ void set_system_io_map(MemoryRegion *mr)
     address_space_io.root = mr;
     memory_region_update_topology();
 }
+
+typedef struct MemoryRegionList MemoryRegionList;
+
+struct MemoryRegionList {
+    const MemoryRegion *mr;
+    bool printed;
+    QTAILQ_ENTRY(MemoryRegionList) queue;
+};
+
+typedef QTAILQ_HEAD(queue, MemoryRegionList) MemoryRegionListHead;
+
+static void mtree_print_mr(fprintf_function mon_printf, void *f,
+                           const MemoryRegion *mr, unsigned int level,
+                           target_phys_addr_t base,
+                           MemoryRegionListHead *print_queue)
+{
+    const MemoryRegion *submr;
+    unsigned int i;
+
+
+    if (!mr) {
+        return;
+    }
+
+    for (i = 0; i < level; i++) {
+        mon_printf(f, "  ");
+    }
+
+    if (mr->alias) {
+        MemoryRegionList *ml;
+        bool found = false;
+
+        /* check if the alias is already in the queue */
+        QTAILQ_FOREACH(ml, print_queue, queue) {
+            if (ml->mr == mr->alias && !ml->printed) {
+                found = true;
+            }
+        }
+
+        if (!found) {
+            ml = g_new(MemoryRegionList, 1);
+            ml->mr = mr->alias;
+            ml->printed = false;
+            QTAILQ_INSERT_TAIL(print_queue, ml, queue);
+        }
+        mon_printf(f, TARGET_FMT_plx "-" TARGET_FMT_plx " : alias %s @%s "
+                   TARGET_FMT_plx "-" TARGET_FMT_plx "\n",
+                   base + mr->addr,
+                   base + mr->addr + (target_phys_addr_t)mr->size - 1,
+                   mr->name,
+                   mr->alias->name,
+                   mr->alias_offset,
+                   mr->alias_offset + (target_phys_addr_t)mr->size - 1);
+    } else {
+        mon_printf(f, TARGET_FMT_plx "-" TARGET_FMT_plx " : %s\n",
+                   base + mr->addr,
+                   base + mr->addr + (target_phys_addr_t)mr->size - 1,
+                   mr->name);
+    }
+    QTAILQ_FOREACH(submr, &mr->subregions, subregions_link) {
+        mtree_print_mr(mon_printf, f, submr, level + 1, base + mr->addr,
+                       print_queue);
+    }
+}
+
+void mtree_info(fprintf_function mon_printf, void *f)
+{
+    MemoryRegionListHead ml_head;
+    MemoryRegionList *ml, *ml2;
+
+    QTAILQ_INIT(&ml_head);
+
+    mon_printf(f, "memory\n");
+    mtree_print_mr(mon_printf, f, address_space_memory.root, 0, 0, &ml_head);
+
+    /* print aliased regions */
+    QTAILQ_FOREACH(ml, &ml_head, queue) {
+        if (!ml->printed) {
+            mon_printf(f, "%s\n", ml->mr->name);
+            mtree_print_mr(mon_printf, f, ml->mr, 0, 0, &ml_head);
+        }
+    }
+
+    QTAILQ_FOREACH_SAFE(ml, &ml_head, queue, ml2) {
+        g_free(ml2);
+    }
+
+    QTAILQ_INIT(&ml_head);
+    mon_printf(f, "I/O\n");
+    mtree_print_mr(mon_printf, f, address_space_io.root, 0, 0, &ml_head);
+}
diff --git a/memory.h b/memory.h
index e93e65a..d5b47da 100644
--- a/memory.h
+++ b/memory.h
@@ -501,6 +501,8 @@ void memory_region_transaction_begin(void);
  */
 void memory_region_transaction_commit(void);
 
+void mtree_info(fprintf_function mon_printf, void *f);
+
 #endif
 
 #endif
diff --git a/monitor.c b/monitor.c
index 8ec2c5e..d323ea5 100644
--- a/monitor.c
+++ b/monitor.c
@@ -63,6 +63,7 @@
 #endif
 #include "trace/control.h"
 #include "ui/qemu-spice.h"
+#include "memory.h"
 
 //#define DEBUG
 //#define DEBUG_COMPLETION
@@ -2470,6 +2471,11 @@ static void tlb_info(Monitor *mon)
 }
 #endif
 
+static void do_info_mtree(Monitor *mon)
+{
+    mtree_info((fprintf_function)monitor_printf, mon);
+}
+
 static void do_info_kvm_print(Monitor *mon, const QObject *data)
 {
     QDict *qdict;
@@ -2978,6 +2984,13 @@ static const mon_cmd_t info_cmds[] = {
     },
 #endif
     {
+        .name       = "mtree",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show memory tree",
+        .mhandler.info = do_info_mtree,
+    },
+    {
         .name       = "jit",
         .args_type  = "",
         .params     = "",
commit 306f66b42f961e38442d1721523dbb4906b33afb
Author: Michael Walle <michael at walle.cc>
Date:   Wed Aug 31 16:48:47 2011 +0200

    milkymist-{minimac2,softusb}: rename memory names
    
    Be consistent with other milkymist models.
    
    Signed-off-by: Michael Walle <michael at walle.cc>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/milkymist-minimac2.c b/hw/milkymist-minimac2.c
index fb48e37..85d9400 100644
--- a/hw/milkymist-minimac2.c
+++ b/hw/milkymist-minimac2.c
@@ -464,11 +464,11 @@ static int milkymist_minimac2_init(SysBusDevice *dev)
     sysbus_init_irq(dev, &s->tx_irq);
 
     memory_region_init_io(&s->regs_region, &minimac2_ops, s,
-                          "minimac2-mmio", R_MAX * 4);
+                          "milkymist-minimac2", R_MAX * 4);
     sysbus_init_mmio_region(dev, &s->regs_region);
 
     /* register buffers memory */
-    memory_region_init_ram(&s->buffers, NULL, "milkymist_minimac2.buffers",
+    memory_region_init_ram(&s->buffers, NULL, "milkymist-minimac2.buffers",
                            buffers_size);
     s->rx0_buf = memory_region_get_ram_ptr(&s->buffers);
     s->rx1_buf = s->rx0_buf + MINIMAC2_BUFFER_SIZE;
diff --git a/hw/milkymist-softusb.c b/hw/milkymist-softusb.c
index ef4d9ee..ec5f334 100644
--- a/hw/milkymist-softusb.c
+++ b/hw/milkymist-softusb.c
@@ -267,10 +267,10 @@ static int milkymist_softusb_init(SysBusDevice *dev)
     sysbus_init_mmio_region(dev, &s->regs_region);
 
     /* register pmem and dmem */
-    memory_region_init_ram(&s->pmem, NULL, "milkymist_softusb.pmem",
+    memory_region_init_ram(&s->pmem, NULL, "milkymist-softusb.pmem",
                            s->pmem_size);
     sysbus_add_memory(dev, s->pmem_base, &s->pmem);
-    memory_region_init_ram(&s->dmem, NULL, "milkymist_softusb.dmem",
+    memory_region_init_ram(&s->dmem, NULL, "milkymist-softusb.dmem",
                            s->dmem_size);
     sysbus_add_memory(dev, s->dmem_base, &s->dmem);
 
commit 883abf8d2c8728b62e6345aee882d79c829de34c
Author: Michael Walle <michael at walle.cc>
Date:   Wed Aug 31 16:48:46 2011 +0200

    milkymist-vgafb: convert to memory API
    
    Signed-off-by: Michael Walle <michael at walle.cc>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/milkymist-vgafb.c b/hw/milkymist-vgafb.c
index 2e55e42..be81abd 100644
--- a/hw/milkymist-vgafb.c
+++ b/hw/milkymist-vgafb.c
@@ -64,6 +64,7 @@ enum {
 
 struct MilkymistVgafbState {
     SysBusDevice busdev;
+    MemoryRegion regs_region;
     DisplayState *ds;
 
     int invalidate;
@@ -153,7 +154,8 @@ static void vgafb_resize(MilkymistVgafbState *s)
     s->invalidate = 1;
 }
 
-static uint32_t vgafb_read(void *opaque, target_phys_addr_t addr)
+static uint64_t vgafb_read(void *opaque, target_phys_addr_t addr,
+                           unsigned size)
 {
     MilkymistVgafbState *s = opaque;
     uint32_t r = 0;
@@ -189,8 +191,8 @@ static uint32_t vgafb_read(void *opaque, target_phys_addr_t addr)
     return r;
 }
 
-static void
-vgafb_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+static void vgafb_write(void *opaque, target_phys_addr_t addr, uint64_t value,
+                        unsigned size)
 {
     MilkymistVgafbState *s = opaque;
 
@@ -238,16 +240,14 @@ vgafb_write(void *opaque, target_phys_addr_t addr, uint32_t value)
     }
 }
 
-static CPUReadMemoryFunc * const vgafb_read_fn[] = {
-   NULL,
-   NULL,
-   &vgafb_read
-};
-
-static CPUWriteMemoryFunc * const vgafb_write_fn[] = {
-   NULL,
-   NULL,
-   &vgafb_write
+static const MemoryRegionOps vgafb_mmio_ops = {
+    .read = vgafb_read,
+    .write = vgafb_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void milkymist_vgafb_reset(DeviceState *d)
@@ -269,11 +269,10 @@ static void milkymist_vgafb_reset(DeviceState *d)
 static int milkymist_vgafb_init(SysBusDevice *dev)
 {
     MilkymistVgafbState *s = FROM_SYSBUS(typeof(*s), dev);
-    int vgafb_regs;
 
-    vgafb_regs = cpu_register_io_memory(vgafb_read_fn, vgafb_write_fn, s,
-            DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, R_MAX * 4, vgafb_regs);
+    memory_region_init_io(&s->regs_region, &vgafb_mmio_ops, s,
+            "milkymist-vgafb", R_MAX * 4);
+    sysbus_init_mmio_region(dev, &s->regs_region);
 
     s->ds = graphic_console_init(vgafb_update_display,
                                  vgafb_invalidate_display,
commit 5adb30d38babd733923004c57c57fef84533a039
Author: Michael Walle <michael at walle.cc>
Date:   Wed Aug 31 16:48:45 2011 +0200

    milkymist-uart: convert to memory API
    
    Signed-off-by: Michael Walle <michael at walle.cc>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/milkymist-uart.c b/hw/milkymist-uart.c
index e8e309d..128cd8c 100644
--- a/hw/milkymist-uart.c
+++ b/hw/milkymist-uart.c
@@ -35,7 +35,9 @@ enum {
 
 struct MilkymistUartState {
     SysBusDevice busdev;
+    MemoryRegion regs_region;
     CharDriverState *chr;
+
     qemu_irq rx_irq;
     qemu_irq tx_irq;
 
@@ -43,7 +45,8 @@ struct MilkymistUartState {
 };
 typedef struct MilkymistUartState MilkymistUartState;
 
-static uint32_t uart_read(void *opaque, target_phys_addr_t addr)
+static uint64_t uart_read(void *opaque, target_phys_addr_t addr,
+                          unsigned size)
 {
     MilkymistUartState *s = opaque;
     uint32_t r = 0;
@@ -66,7 +69,8 @@ static uint32_t uart_read(void *opaque, target_phys_addr_t addr)
     return r;
 }
 
-static void uart_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+static void uart_write(void *opaque, target_phys_addr_t addr, uint64_t value,
+                       unsigned size)
 {
     MilkymistUartState *s = opaque;
     unsigned char ch = value;
@@ -93,16 +97,14 @@ static void uart_write(void *opaque, target_phys_addr_t addr, uint32_t value)
     }
 }
 
-static CPUReadMemoryFunc * const uart_read_fn[] = {
-    NULL,
-    NULL,
-    &uart_read,
-};
-
-static CPUWriteMemoryFunc * const uart_write_fn[] = {
-    NULL,
-    NULL,
-    &uart_write,
+static const MemoryRegionOps uart_mmio_ops = {
+    .read = uart_read,
+    .write = uart_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void uart_rx(void *opaque, const uint8_t *buf, int size)
@@ -136,14 +138,13 @@ static void milkymist_uart_reset(DeviceState *d)
 static int milkymist_uart_init(SysBusDevice *dev)
 {
     MilkymistUartState *s = FROM_SYSBUS(typeof(*s), dev);
-    int uart_regs;
 
     sysbus_init_irq(dev, &s->rx_irq);
     sysbus_init_irq(dev, &s->tx_irq);
 
-    uart_regs = cpu_register_io_memory(uart_read_fn, uart_write_fn, s,
-            DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, R_MAX * 4, uart_regs);
+    memory_region_init_io(&s->regs_region, &uart_mmio_ops, s,
+            "milkymist-uart", R_MAX * 4);
+    sysbus_init_mmio_region(dev, &s->regs_region);
 
     s->chr = qdev_init_chardev(&dev->qdev);
     if (s->chr) {
commit 7100453f2ecb2b1593e9559258fda4a11493d2b5
Author: Michael Walle <michael at walle.cc>
Date:   Wed Aug 31 16:48:44 2011 +0200

    milkymist-tmu2: convert to memory API
    
    Signed-off-by: Michael Walle <michael at walle.cc>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/milkymist-tmu2.c b/hw/milkymist-tmu2.c
index 953d42f..aad0ed0 100644
--- a/hw/milkymist-tmu2.c
+++ b/hw/milkymist-tmu2.c
@@ -77,6 +77,7 @@ struct vertex {
 
 struct MilkymistTMU2State {
     SysBusDevice busdev;
+    MemoryRegion regs_region;
     CharDriverState *chr;
     qemu_irq irq;
 
@@ -309,7 +310,8 @@ static void tmu2_start(MilkymistTMU2State *s)
     qemu_irq_pulse(s->irq);
 }
 
-static uint32_t tmu2_read(void *opaque, target_phys_addr_t addr)
+static uint64_t tmu2_read(void *opaque, target_phys_addr_t addr,
+                          unsigned size)
 {
     MilkymistTMU2State *s = opaque;
     uint32_t r = 0;
@@ -370,7 +372,8 @@ static void tmu2_check_registers(MilkymistTMU2State *s)
     }
 }
 
-static void tmu2_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+static void tmu2_write(void *opaque, target_phys_addr_t addr, uint64_t value,
+                       unsigned size)
 {
     MilkymistTMU2State *s = opaque;
 
@@ -414,16 +417,14 @@ static void tmu2_write(void *opaque, target_phys_addr_t addr, uint32_t value)
     tmu2_check_registers(s);
 }
 
-static CPUReadMemoryFunc * const tmu2_read_fn[] = {
-    NULL,
-    NULL,
-    &tmu2_read,
-};
-
-static CPUWriteMemoryFunc * const tmu2_write_fn[] = {
-    NULL,
-    NULL,
-    &tmu2_write,
+static const MemoryRegionOps tmu2_mmio_ops = {
+    .read = tmu2_read,
+    .write = tmu2_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void milkymist_tmu2_reset(DeviceState *d)
@@ -439,7 +440,6 @@ static void milkymist_tmu2_reset(DeviceState *d)
 static int milkymist_tmu2_init(SysBusDevice *dev)
 {
     MilkymistTMU2State *s = FROM_SYSBUS(typeof(*s), dev);
-    int tmu2_regs;
 
     if (tmu2_glx_init(s)) {
         return 1;
@@ -447,9 +447,9 @@ static int milkymist_tmu2_init(SysBusDevice *dev)
 
     sysbus_init_irq(dev, &s->irq);
 
-    tmu2_regs = cpu_register_io_memory(tmu2_read_fn, tmu2_write_fn, s,
-            DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, R_MAX * 4, tmu2_regs);
+    memory_region_init_io(&s->regs_region, &tmu2_mmio_ops, s,
+            "milkymist-tmu2", R_MAX * 4);
+    sysbus_init_mmio_region(dev, &s->regs_region);
 
     return 0;
 }
commit dfa87ccfad0d868a9c28f198df3146067f84490a
Author: Michael Walle <michael at walle.cc>
Date:   Wed Aug 31 16:48:43 2011 +0200

    milkymist-sysctl: convert to memory API
    
    Signed-off-by: Michael Walle <michael at walle.cc>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/milkymist-sysctl.c b/hw/milkymist-sysctl.c
index 7b2d544..5783f08 100644
--- a/hw/milkymist-sysctl.c
+++ b/hw/milkymist-sysctl.c
@@ -59,6 +59,7 @@ enum {
 
 struct MilkymistSysctlState {
     SysBusDevice busdev;
+    MemoryRegion regs_region;
 
     QEMUBH *bh0;
     QEMUBH *bh1;
@@ -88,7 +89,8 @@ static void sysctl_icap_write(MilkymistSysctlState *s, uint32_t value)
     }
 }
 
-static uint32_t sysctl_read(void *opaque, target_phys_addr_t addr)
+static uint64_t sysctl_read(void *opaque, target_phys_addr_t addr,
+                            unsigned size)
 {
     MilkymistSysctlState *s = opaque;
     uint32_t r = 0;
@@ -129,7 +131,8 @@ static uint32_t sysctl_read(void *opaque, target_phys_addr_t addr)
     return r;
 }
 
-static void sysctl_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+static void sysctl_write(void *opaque, target_phys_addr_t addr, uint64_t value,
+                         unsigned size)
 {
     MilkymistSysctlState *s = opaque;
 
@@ -195,16 +198,14 @@ static void sysctl_write(void *opaque, target_phys_addr_t addr, uint32_t value)
     }
 }
 
-static CPUReadMemoryFunc * const sysctl_read_fn[] = {
-    NULL,
-    NULL,
-    &sysctl_read,
-};
-
-static CPUWriteMemoryFunc * const sysctl_write_fn[] = {
-    NULL,
-    NULL,
-    &sysctl_write,
+static const MemoryRegionOps sysctl_mmio_ops = {
+    .read = sysctl_read,
+    .write = sysctl_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void timer0_hit(void *opaque)
@@ -258,7 +259,6 @@ static void milkymist_sysctl_reset(DeviceState *d)
 static int milkymist_sysctl_init(SysBusDevice *dev)
 {
     MilkymistSysctlState *s = FROM_SYSBUS(typeof(*s), dev);
-    int sysctl_regs;
 
     sysbus_init_irq(dev, &s->gpio_irq);
     sysbus_init_irq(dev, &s->timer0_irq);
@@ -271,9 +271,9 @@ static int milkymist_sysctl_init(SysBusDevice *dev)
     ptimer_set_freq(s->ptimer0, s->freq_hz);
     ptimer_set_freq(s->ptimer1, s->freq_hz);
 
-    sysctl_regs = cpu_register_io_memory(sysctl_read_fn, sysctl_write_fn, s,
-            DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, R_MAX * 4, sysctl_regs);
+    memory_region_init_io(&s->regs_region, &sysctl_mmio_ops, s,
+            "milkymist-sysctl", R_MAX * 4);
+    sysbus_init_mmio_region(dev, &s->regs_region);
 
     return 0;
 }
commit d46ccfcef3f97bf40d270861fbed76a3d2fdefa4
Author: Michael Walle <michael at walle.cc>
Date:   Wed Aug 31 16:48:42 2011 +0200

    milkymist-pfpu: convert to memory API
    
    Signed-off-by: Michael Walle <michael at walle.cc>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/milkymist-pfpu.c b/hw/milkymist-pfpu.c
index 306d1ce..672f6e4 100644
--- a/hw/milkymist-pfpu.c
+++ b/hw/milkymist-pfpu.c
@@ -118,6 +118,7 @@ static const char *opcode_to_str[] = {
 
 struct MilkymistPFPUState {
     SysBusDevice busdev;
+    MemoryRegion regs_region;
     CharDriverState *chr;
     qemu_irq irq;
 
@@ -379,7 +380,8 @@ static inline int get_microcode_address(MilkymistPFPUState *s, uint32_t addr)
     return (512 * s->regs[R_CODEPAGE]) + addr - MICROCODE_BEGIN;
 }
 
-static uint32_t pfpu_read(void *opaque, target_phys_addr_t addr)
+static uint64_t pfpu_read(void *opaque, target_phys_addr_t addr,
+                          unsigned size)
 {
     MilkymistPFPUState *s = opaque;
     uint32_t r = 0;
@@ -418,8 +420,8 @@ static uint32_t pfpu_read(void *opaque, target_phys_addr_t addr)
     return r;
 }
 
-static void
-pfpu_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+static void pfpu_write(void *opaque, target_phys_addr_t addr, uint64_t value,
+                       unsigned size)
 {
     MilkymistPFPUState *s = opaque;
 
@@ -459,16 +461,14 @@ pfpu_write(void *opaque, target_phys_addr_t addr, uint32_t value)
     }
 }
 
-static CPUReadMemoryFunc * const pfpu_read_fn[] = {
-    NULL,
-    NULL,
-    &pfpu_read,
-};
-
-static CPUWriteMemoryFunc * const pfpu_write_fn[] = {
-    NULL,
-    NULL,
-    &pfpu_write,
+static const MemoryRegionOps pfpu_mmio_ops = {
+    .read = pfpu_read,
+    .write = pfpu_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void milkymist_pfpu_reset(DeviceState *d)
@@ -494,13 +494,12 @@ static void milkymist_pfpu_reset(DeviceState *d)
 static int milkymist_pfpu_init(SysBusDevice *dev)
 {
     MilkymistPFPUState *s = FROM_SYSBUS(typeof(*s), dev);
-    int pfpu_regs;
 
     sysbus_init_irq(dev, &s->irq);
 
-    pfpu_regs = cpu_register_io_memory(pfpu_read_fn, pfpu_write_fn, s,
-            DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, MICROCODE_END * 4, pfpu_regs);
+    memory_region_init_io(&s->regs_region, &pfpu_mmio_ops, s,
+            "milkymist-pfpu", MICROCODE_END * 4);
+    sysbus_init_mmio_region(dev, &s->regs_region);
 
     return 0;
 }
commit 8c85d15b3f5feee80b81499290afba564cf9eb9d
Author: Michael Walle <michael at walle.cc>
Date:   Wed Aug 31 16:48:41 2011 +0200

    milkymist-memcard: convert to memory API
    
    Signed-off-by: Michael Walle <michael at walle.cc>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/milkymist-memcard.c b/hw/milkymist-memcard.c
index 22dc377..fb6e558 100644
--- a/hw/milkymist-memcard.c
+++ b/hw/milkymist-memcard.c
@@ -60,6 +60,7 @@ enum {
 
 struct MilkymistMemcardState {
     SysBusDevice busdev;
+    MemoryRegion regs_region;
     SDState *card;
 
     int command_write_ptr;
@@ -116,7 +117,8 @@ static void memcard_sd_command(MilkymistMemcardState *s)
     }
 }
 
-static uint32_t memcard_read(void *opaque, target_phys_addr_t addr)
+static uint64_t memcard_read(void *opaque, target_phys_addr_t addr,
+                             unsigned size)
 {
     MilkymistMemcardState *s = opaque;
     uint32_t r = 0;
@@ -164,7 +166,8 @@ static uint32_t memcard_read(void *opaque, target_phys_addr_t addr)
     return r;
 }
 
-static void memcard_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+static void memcard_write(void *opaque, target_phys_addr_t addr, uint64_t value,
+                          unsigned size)
 {
     MilkymistMemcardState *s = opaque;
 
@@ -216,16 +219,14 @@ static void memcard_write(void *opaque, target_phys_addr_t addr, uint32_t value)
     }
 }
 
-static CPUReadMemoryFunc * const memcard_read_fn[] = {
-    NULL,
-    NULL,
-    &memcard_read,
-};
-
-static CPUWriteMemoryFunc * const memcard_write_fn[] = {
-    NULL,
-    NULL,
-    &memcard_write,
+static const MemoryRegionOps memcard_mmio_ops = {
+    .read = memcard_read,
+    .write = memcard_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void milkymist_memcard_reset(DeviceState *d)
@@ -247,15 +248,14 @@ static int milkymist_memcard_init(SysBusDevice *dev)
 {
     MilkymistMemcardState *s = FROM_SYSBUS(typeof(*s), dev);
     DriveInfo *dinfo;
-    int memcard_regs;
 
     dinfo = drive_get_next(IF_SD);
     s->card = sd_init(dinfo ? dinfo->bdrv : NULL, 0);
     s->enabled = dinfo ? bdrv_is_inserted(dinfo->bdrv) : 0;
 
-    memcard_regs = cpu_register_io_memory(memcard_read_fn, memcard_write_fn, s,
-            DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, R_MAX * 4, memcard_regs);
+    memory_region_init_io(&s->regs_region, &memcard_mmio_ops, s,
+            "milkymist-memcard", R_MAX * 4);
+    sysbus_init_mmio_region(dev, &s->regs_region);
 
     return 0;
 }
commit 321c17ae97de0e69d1dc2d7609734adca0aa5c05
Author: Michael Walle <michael at walle.cc>
Date:   Wed Aug 31 16:48:40 2011 +0200

    milkymist-hpdmc: convert to memory API
    
    Signed-off-by: Michael Walle <michael at walle.cc>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/milkymist-hpdmc.c b/hw/milkymist-hpdmc.c
index c0962fb..17c840f 100644
--- a/hw/milkymist-hpdmc.c
+++ b/hw/milkymist-hpdmc.c
@@ -42,12 +42,14 @@ enum {
 
 struct MilkymistHpdmcState {
     SysBusDevice busdev;
+    MemoryRegion regs_region;
 
     uint32_t regs[R_MAX];
 };
 typedef struct MilkymistHpdmcState MilkymistHpdmcState;
 
-static uint32_t hpdmc_read(void *opaque, target_phys_addr_t addr)
+static uint64_t hpdmc_read(void *opaque, target_phys_addr_t addr,
+                           unsigned size)
 {
     MilkymistHpdmcState *s = opaque;
     uint32_t r = 0;
@@ -72,7 +74,8 @@ static uint32_t hpdmc_read(void *opaque, target_phys_addr_t addr)
     return r;
 }
 
-static void hpdmc_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+static void hpdmc_write(void *opaque, target_phys_addr_t addr, uint64_t value,
+                        unsigned size)
 {
     MilkymistHpdmcState *s = opaque;
 
@@ -96,16 +99,14 @@ static void hpdmc_write(void *opaque, target_phys_addr_t addr, uint32_t value)
     }
 }
 
-static CPUReadMemoryFunc * const hpdmc_read_fn[] = {
-    NULL,
-    NULL,
-    &hpdmc_read,
-};
-
-static CPUWriteMemoryFunc * const hpdmc_write_fn[] = {
-    NULL,
-    NULL,
-    &hpdmc_write,
+static const MemoryRegionOps hpdmc_mmio_ops = {
+    .read = hpdmc_read,
+    .write = hpdmc_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void milkymist_hpdmc_reset(DeviceState *d)
@@ -125,11 +126,10 @@ static void milkymist_hpdmc_reset(DeviceState *d)
 static int milkymist_hpdmc_init(SysBusDevice *dev)
 {
     MilkymistHpdmcState *s = FROM_SYSBUS(typeof(*s), dev);
-    int hpdmc_regs;
 
-    hpdmc_regs = cpu_register_io_memory(hpdmc_read_fn, hpdmc_write_fn, s,
-            DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, R_MAX * 4, hpdmc_regs);
+    memory_region_init_io(&s->regs_region, &hpdmc_mmio_ops, s,
+            "milkymist-hpdmc", R_MAX * 4);
+    sysbus_init_mmio_region(dev, &s->regs_region);
 
     return 0;
 }
commit 9496e1c335993eca3901d94f19c86fd501715a49
Author: Michael Walle <michael at walle.cc>
Date:   Wed Aug 31 16:48:39 2011 +0200

    milkymist-ac97: convert to memory API
    
    Signed-off-by: Michael Walle <michael at walle.cc>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/milkymist-ac97.c b/hw/milkymist-ac97.c
index 6104732..5c5ed27 100644
--- a/hw/milkymist-ac97.c
+++ b/hw/milkymist-ac97.c
@@ -53,6 +53,7 @@ enum {
 
 struct MilkymistAC97State {
     SysBusDevice busdev;
+    MemoryRegion regs_region;
 
     QEMUSoundCard card;
     SWVoiceIn *voice_in;
@@ -82,7 +83,8 @@ static void update_voices(MilkymistAC97State *s)
     }
 }
 
-static uint32_t ac97_read(void *opaque, target_phys_addr_t addr)
+static uint64_t ac97_read(void *opaque, target_phys_addr_t addr,
+                          unsigned size)
 {
     MilkymistAC97State *s = opaque;
     uint32_t r = 0;
@@ -113,7 +115,8 @@ static uint32_t ac97_read(void *opaque, target_phys_addr_t addr)
     return r;
 }
 
-static void ac97_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+static void ac97_write(void *opaque, target_phys_addr_t addr, uint64_t value,
+                       unsigned size)
 {
     MilkymistAC97State *s = opaque;
 
@@ -159,16 +162,14 @@ static void ac97_write(void *opaque, target_phys_addr_t addr, uint32_t value)
 
 }
 
-static CPUReadMemoryFunc * const ac97_read_fn[] = {
-    NULL,
-    NULL,
-    &ac97_read,
-};
-
-static CPUWriteMemoryFunc * const ac97_write_fn[] = {
-    NULL,
-    NULL,
-    &ac97_write,
+static const MemoryRegionOps ac97_mmio_ops = {
+    .read = ac97_read,
+    .write = ac97_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void ac97_in_cb(void *opaque, int avail_b)
@@ -280,7 +281,6 @@ static int ac97_post_load(void *opaque, int version_id)
 static int milkymist_ac97_init(SysBusDevice *dev)
 {
     MilkymistAC97State *s = FROM_SYSBUS(typeof(*s), dev);
-    int ac97_regs;
 
     struct audsettings as;
     sysbus_init_irq(dev, &s->crrequest_irq);
@@ -300,9 +300,9 @@ static int milkymist_ac97_init(SysBusDevice *dev)
     s->voice_out = AUD_open_out(&s->card, s->voice_out,
             "mm_ac97.out", s, ac97_out_cb, &as);
 
-    ac97_regs = cpu_register_io_memory(ac97_read_fn, ac97_write_fn, s,
-            DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, R_MAX * 4, ac97_regs);
+    memory_region_init_io(&s->regs_region, &ac97_mmio_ops, s,
+            "milkymist-ac97", R_MAX * 4);
+    sysbus_init_mmio_region(dev, &s->regs_region);
 
     return 0;
 }
commit 71cf9e62427230ebc0ddd68a206b261952dffc57
Author: Fabien Chouteau <chouteau at adacore.com>
Date:   Tue Aug 30 17:46:26 2011 +0200

    openpic: Memory API conversion for mpic
    
    This patch converts mpic to the new memory API (through old mmio).
    
    Signed-off-by: Fabien Chouteau <chouteau at adacore.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/openpic.c b/hw/openpic.c
index 26c96e2..88e997e 100644
--- a/hw/openpic.c
+++ b/hw/openpic.c
@@ -206,6 +206,10 @@ typedef struct IRQ_dst_t {
 typedef struct openpic_t {
     PCIDevice pci_dev;
     MemoryRegion mem;
+
+    /* Sub-regions */
+    MemoryRegion sub_io_mem[7];
+
     /* Global registers */
     uint32_t frep; /* Feature reporting register */
     uint32_t glbc; /* Global configuration register  */
@@ -1537,107 +1541,122 @@ static uint32_t mpic_src_msi_read (void *opaque, target_phys_addr_t addr)
     return retval;
 }
 
-static CPUWriteMemoryFunc * const mpic_glb_write[] = {
-    &openpic_buggy_write,
-    &openpic_buggy_write,
-    &openpic_gbl_write,
-};
-
-static CPUReadMemoryFunc * const mpic_glb_read[] = {
-    &openpic_buggy_read,
-    &openpic_buggy_read,
-    &openpic_gbl_read,
-};
-
-static CPUWriteMemoryFunc * const mpic_tmr_write[] = {
-    &openpic_buggy_write,
-    &openpic_buggy_write,
-    &mpic_timer_write,
+static const MemoryRegionOps mpic_glb_ops = {
+    .old_mmio = {
+        .write = { openpic_buggy_write,
+                   openpic_buggy_write,
+                   openpic_gbl_write,
+        },
+        .read  = { openpic_buggy_read,
+                   openpic_buggy_read,
+                   openpic_gbl_read,
+        },
+    },
+    .endianness = DEVICE_BIG_ENDIAN,
 };
 
-static CPUReadMemoryFunc * const mpic_tmr_read[] = {
-    &openpic_buggy_read,
-    &openpic_buggy_read,
-    &mpic_timer_read,
+static const MemoryRegionOps mpic_tmr_ops = {
+    .old_mmio = {
+        .write = { openpic_buggy_write,
+                   openpic_buggy_write,
+                   mpic_timer_write,
+        },
+        .read  = { openpic_buggy_read,
+                   openpic_buggy_read,
+                   mpic_timer_read,
+        },
+    },
+    .endianness = DEVICE_BIG_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const mpic_cpu_write[] = {
-    &openpic_buggy_write,
-    &openpic_buggy_write,
-    &openpic_cpu_write,
+static const MemoryRegionOps mpic_cpu_ops = {
+    .old_mmio = {
+        .write = { openpic_buggy_write,
+                   openpic_buggy_write,
+                   openpic_cpu_write,
+        },
+        .read  = { openpic_buggy_read,
+                   openpic_buggy_read,
+                   openpic_cpu_read,
+        },
+    },
+    .endianness = DEVICE_BIG_ENDIAN,
 };
 
-static CPUReadMemoryFunc * const mpic_cpu_read[] = {
-    &openpic_buggy_read,
-    &openpic_buggy_read,
-    &openpic_cpu_read,
+static const MemoryRegionOps mpic_ext_ops = {
+    .old_mmio = {
+        .write = { openpic_buggy_write,
+                   openpic_buggy_write,
+                   mpic_src_ext_write,
+        },
+        .read  = { openpic_buggy_read,
+                   openpic_buggy_read,
+                   mpic_src_ext_read,
+        },
+    },
+    .endianness = DEVICE_BIG_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const mpic_ext_write[] = {
-    &openpic_buggy_write,
-    &openpic_buggy_write,
-    &mpic_src_ext_write,
+static const MemoryRegionOps mpic_int_ops = {
+    .old_mmio = {
+        .write = { openpic_buggy_write,
+                   openpic_buggy_write,
+                   mpic_src_int_write,
+        },
+        .read  = { openpic_buggy_read,
+                   openpic_buggy_read,
+                   mpic_src_int_read,
+        },
+    },
+    .endianness = DEVICE_BIG_ENDIAN,
 };
 
-static CPUReadMemoryFunc * const mpic_ext_read[] = {
-    &openpic_buggy_read,
-    &openpic_buggy_read,
-    &mpic_src_ext_read,
+static const MemoryRegionOps mpic_msg_ops = {
+    .old_mmio = {
+        .write = { openpic_buggy_write,
+                   openpic_buggy_write,
+                   mpic_src_msg_write,
+        },
+        .read  = { openpic_buggy_read,
+                   openpic_buggy_read,
+                   mpic_src_msg_read,
+        },
+    },
+    .endianness = DEVICE_BIG_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const mpic_int_write[] = {
-    &openpic_buggy_write,
-    &openpic_buggy_write,
-    &mpic_src_int_write,
+static const MemoryRegionOps mpic_msi_ops = {
+    .old_mmio = {
+        .write = { openpic_buggy_write,
+                   openpic_buggy_write,
+                   mpic_src_msi_write,
+        },
+        .read  = { openpic_buggy_read,
+                   openpic_buggy_read,
+                   mpic_src_msi_read,
+        },
+    },
+    .endianness = DEVICE_BIG_ENDIAN,
 };
 
-static CPUReadMemoryFunc * const mpic_int_read[] = {
-    &openpic_buggy_read,
-    &openpic_buggy_read,
-    &mpic_src_int_read,
-};
-
-static CPUWriteMemoryFunc * const mpic_msg_write[] = {
-    &openpic_buggy_write,
-    &openpic_buggy_write,
-    &mpic_src_msg_write,
-};
-
-static CPUReadMemoryFunc * const mpic_msg_read[] = {
-    &openpic_buggy_read,
-    &openpic_buggy_read,
-    &mpic_src_msg_read,
-};
-static CPUWriteMemoryFunc * const mpic_msi_write[] = {
-    &openpic_buggy_write,
-    &openpic_buggy_write,
-    &mpic_src_msi_write,
-};
-
-static CPUReadMemoryFunc * const mpic_msi_read[] = {
-    &openpic_buggy_read,
-    &openpic_buggy_read,
-    &mpic_src_msi_read,
-};
-
-qemu_irq *mpic_init (target_phys_addr_t base, int nb_cpus,
-                        qemu_irq **irqs, qemu_irq irq_out)
+qemu_irq *mpic_init (MemoryRegion *address_space, target_phys_addr_t base,
+                     int nb_cpus, qemu_irq **irqs, qemu_irq irq_out)
 {
-    openpic_t *mpp;
-    int i;
+    openpic_t    *mpp;
+    int           i;
     struct {
-        CPUReadMemoryFunc * const *read;
-        CPUWriteMemoryFunc * const *write;
-        target_phys_addr_t start_addr;
-        ram_addr_t size;
+        const char             *name;
+        MemoryRegionOps const  *ops;
+        target_phys_addr_t      start_addr;
+        ram_addr_t              size;
     } const list[] = {
-        {mpic_glb_read, mpic_glb_write, MPIC_GLB_REG_START, MPIC_GLB_REG_SIZE},
-        {mpic_tmr_read, mpic_tmr_write, MPIC_TMR_REG_START, MPIC_TMR_REG_SIZE},
-        {mpic_ext_read, mpic_ext_write, MPIC_EXT_REG_START, MPIC_EXT_REG_SIZE},
-        {mpic_int_read, mpic_int_write, MPIC_INT_REG_START, MPIC_INT_REG_SIZE},
-        {mpic_msg_read, mpic_msg_write, MPIC_MSG_REG_START, MPIC_MSG_REG_SIZE},
-        {mpic_msi_read, mpic_msi_write, MPIC_MSI_REG_START, MPIC_MSI_REG_SIZE},
-        {mpic_cpu_read, mpic_cpu_write, MPIC_CPU_REG_START, MPIC_CPU_REG_SIZE},
+        {"glb", &mpic_glb_ops, MPIC_GLB_REG_START, MPIC_GLB_REG_SIZE},
+        {"tmr", &mpic_tmr_ops, MPIC_TMR_REG_START, MPIC_TMR_REG_SIZE},
+        {"ext", &mpic_ext_ops, MPIC_EXT_REG_START, MPIC_EXT_REG_SIZE},
+        {"int", &mpic_int_ops, MPIC_INT_REG_START, MPIC_INT_REG_SIZE},
+        {"msg", &mpic_msg_ops, MPIC_MSG_REG_START, MPIC_MSG_REG_SIZE},
+        {"msi", &mpic_msi_ops, MPIC_MSI_REG_START, MPIC_MSI_REG_SIZE},
+        {"cpu", &mpic_cpu_ops, MPIC_CPU_REG_START, MPIC_CPU_REG_SIZE},
     };
 
     /* XXX: for now, only one CPU is supported */
@@ -1646,16 +1665,16 @@ qemu_irq *mpic_init (target_phys_addr_t base, int nb_cpus,
 
     mpp = g_malloc0(sizeof(openpic_t));
 
+    memory_region_init(&mpp->mem, "mpic", 0x40000);
+    memory_region_add_subregion(address_space, base, &mpp->mem);
+
     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,
-                                           DEVICE_BIG_ENDIAN);
-        if (mem_index < 0) {
-            goto free;
-        }
-        cpu_register_physical_memory(base + list[i].start_addr,
-                                     list[i].size, mem_index);
+        memory_region_init_io(&mpp->sub_io_mem[i], list[i].ops, mpp,
+                              list[i].name, list[i].size);
+
+        memory_region_add_subregion(&mpp->mem, list[i].start_addr,
+                                    &mpp->sub_io_mem[i]);
     }
 
     mpp->nb_cpus = nb_cpus;
@@ -1674,8 +1693,4 @@ qemu_irq *mpic_init (target_phys_addr_t base, int nb_cpus,
     qemu_register_reset(mpic_reset, mpp);
 
     return qemu_allocate_irqs(openpic_set_irq, mpp, mpp->max_irq);
-
-free:
-    g_free(mpp);
-    return NULL;
 }
diff --git a/hw/openpic.h b/hw/openpic.h
index 75de361..715f084 100644
--- a/hw/openpic.h
+++ b/hw/openpic.h
@@ -13,6 +13,6 @@ enum {
 
 qemu_irq *openpic_init (PCIBus *bus, MemoryRegion **pmem, int nb_cpus,
                         qemu_irq **irqs, qemu_irq irq_out);
-qemu_irq *mpic_init (target_phys_addr_t base, int nb_cpus,
-                        qemu_irq **irqs, qemu_irq irq_out);
+qemu_irq *mpic_init (MemoryRegion *address_space, target_phys_addr_t base,
+                     int nb_cpus, qemu_irq **irqs, qemu_irq irq_out);
 #endif /* __OPENPIC_H__ */
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 274b37c..28acf0b 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -272,7 +272,7 @@ static void mpc8544ds_init(ram_addr_t ram_size,
     irqs = g_malloc0(sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
     irqs[OPENPIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPCE500_INPUT_INT];
     irqs[OPENPIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPCE500_INPUT_CINT];
-    mpic = mpic_init(MPC8544_MPIC_REGS_BASE, 1, &irqs, NULL);
+    mpic = mpic_init(address_space_mem, MPC8544_MPIC_REGS_BASE, 1, &irqs, NULL);
 
     /* Serial */
     if (serial_hds[0]) {
commit 5a95b51dd834462ed2ba82f6cf149b0cf5640ba4
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Wed Aug 24 18:28:21 2011 +0100

    hw/smc91c111: Convert to MemoryRegion
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/smc91c111.c b/hw/smc91c111.c
index 3a8a85c..fc8c498 100644
--- a/hw/smc91c111.c
+++ b/hw/smc91c111.c
@@ -43,7 +43,7 @@ typedef struct {
     uint8_t data[NUM_PACKETS][2048];
     uint8_t int_level;
     uint8_t int_mask;
-    int mmio_index;
+    MemoryRegion mmio;
 } smc91c111_state;
 
 static const VMStateDescription vmstate_smc91c111 = {
@@ -717,16 +717,15 @@ static ssize_t smc91c111_receive(VLANClientState *nc, const uint8_t *buf, size_t
     return size;
 }
 
-static CPUReadMemoryFunc * const smc91c111_readfn[] = {
-    smc91c111_readb,
-    smc91c111_readw,
-    smc91c111_readl
-};
-
-static CPUWriteMemoryFunc * const smc91c111_writefn[] = {
-    smc91c111_writeb,
-    smc91c111_writew,
-    smc91c111_writel
+static const MemoryRegionOps smc91c111_mem_ops = {
+    /* The special case for 32 bit writes to 0xc means we can't just
+     * set .impl.min/max_access_size to 1, unfortunately
+     */
+    .old_mmio = {
+        .read = { smc91c111_readb, smc91c111_readw, smc91c111_readl, },
+        .write = { smc91c111_writeb, smc91c111_writew, smc91c111_writel, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void smc91c111_cleanup(VLANClientState *nc)
@@ -747,11 +746,9 @@ static NetClientInfo net_smc91c111_info = {
 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,
-                                           DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, 16, s->mmio_index);
+    memory_region_init_io(&s->mmio, &smc91c111_mem_ops, s,
+                          "smc91c111-mmio", 16);
+    sysbus_init_mmio_region(dev, &s->mmio);
     sysbus_init_irq(dev, &s->irq);
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
     s->nic = qemu_new_nic(&net_smc91c111_info, &s->conf,
commit 38bc50f7e22a95a4cf4d8f326b7a94ea8104097a
Author: Richard Henderson <rth at twiddle.net>
Date:   Thu Aug 11 16:07:21 2011 -0700

    sun4u: Pass address_space_mem to sun4uv_init
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/sun4u.c b/hw/sun4u.c
index 28a5374..88c633d 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -736,7 +736,8 @@ static CPUState *cpu_devinit(const char *cpu_model, const struct hwdef *hwdef)
     return env;
 }
 
-static void sun4uv_init(ram_addr_t RAM_size,
+static void sun4uv_init(MemoryRegion *address_space_mem,
+                        ram_addr_t RAM_size,
                         const char *boot_devices,
                         const char *kernel_filename, const char *kernel_cmdline,
                         const char *initrd_filename, const char *cpu_model,
@@ -771,7 +772,7 @@ static void sun4uv_init(ram_addr_t RAM_size,
 
     i = 0;
     if (hwdef->console_serial_base) {
-        serial_mm_init(get_system_memory(), hwdef->console_serial_base, 0,
+        serial_mm_init(address_space_mem, hwdef->console_serial_base, 0,
                        NULL, 115200, serial_hds[i], DEVICE_BIG_ENDIAN);
         i++;
     }
@@ -876,7 +877,7 @@ static void sun4u_init(ram_addr_t RAM_size,
                        const char *kernel_filename, const char *kernel_cmdline,
                        const char *initrd_filename, const char *cpu_model)
 {
-    sun4uv_init(RAM_size, boot_devices, kernel_filename,
+    sun4uv_init(get_system_memory(), RAM_size, boot_devices, kernel_filename,
                 kernel_cmdline, initrd_filename, cpu_model, &hwdefs[0]);
 }
 
@@ -886,7 +887,7 @@ static void sun4v_init(ram_addr_t RAM_size,
                        const char *kernel_filename, const char *kernel_cmdline,
                        const char *initrd_filename, const char *cpu_model)
 {
-    sun4uv_init(RAM_size, boot_devices, kernel_filename,
+    sun4uv_init(get_system_memory(), RAM_size, boot_devices, kernel_filename,
                 kernel_cmdline, initrd_filename, cpu_model, &hwdefs[1]);
 }
 
@@ -896,7 +897,7 @@ static void niagara_init(ram_addr_t RAM_size,
                          const char *kernel_filename, const char *kernel_cmdline,
                          const char *initrd_filename, const char *cpu_model)
 {
-    sun4uv_init(RAM_size, boot_devices, kernel_filename,
+    sun4uv_init(get_system_memory(), RAM_size, boot_devices, kernel_filename,
                 kernel_cmdline, initrd_filename, cpu_model, &hwdefs[2]);
 }
 
commit 27a9d2eacb7f5533c31d6f0f1560ee824407f037
Author: Richard Henderson <rth at twiddle.net>
Date:   Thu Aug 11 16:07:20 2011 -0700

    sm501: Pass address_space_mem to sm501_init
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/devices.h b/hw/devices.h
index 07fda83..8ac384f 100644
--- a/hw/devices.h
+++ b/hw/devices.h
@@ -1,6 +1,9 @@
 #ifndef QEMU_DEVICES_H
 #define QEMU_DEVICES_H
 
+/* ??? Not all users of this file can include cpu-common.h.  */
+struct MemoryRegion;
+
 /* Devices that have nowhere better to go.  */
 
 /* smc91c111.c */
@@ -57,7 +60,8 @@ qemu_irq *tc6393xb_gpio_in_get(TC6393xbState *s);
 qemu_irq tc6393xb_l3v_get(TC6393xbState *s);
 
 /* sm501.c */
-void sm501_init(uint32_t base, uint32_t local_mem_bytes, qemu_irq irq,
+void sm501_init(struct MemoryRegion *address_space_mem, uint32_t base,
+                uint32_t local_mem_bytes, qemu_irq irq,
                 CharDriverState *chr);
 
 #endif
diff --git a/hw/r2d.c b/hw/r2d.c
index b8b0df3..82377a0 100644
--- a/hw/r2d.c
+++ b/hw/r2d.c
@@ -37,6 +37,7 @@
 #include "usb.h"
 #include "flash.h"
 #include "blockdev.h"
+#include "exec-memory.h"
 
 #define FLASH_BASE 0x00000000
 #define FLASH_SIZE 0x02000000
@@ -235,6 +236,7 @@ static void r2d_init(ram_addr_t ram_size,
     qemu_irq *irq;
     DriveInfo *dinfo;
     int i;
+    MemoryRegion *address_space_mem = get_system_memory();
 
     if (!cpu_model)
         cpu_model = "SH7751R";
@@ -258,7 +260,8 @@ static void r2d_init(ram_addr_t ram_size,
     sysbus_create_varargs("sh_pci", 0x1e200000, irq[PCI_INTA], irq[PCI_INTB],
                           irq[PCI_INTC], irq[PCI_INTD], NULL);
 
-    sm501_init(0x10000000, SM501_VRAM_SIZE, irq[SM501], serial_hds[2]);
+    sm501_init(address_space_mem, 0x10000000, SM501_VRAM_SIZE,
+               irq[SM501], serial_hds[2]);
 
     /* onboard CF (True IDE mode, Master only). */
     dinfo = drive_get(IF_IDE, 0, 0);
diff --git a/hw/sm501.c b/hw/sm501.c
index 6b54717..a7ed6fa 100644
--- a/hw/sm501.c
+++ b/hw/sm501.c
@@ -30,7 +30,6 @@
 #include "sysbus.h"
 #include "qdev-addr.h"
 #include "range.h"
-#include "exec-memory.h"
 
 /*
  * Status: 2010/05/07
@@ -1386,8 +1385,8 @@ static void sm501_update_display(void *opaque)
 	sm501_draw_crt(s);
 }
 
-void sm501_init(uint32_t base, uint32_t local_mem_bytes, qemu_irq irq,
-                CharDriverState *chr)
+void sm501_init(MemoryRegion *address_space_mem, uint32_t base,
+                uint32_t local_mem_bytes, qemu_irq irq, CharDriverState *chr)
 {
     SM501State * s;
     DeviceState *dev;
@@ -1441,7 +1440,7 @@ void sm501_init(uint32_t base, uint32_t local_mem_bytes, qemu_irq irq,
 
     /* bridge to serial emulation module */
     if (chr) {
-        serial_mm_init(get_system_memory(),
+        serial_mm_init(address_space_mem,
                        base + MMIO_BASE_OFFSET + SM501_UART0, 2,
                        NULL, /* TODO : chain irq to IRL */
                        115200, chr, DEVICE_NATIVE_ENDIAN);
commit a6dc4c2d95f7b7bd95a53e8c2e524a8a202b4d1f
Author: Richard Henderson <rth at twiddle.net>
Date:   Thu Aug 11 16:07:19 2011 -0700

    pxa: Pass in address_space to pxa{255, 270}_init
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/gumstix.c b/hw/gumstix.c
index b8b76f4..686a5ed 100644
--- a/hw/gumstix.c
+++ b/hw/gumstix.c
@@ -38,6 +38,7 @@
 #include "devices.h"
 #include "boards.h"
 #include "blockdev.h"
+#include "exec-memory.h"
 
 static const int sector_len = 128 * 1024;
 
@@ -49,11 +50,12 @@ static void connex_init(ram_addr_t ram_size,
     PXA2xxState *cpu;
     DriveInfo *dinfo;
     int be;
+    MemoryRegion *address_space_mem = get_system_memory();
 
     uint32_t connex_rom = 0x01000000;
     uint32_t connex_ram = 0x04000000;
 
-    cpu = pxa255_init(connex_ram);
+    cpu = pxa255_init(address_space_mem, connex_ram);
 
     dinfo = drive_get(IF_PFLASH, 0, 0);
     if (!dinfo) {
@@ -87,11 +89,12 @@ static void verdex_init(ram_addr_t ram_size,
     PXA2xxState *cpu;
     DriveInfo *dinfo;
     int be;
+    MemoryRegion *address_space_mem = get_system_memory();
 
     uint32_t verdex_rom = 0x02000000;
     uint32_t verdex_ram = 0x10000000;
 
-    cpu = pxa270_init(verdex_ram, cpu_model ?: "pxa270-c0");
+    cpu = pxa270_init(address_space_mem, verdex_ram, cpu_model ?: "pxa270-c0");
 
     dinfo = drive_get(IF_PFLASH, 0, 0);
     if (!dinfo) {
diff --git a/hw/mainstone.c b/hw/mainstone.c
index 336f31e..3ed6649 100644
--- a/hw/mainstone.c
+++ b/hw/mainstone.c
@@ -110,7 +110,7 @@ static void mainstone_common_init(MemoryRegion *address_space_mem,
         cpu_model = "pxa270-c5";
 
     /* Setup CPU & memory */
-    cpu = pxa270_init(mainstone_binfo.ram_size, cpu_model);
+    cpu = pxa270_init(address_space_mem, mainstone_binfo.ram_size, cpu_model);
     memory_region_init_ram(rom, NULL, "mainstone.rom", MAINSTONE_ROM);
     memory_region_set_readonly(rom, true);
     memory_region_add_subregion(address_space_mem, 0, rom);
diff --git a/hw/pxa.h b/hw/pxa.h
index 859fc67..1204165 100644
--- a/hw/pxa.h
+++ b/hw/pxa.h
@@ -9,6 +9,8 @@
 #ifndef PXA_H
 # define PXA_H			"pxa.h"
 
+#include "memory.h"
+
 /* Interrupt numbers */
 # define PXA2XX_PIC_SSP3	0
 # define PXA2XX_PIC_USBH2	2
@@ -173,7 +175,8 @@ struct PXA2xxI2SState {
 # define PA_FMT			"0x%08lx"
 # define REG_FMT		"0x" TARGET_FMT_plx
 
-PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision);
-PXA2xxState *pxa255_init(unsigned int sdram_size);
+PXA2xxState *pxa270_init(MemoryRegion *address_space, unsigned int sdram_size,
+                         const char *revision);
+PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size);
 
 #endif	/* PXA_H */
diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c
index c47e698..70d7c8a 100644
--- a/hw/pxa2xx.c
+++ b/hw/pxa2xx.c
@@ -15,7 +15,6 @@
 #include "ssi.h"
 #include "qemu-char.h"
 #include "blockdev.h"
-#include "exec-memory.h"
 
 static struct {
     target_phys_addr_t io_base;
@@ -2060,7 +2059,8 @@ static void pxa2xx_reset(void *opaque, int line, int level)
 }
 
 /* Initialise a PXA270 integrated chip (ARM based core).  */
-PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision)
+PXA2xxState *pxa270_init(MemoryRegion *address_space,
+                         unsigned int sdram_size, const char *revision)
 {
     PXA2xxState *s;
     int iomemtype, i;
@@ -2116,7 +2116,7 @@ PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision)
 
     for (i = 0; pxa270_serial[i].io_base; i++) {
         if (serial_hds[i]) {
-            serial_mm_init(get_system_memory(), pxa270_serial[i].io_base, 2,
+            serial_mm_init(address_space, pxa270_serial[i].io_base, 2,
                            qdev_get_gpio_in(s->pic, pxa270_serial[i].irqn),
                            14857000 / 16, serial_hds[i],
                            DEVICE_NATIVE_ENDIAN);
@@ -2199,7 +2199,7 @@ PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision)
 }
 
 /* Initialise a PXA255 integrated chip (ARM based core).  */
-PXA2xxState *pxa255_init(unsigned int sdram_size)
+PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size)
 {
     PXA2xxState *s;
     int iomemtype, i;
@@ -2248,7 +2248,7 @@ PXA2xxState *pxa255_init(unsigned int sdram_size)
 
     for (i = 0; pxa255_serial[i].io_base; i++) {
         if (serial_hds[i]) {
-            serial_mm_init(get_system_memory(), pxa255_serial[i].io_base, 2,
+            serial_mm_init(address_space, pxa255_serial[i].io_base, 2,
                            qdev_get_gpio_in(s->pic, pxa255_serial[i].irqn),
                            14745600 / 16, serial_hds[i],
                            DEVICE_NATIVE_ENDIAN);
diff --git a/hw/spitz.c b/hw/spitz.c
index 0adae59..6f8a94c 100644
--- a/hw/spitz.c
+++ b/hw/spitz.c
@@ -24,6 +24,7 @@
 #include "boards.h"
 #include "blockdev.h"
 #include "sysbus.h"
+#include "exec-memory.h"
 
 #undef REG_FMT
 #define REG_FMT			"0x%02lx"
@@ -896,12 +897,13 @@ static void spitz_common_init(ram_addr_t ram_size,
 {
     PXA2xxState *cpu;
     DeviceState *scp0, *scp1 = NULL;
+    MemoryRegion *address_space_mem = get_system_memory();
 
     if (!cpu_model)
         cpu_model = (model == terrier) ? "pxa270-c5" : "pxa270-c0";
 
     /* Setup CPU & memory */
-    cpu = pxa270_init(spitz_binfo.ram_size, cpu_model);
+    cpu = pxa270_init(address_space_mem, spitz_binfo.ram_size, cpu_model);
 
     sl_flash_register(cpu, (model == spitz) ? FLASH_128M : FLASH_1024M);
 
diff --git a/hw/tosa.c b/hw/tosa.c
index 7b407f4..92702d1 100644
--- a/hw/tosa.c
+++ b/hw/tosa.c
@@ -20,6 +20,7 @@
 #include "ssi.h"
 #include "blockdev.h"
 #include "sysbus.h"
+#include "exec-memory.h"
 
 #define TOSA_RAM    0x04000000
 #define TOSA_ROM	0x00800000
@@ -206,6 +207,7 @@ static void tosa_init(ram_addr_t ram_size,
                 const char *kernel_filename, const char *kernel_cmdline,
                 const char *initrd_filename, const char *cpu_model)
 {
+    MemoryRegion *address_space_mem = get_system_memory();
     PXA2xxState *cpu;
     TC6393xbState *tmio;
     DeviceState *scp0, *scp1;
@@ -213,7 +215,7 @@ static void tosa_init(ram_addr_t ram_size,
     if (!cpu_model)
         cpu_model = "pxa255";
 
-    cpu = pxa255_init(tosa_binfo.ram_size);
+    cpu = pxa255_init(address_space_mem, tosa_binfo.ram_size);
 
     cpu_register_physical_memory(0, TOSA_ROM,
                     qemu_ram_alloc(NULL, "tosa.rom", TOSA_ROM) | IO_MEM_ROM);
diff --git a/hw/z2.c b/hw/z2.c
index b6ae608..a03bb33 100644
--- a/hw/z2.c
+++ b/hw/z2.c
@@ -20,6 +20,7 @@
 #include "blockdev.h"
 #include "console.h"
 #include "audio/audio.h"
+#include "exec-memory.h"
 
 #ifdef DEBUG_Z2
 #define DPRINTF(fmt, ...) \
@@ -277,6 +278,7 @@ static void z2_init(ram_addr_t ram_size,
                 const char *kernel_filename, const char *kernel_cmdline,
                 const char *initrd_filename, const char *cpu_model)
 {
+    MemoryRegion *address_space_mem = get_system_memory();
     uint32_t sector_len = 0x10000;
     PXA2xxState *cpu;
     DriveInfo *dinfo;
@@ -290,7 +292,7 @@ static void z2_init(ram_addr_t ram_size,
     }
 
     /* Setup CPU & memory */
-    cpu = pxa270_init(z2_binfo.ram_size, cpu_model);
+    cpu = pxa270_init(address_space_mem, z2_binfo.ram_size, cpu_model);
 
 #ifdef TARGET_WORDS_BIGENDIAN
     be = 1;
commit 3e9f0113b4c5ec37fbba0a50b28ea26c8477da93
Author: Richard Henderson <rth at twiddle.net>
Date:   Thu Aug 11 16:07:18 2011 -0700

    ppc440: Pass in address_space_mem to ppc440ep_init
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/ppc440.c b/hw/ppc440.c
index 1d1376e..cd8a95d 100644
--- a/hw/ppc440.c
+++ b/hw/ppc440.c
@@ -20,7 +20,6 @@
 #include "ppc405.h"
 #include "sysemu.h"
 #include "kvm.h"
-#include "exec-memory.h"
 
 #define PPC440EP_PCI_CONFIG     0xeec00000
 #define PPC440EP_PCI_INTACK     0xeed00000
@@ -35,9 +34,9 @@ static const unsigned int ppc440ep_sdram_bank_sizes[] = {
     256<<20, 128<<20, 64<<20, 32<<20, 16<<20, 8<<20, 0
 };
 
-CPUState *ppc440ep_init(ram_addr_t *ram_size, PCIBus **pcip,
-                        const unsigned int pci_irq_nrs[4], int do_init,
-                        const char *cpu_model)
+CPUState *ppc440ep_init(MemoryRegion *address_space_mem, ram_addr_t *ram_size,
+                        PCIBus **pcip, const unsigned int pci_irq_nrs[4],
+                        int do_init, const char *cpu_model)
 {
     MemoryRegion *ram_memories
         = g_malloc(PPC440EP_SDRAM_NR_BANKS * sizeof(*ram_memories));
@@ -93,12 +92,12 @@ CPUState *ppc440ep_init(ram_addr_t *ram_size, PCIBus **pcip,
     isa_mmio_init(PPC440EP_PCI_IO, PPC440EP_PCI_IOLEN);
 
     if (serial_hds[0] != NULL) {
-        serial_mm_init(get_system_memory(), 0xef600300, 0, pic[0],
+        serial_mm_init(address_space_mem, 0xef600300, 0, pic[0],
                        PPC_SERIAL_MM_BAUDBASE, serial_hds[0],
                        DEVICE_BIG_ENDIAN);
     }
     if (serial_hds[1] != NULL) {
-        serial_mm_init(get_system_memory(), 0xef600400, 0, pic[1],
+        serial_mm_init(address_space_mem, 0xef600400, 0, pic[1],
                        PPC_SERIAL_MM_BAUDBASE, serial_hds[1],
                        DEVICE_BIG_ENDIAN);
     }
diff --git a/hw/ppc440.h b/hw/ppc440.h
index a40f917..9c27c36 100644
--- a/hw/ppc440.h
+++ b/hw/ppc440.h
@@ -14,8 +14,8 @@
 
 #include "hw.h"
 
-CPUState *ppc440ep_init(ram_addr_t *ram_size, PCIBus **pcip,
-                        const unsigned int pci_irq_nrs[4], int do_init,
-                        const char *cpu_model);
+CPUState *ppc440ep_init(MemoryRegion *address_space, ram_addr_t *ram_size,
+                        PCIBus **pcip, const unsigned int pci_irq_nrs[4],
+                        int do_init, const char *cpu_model);
 
 #endif
diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c
index 1addb68..9228939 100644
--- a/hw/ppc440_bamboo.c
+++ b/hw/ppc440_bamboo.c
@@ -23,6 +23,7 @@
 #include "device_tree.h"
 #include "loader.h"
 #include "elf.h"
+#include "exec-memory.h"
 
 #define BINARY_DEVICE_TREE_FILE "bamboo.dtb"
 
@@ -96,6 +97,7 @@ static void bamboo_init(ram_addr_t ram_size,
                         const char *cpu_model)
 {
     unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 };
+    MemoryRegion *address_space_mem = get_system_memory();
     PCIBus *pcibus;
     CPUState *env;
     uint64_t elf_entry;
@@ -107,7 +109,8 @@ static void bamboo_init(ram_addr_t ram_size,
     int i;
 
     /* Setup CPU. */
-    env = ppc440ep_init(&ram_size, &pcibus, pci_irq_nrs, 1, cpu_model);
+    env = ppc440ep_init(address_space_mem, &ram_size, &pcibus,
+                        pci_irq_nrs, 1, cpu_model);
 
     if (pcibus) {
         /* Register network interfaces. */
commit 52ce55a1024bc4b0d2c726080a205123efdd9780
Author: Richard Henderson <rth at twiddle.net>
Date:   Thu Aug 11 16:07:17 2011 -0700

    ppc405: Pass in address_space_mem to ppc405{cr, ep}_init
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/ppc405.h b/hw/ppc405.h
index f0e81a6..d8fdf09 100644
--- a/hw/ppc405.h
+++ b/hw/ppc405.h
@@ -59,16 +59,18 @@ struct ppc4xx_bd_info_t {
 ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd,
                                 uint32_t flags);
 
-CPUState *ppc405cr_init (MemoryRegion ram_memories[4],
-                         target_phys_addr_t ram_bases[4],
-                         target_phys_addr_t ram_sizes[4],
-                         uint32_t sysclk, qemu_irq **picp,
-                         int do_init);
-CPUState *ppc405ep_init (MemoryRegion ram_memories[2],
-                         target_phys_addr_t ram_bases[2],
-                         target_phys_addr_t ram_sizes[2],
-                         uint32_t sysclk, qemu_irq **picp,
-                         int do_init);
+CPUState *ppc405cr_init(MemoryRegion *address_space_mem,
+                        MemoryRegion ram_memories[4],
+                        target_phys_addr_t ram_bases[4],
+                        target_phys_addr_t ram_sizes[4],
+                        uint32_t sysclk, qemu_irq **picp,
+                        int do_init);
+CPUState *ppc405ep_init(MemoryRegion *address_space_mem,
+                        MemoryRegion ram_memories[2],
+                        target_phys_addr_t ram_bases[2],
+                        target_phys_addr_t ram_sizes[2],
+                        uint32_t sysclk, qemu_irq **picp,
+                        int do_init);
 /* IBM STBxxx microcontrollers */
 CPUState *ppc_stb025_init (MemoryRegion ram_memories[2],
                            target_phys_addr_t ram_bases[2],
diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c
index e6c8ac6..ca65ac3 100644
--- a/hw/ppc405_boards.c
+++ b/hw/ppc405_boards.c
@@ -207,8 +207,8 @@ static void ref405ep_init (ram_addr_t ram_size,
 #ifdef DEBUG_BOARD_INIT
     printf("%s: register cpu\n", __func__);
 #endif
-    env = ppc405ep_init(ram_memories, ram_bases, ram_sizes, 33333333, &pic,
-                        kernel_filename == NULL ? 0 : 1);
+    env = ppc405ep_init(get_system_memory(), ram_memories, ram_bases, ram_sizes,
+                        33333333, &pic, kernel_filename == NULL ? 0 : 1);
     /* allocate SRAM */
     sram_size = 512 * 1024;
     sram_offset = qemu_ram_alloc(NULL, "ef405ep.sram", sram_size);
@@ -534,8 +534,8 @@ static void taihu_405ep_init(ram_addr_t ram_size,
 #ifdef DEBUG_BOARD_INIT
     printf("%s: register cpu\n", __func__);
 #endif
-    ppc405ep_init(ram_memories, ram_bases, ram_sizes, 33333333, &pic,
-                  kernel_filename == NULL ? 0 : 1);
+    ppc405ep_init(get_system_memory(), ram_memories, ram_bases, ram_sizes,
+                  33333333, &pic, kernel_filename == NULL ? 0 : 1);
     /* allocate and load BIOS */
 #ifdef DEBUG_BOARD_INIT
     printf("%s: register BIOS\n", __func__);
diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c
index 86cf768..a6e7431 100644
--- a/hw/ppc405_uc.c
+++ b/hw/ppc405_uc.c
@@ -2107,11 +2107,12 @@ static void ppc405cr_cpc_init (CPUState *env, clk_setup_t clk_setup[7],
     qemu_register_reset(ppc405cr_cpc_reset, cpc);
 }
 
-CPUState *ppc405cr_init (MemoryRegion ram_memories[4],
-                         target_phys_addr_t ram_bases[4],
-                         target_phys_addr_t ram_sizes[4],
-                         uint32_t sysclk, qemu_irq **picp,
-                         int do_init)
+CPUState *ppc405cr_init(MemoryRegion *address_space_mem,
+                        MemoryRegion ram_memories[4],
+                        target_phys_addr_t ram_bases[4],
+                        target_phys_addr_t ram_sizes[4],
+                        uint32_t sysclk, qemu_irq **picp,
+                        int do_init)
 {
     clk_setup_t clk_setup[PPC405CR_CLK_NB];
     qemu_irq dma_irqs[4];
@@ -2149,12 +2150,12 @@ CPUState *ppc405cr_init (MemoryRegion ram_memories[4],
     ppc405_dma_init(env, dma_irqs);
     /* Serial ports */
     if (serial_hds[0] != NULL) {
-        serial_mm_init(get_system_memory(), 0xef600300, 0, pic[0],
+        serial_mm_init(address_space_mem, 0xef600300, 0, pic[0],
                        PPC_SERIAL_MM_BAUDBASE, serial_hds[0],
                        DEVICE_BIG_ENDIAN);
     }
     if (serial_hds[1] != NULL) {
-        serial_mm_init(get_system_memory(), 0xef600400, 0, pic[1],
+        serial_mm_init(address_space_mem, 0xef600400, 0, pic[1],
                        PPC_SERIAL_MM_BAUDBASE, serial_hds[1],
                        DEVICE_BIG_ENDIAN);
     }
@@ -2455,11 +2456,12 @@ static void ppc405ep_cpc_init (CPUState *env, clk_setup_t clk_setup[8],
 #endif
 }
 
-CPUState *ppc405ep_init (MemoryRegion ram_memories[2],
-                         target_phys_addr_t ram_bases[2],
-                         target_phys_addr_t ram_sizes[2],
-                         uint32_t sysclk, qemu_irq **picp,
-                         int do_init)
+CPUState *ppc405ep_init(MemoryRegion *address_space_mem,
+                        MemoryRegion ram_memories[2],
+                        target_phys_addr_t ram_bases[2],
+                        target_phys_addr_t ram_sizes[2],
+                        uint32_t sysclk, qemu_irq **picp,
+                        int do_init)
 {
     clk_setup_t clk_setup[PPC405EP_CLK_NB], tlb_clk_setup;
     qemu_irq dma_irqs[4], gpt_irqs[5], mal_irqs[4];
@@ -2506,12 +2508,12 @@ CPUState *ppc405ep_init (MemoryRegion ram_memories[2],
     ppc405_gpio_init(0xef600700);
     /* Serial ports */
     if (serial_hds[0] != NULL) {
-        serial_mm_init(get_system_memory(), 0xef600300, 0, pic[0],
+        serial_mm_init(address_space_mem, 0xef600300, 0, pic[0],
                        PPC_SERIAL_MM_BAUDBASE, serial_hds[0],
                        DEVICE_BIG_ENDIAN);
     }
     if (serial_hds[1] != NULL) {
-        serial_mm_init(get_system_memory(), 0xef600400, 0, pic[1],
+        serial_mm_init(address_space_mem, 0xef600400, 0, pic[1],
                        PPC_SERIAL_MM_BAUDBASE, serial_hds[1],
                        DEVICE_BIG_ENDIAN);
     }
commit 39186d8ab8af8937cee4743cc1956bdc28923ac9
Author: Richard Henderson <rth at twiddle.net>
Date:   Thu Aug 11 16:07:16 2011 -0700

    serial: Add MemoryRegion parameter to serial_mm_init
    
    Remove the get_system_memory() call from serial_mm_init, pushing
    it back into the callers.  In many cases we already have the
    system memory region available.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c
index 1f3998f..14beea2 100644
--- a/hw/mips_jazz.c
+++ b/hw/mips_jazz.c
@@ -264,12 +264,12 @@ static void mips_jazz_init(MemoryRegion *address_space,
 
     /* Serial ports */
     if (serial_hds[0]) {
-        serial_mm_init(0x80006000, 0, rc4030[8], 8000000/16, serial_hds[0],
-                       DEVICE_NATIVE_ENDIAN);
+        serial_mm_init(address_space, 0x80006000, 0, rc4030[8], 8000000/16,
+                       serial_hds[0], DEVICE_NATIVE_ENDIAN);
     }
     if (serial_hds[1]) {
-        serial_mm_init(0x80007000, 0, rc4030[9], 8000000/16, serial_hds[1],
-                       DEVICE_NATIVE_ENDIAN);
+        serial_mm_init(address_space, 0x80007000, 0, rc4030[9], 8000000/16,
+                       serial_hds[1], DEVICE_NATIVE_ENDIAN);
     }
 
     /* Parallel port */
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index 84d1e47..bb49749 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -446,8 +446,8 @@ static MaltaFPGAState *malta_fpga_init(MemoryRegion *address_space,
 
     s->display = qemu_chr_new("fpga", "vc:320x200", malta_fpga_led_init);
 
-    s->uart = serial_mm_init(base + 0x900, 3, uart_irq, 230400, uart_chr,
-                             DEVICE_NATIVE_ENDIAN);
+    s->uart = serial_mm_init(address_space, base + 0x900, 3, uart_irq,
+                             230400, uart_chr, DEVICE_NATIVE_ENDIAN);
 
     malta_fpga_reset(s);
     qemu_register_reset(malta_fpga_reset, s);
diff --git a/hw/musicpal.c b/hw/musicpal.c
index 2131db1..20553b5 100644
--- a/hw/musicpal.c
+++ b/hw/musicpal.c
@@ -1486,12 +1486,12 @@ static void musicpal_init(ram_addr_t ram_size,
                           pic[MP_TIMER4_IRQ], NULL);
 
     if (serial_hds[0]) {
-        serial_mm_init(MP_UART1_BASE, 2, pic[MP_UART1_IRQ], 1825000,
-                       serial_hds[0], DEVICE_NATIVE_ENDIAN);
+        serial_mm_init(address_space_mem, MP_UART1_BASE, 2, pic[MP_UART1_IRQ],
+                       1825000, serial_hds[0], DEVICE_NATIVE_ENDIAN);
     }
     if (serial_hds[1]) {
-        serial_mm_init(MP_UART2_BASE, 2, pic[MP_UART2_IRQ], 1825000,
-                       serial_hds[1], DEVICE_NATIVE_ENDIAN);
+        serial_mm_init(address_space_mem, MP_UART2_BASE, 2, pic[MP_UART2_IRQ],
+                       1825000, serial_hds[1], DEVICE_NATIVE_ENDIAN);
     }
 
     /* Register flash */
diff --git a/hw/omap_uart.c b/hw/omap_uart.c
index b43f04c..19f8e6e 100644
--- a/hw/omap_uart.c
+++ b/hw/omap_uart.c
@@ -22,6 +22,7 @@
 #include "omap.h"
 /* We use pc-style serial ports.  */
 #include "pc.h"
+#include "exec-memory.h"
 
 /* UARTs */
 struct omap_uart_s {
@@ -60,7 +61,8 @@ struct omap_uart_s *omap_uart_init(target_phys_addr_t base,
     s->base = base;
     s->fclk = fclk;
     s->irq = irq;
-    s->serial = serial_mm_init(base, 2, irq, omap_clk_getrate(fclk)/16,
+    s->serial = serial_mm_init(get_system_memory(), base, 2, irq,
+                               omap_clk_getrate(fclk)/16,
                                chr ?: qemu_chr_new(label, "null", NULL),
                                DEVICE_NATIVE_ENDIAN);
     return s;
@@ -176,7 +178,7 @@ struct omap_uart_s *omap2_uart_init(struct omap_target_agent_s *ta,
 void omap_uart_attach(struct omap_uart_s *s, CharDriverState *chr)
 {
     /* TODO: Should reuse or destroy current s->serial */
-    s->serial = serial_mm_init(s->base, 2, s->irq,
+    s->serial = serial_mm_init(get_system_memory(), s->base, 2, s->irq,
                                omap_clk_getrate(s->fclk) / 16,
                                chr ?: qemu_chr_new("null", "null", NULL),
                                DEVICE_NATIVE_ENDIAN);
diff --git a/hw/pc.h b/hw/pc.h
index a0d7265..f3e21b6 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -15,9 +15,10 @@
 
 SerialState *serial_init(int base, qemu_irq irq, int baudbase,
                          CharDriverState *chr);
-SerialState *serial_mm_init (target_phys_addr_t base, int it_shift,
-                             qemu_irq irq, int baudbase,
-                             CharDriverState *chr, enum device_endian);
+SerialState *serial_mm_init(MemoryRegion *address_space,
+                            target_phys_addr_t base, int it_shift,
+                            qemu_irq irq, int baudbase,
+                            CharDriverState *chr, enum device_endian);
 static inline bool serial_isa_init(int index, CharDriverState *chr)
 {
     ISADevice *dev;
diff --git a/hw/petalogix_ml605_mmu.c b/hw/petalogix_ml605_mmu.c
index ab89341..2a0f7fd 100644
--- a/hw/petalogix_ml605_mmu.c
+++ b/hw/petalogix_ml605_mmu.c
@@ -38,6 +38,7 @@
 #include "elf.h"
 #include "blockdev.h"
 #include "pc.h"
+#include "exec-memory.h"
 
 #include "microblaze_pic_cpu.h"
 #include "xilinx_axidma.h"
@@ -141,6 +142,7 @@ petalogix_ml605_init(ram_addr_t ram_size,
                           const char *kernel_cmdline,
                           const char *initrd_filename, const char *cpu_model)
 {
+    MemoryRegion *address_space_mem = get_system_memory();
     DeviceState *dev;
     CPUState *env;
     int kernel_size;
@@ -184,8 +186,8 @@ petalogix_ml605_init(ram_addr_t ram_size,
         irq[i] = qdev_get_gpio_in(dev, i);
     }
 
-    serial_mm_init(UART16550_BASEADDR + 0x1000, 2, irq[5], 115200,
-                   serial_hds[0], DEVICE_LITTLE_ENDIAN);
+    serial_mm_init(address_space_mem, UART16550_BASEADDR + 0x1000, 2,
+                   irq[5], 115200, serial_hds[0], DEVICE_LITTLE_ENDIAN);
 
     /* 2 timers at irq 2 @ 100 Mhz.  */
     xilinx_timer_create(TIMER_BASEADDR, irq[2], 2, 100 * 1000000);
diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c
index 924aada..86cf768 100644
--- a/hw/ppc405_uc.c
+++ b/hw/ppc405_uc.c
@@ -2149,12 +2149,14 @@ CPUState *ppc405cr_init (MemoryRegion ram_memories[4],
     ppc405_dma_init(env, dma_irqs);
     /* Serial ports */
     if (serial_hds[0] != NULL) {
-        serial_mm_init(0xef600300, 0, pic[0], PPC_SERIAL_MM_BAUDBASE,
-                       serial_hds[0], DEVICE_BIG_ENDIAN);
+        serial_mm_init(get_system_memory(), 0xef600300, 0, pic[0],
+                       PPC_SERIAL_MM_BAUDBASE, serial_hds[0],
+                       DEVICE_BIG_ENDIAN);
     }
     if (serial_hds[1] != NULL) {
-        serial_mm_init(0xef600400, 0, pic[1], PPC_SERIAL_MM_BAUDBASE,
-                       serial_hds[1], DEVICE_BIG_ENDIAN);
+        serial_mm_init(get_system_memory(), 0xef600400, 0, pic[1],
+                       PPC_SERIAL_MM_BAUDBASE, serial_hds[1],
+                       DEVICE_BIG_ENDIAN);
     }
     /* IIC controller */
     ppc405_i2c_init(0xef600500, pic[2]);
@@ -2504,12 +2506,14 @@ CPUState *ppc405ep_init (MemoryRegion ram_memories[2],
     ppc405_gpio_init(0xef600700);
     /* Serial ports */
     if (serial_hds[0] != NULL) {
-        serial_mm_init(0xef600300, 0, pic[0], PPC_SERIAL_MM_BAUDBASE,
-                       serial_hds[0], DEVICE_BIG_ENDIAN);
+        serial_mm_init(get_system_memory(), 0xef600300, 0, pic[0],
+                       PPC_SERIAL_MM_BAUDBASE, serial_hds[0],
+                       DEVICE_BIG_ENDIAN);
     }
     if (serial_hds[1] != NULL) {
-        serial_mm_init(0xef600400, 0, pic[1], PPC_SERIAL_MM_BAUDBASE,
-                       serial_hds[1], DEVICE_BIG_ENDIAN);
+        serial_mm_init(get_system_memory(), 0xef600400, 0, pic[1],
+                       PPC_SERIAL_MM_BAUDBASE, serial_hds[1],
+                       DEVICE_BIG_ENDIAN);
     }
     /* OCM */
     ppc405_ocm_init(env);
diff --git a/hw/ppc440.c b/hw/ppc440.c
index 0cd7bca..1d1376e 100644
--- a/hw/ppc440.c
+++ b/hw/ppc440.c
@@ -20,6 +20,7 @@
 #include "ppc405.h"
 #include "sysemu.h"
 #include "kvm.h"
+#include "exec-memory.h"
 
 #define PPC440EP_PCI_CONFIG     0xeec00000
 #define PPC440EP_PCI_INTACK     0xeed00000
@@ -92,12 +93,14 @@ CPUState *ppc440ep_init(ram_addr_t *ram_size, PCIBus **pcip,
     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,
-                       serial_hds[0], DEVICE_BIG_ENDIAN);
+        serial_mm_init(get_system_memory(), 0xef600300, 0, pic[0],
+                       PPC_SERIAL_MM_BAUDBASE, serial_hds[0],
+                       DEVICE_BIG_ENDIAN);
     }
     if (serial_hds[1] != NULL) {
-        serial_mm_init(0xef600400, 0, pic[1], PPC_SERIAL_MM_BAUDBASE,
-                       serial_hds[1], DEVICE_BIG_ENDIAN);
+        serial_mm_init(get_system_memory(), 0xef600400, 0, pic[1],
+                       PPC_SERIAL_MM_BAUDBASE, serial_hds[1],
+                       DEVICE_BIG_ENDIAN);
     }
 
     return env;
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index fc46991..274b37c 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -32,6 +32,7 @@
 #include "loader.h"
 #include "elf.h"
 #include "sysbus.h"
+#include "exec-memory.h"
 
 #define BINARY_DEVICE_TREE_FILE    "mpc8544ds.dtb"
 #define UIMAGE_LOAD_BASE           0
@@ -225,6 +226,7 @@ static void mpc8544ds_init(ram_addr_t ram_size,
                          const char *initrd_filename,
                          const char *cpu_model)
 {
+    MemoryRegion *address_space_mem = get_system_memory();
     PCIBus *pci_bus;
     CPUState *env;
     uint64_t elf_entry;
@@ -274,13 +276,13 @@ static void mpc8544ds_init(ram_addr_t ram_size,
 
     /* Serial */
     if (serial_hds[0]) {
-        serial_mm_init(MPC8544_SERIAL0_REGS_BASE,
+        serial_mm_init(address_space_mem, MPC8544_SERIAL0_REGS_BASE,
                        0, mpic[12+26], 399193,
                        serial_hds[0], DEVICE_BIG_ENDIAN);
     }
 
     if (serial_hds[1]) {
-        serial_mm_init(MPC8544_SERIAL1_REGS_BASE,
+        serial_mm_init(address_space_mem, MPC8544_SERIAL1_REGS_BASE,
                        0, mpic[12+26], 399193,
                        serial_hds[0], DEVICE_BIG_ENDIAN);
     }
diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c
index 60f4c34..c47e698 100644
--- a/hw/pxa2xx.c
+++ b/hw/pxa2xx.c
@@ -15,6 +15,7 @@
 #include "ssi.h"
 #include "qemu-char.h"
 #include "blockdev.h"
+#include "exec-memory.h"
 
 static struct {
     target_phys_addr_t io_base;
@@ -2115,7 +2116,7 @@ PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision)
 
     for (i = 0; pxa270_serial[i].io_base; i++) {
         if (serial_hds[i]) {
-            serial_mm_init(pxa270_serial[i].io_base, 2,
+            serial_mm_init(get_system_memory(), pxa270_serial[i].io_base, 2,
                            qdev_get_gpio_in(s->pic, pxa270_serial[i].irqn),
                            14857000 / 16, serial_hds[i],
                            DEVICE_NATIVE_ENDIAN);
@@ -2247,7 +2248,7 @@ PXA2xxState *pxa255_init(unsigned int sdram_size)
 
     for (i = 0; pxa255_serial[i].io_base; i++) {
         if (serial_hds[i]) {
-            serial_mm_init(pxa255_serial[i].io_base, 2,
+            serial_mm_init(get_system_memory(), pxa255_serial[i].io_base, 2,
                            qdev_get_gpio_in(s->pic, pxa255_serial[i].irqn),
                            14745600 / 16, serial_hds[i],
                            DEVICE_NATIVE_ENDIAN);
diff --git a/hw/serial.c b/hw/serial.c
index 0fafc1d..d35c7a9 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -28,7 +28,6 @@
 #include "pc.h"
 #include "qemu-timer.h"
 #include "sysemu.h"
-#include "exec-memory.h"
 
 //#define DEBUG_SERIAL
 
@@ -855,9 +854,10 @@ static const MemoryRegionOps serial_mm_ops[3] = {
     },
 };
 
-SerialState *serial_mm_init (target_phys_addr_t base, int it_shift,
-                             qemu_irq irq, int baudbase,
-                             CharDriverState *chr, enum device_endian end)
+SerialState *serial_mm_init(MemoryRegion *address_space,
+                            target_phys_addr_t base, int it_shift,
+                            qemu_irq irq, int baudbase,
+                            CharDriverState *chr, enum device_endian end)
 {
     SerialState *s;
 
@@ -873,7 +873,7 @@ SerialState *serial_mm_init (target_phys_addr_t base, int it_shift,
 
     memory_region_init_io(&s->io, &serial_mm_ops[end], s,
                           "serial", 8 << it_shift);
-    memory_region_add_subregion(get_system_memory(), base, &s->io);
+    memory_region_add_subregion(address_space, base, &s->io);
 
     serial_update_msl(s);
     return s;
diff --git a/hw/sm501.c b/hw/sm501.c
index fddf21a..6b54717 100644
--- a/hw/sm501.c
+++ b/hw/sm501.c
@@ -30,6 +30,7 @@
 #include "sysbus.h"
 #include "qdev-addr.h"
 #include "range.h"
+#include "exec-memory.h"
 
 /*
  * Status: 2010/05/07
@@ -1440,7 +1441,8 @@ void sm501_init(uint32_t base, uint32_t local_mem_bytes, qemu_irq irq,
 
     /* bridge to serial emulation module */
     if (chr) {
-        serial_mm_init(base + MMIO_BASE_OFFSET + SM501_UART0, 2,
+        serial_mm_init(get_system_memory(),
+                       base + MMIO_BASE_OFFSET + SM501_UART0, 2,
                        NULL, /* TODO : chain irq to IRL */
                        115200, chr, DEVICE_NATIVE_ENDIAN);
     }
diff --git a/hw/sun4u.c b/hw/sun4u.c
index 60e1e9d..28a5374 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -38,6 +38,7 @@
 #include "loader.h"
 #include "elf.h"
 #include "blockdev.h"
+#include "exec-memory.h"
 
 //#define DEBUG_IRQ
 //#define DEBUG_EBUS
@@ -770,8 +771,8 @@ static void sun4uv_init(ram_addr_t RAM_size,
 
     i = 0;
     if (hwdef->console_serial_base) {
-        serial_mm_init(hwdef->console_serial_base, 0, NULL, 115200,
-                       serial_hds[i], DEVICE_BIG_ENDIAN);
+        serial_mm_init(get_system_memory(), hwdef->console_serial_base, 0,
+                       NULL, 115200, serial_hds[i], DEVICE_BIG_ENDIAN);
         i++;
     }
     for(; i < MAX_SERIAL_PORTS; i++) {
diff --git a/hw/virtex_ml507.c b/hw/virtex_ml507.c
index 8c52a06..68bf53a 100644
--- a/hw/virtex_ml507.c
+++ b/hw/virtex_ml507.c
@@ -34,6 +34,7 @@
 #include "loader.h"
 #include "elf.h"
 #include "qemu-log.h"
+#include "exec-memory.h"
 
 #include "ppc.h"
 #include "ppc4xx.h"
@@ -191,6 +192,7 @@ static void virtex_init(ram_addr_t ram_size,
                         const char *kernel_cmdline,
                         const char *initrd_filename, const char *cpu_model)
 {
+    MemoryRegion *address_space_mem = get_system_memory();
     DeviceState *dev;
     CPUState *env;
     target_phys_addr_t ram_base = 0;
@@ -226,8 +228,8 @@ static void virtex_init(ram_addr_t ram_size,
         irq[i] = qdev_get_gpio_in(dev, i);
     }
 
-    serial_mm_init(0x83e01003ULL, 2, irq[9], 115200, serial_hds[0],
-                   DEVICE_LITTLE_ENDIAN);
+    serial_mm_init(address_space_mem, 0x83e01003ULL, 2, irq[9], 115200,
+                   serial_hds[0], DEVICE_LITTLE_ENDIAN);
 
     /* 2 timers at irq 2 @ 62 Mhz.  */
     xilinx_timer_create(0x83c00000, irq[3], 2, 62 * 1000000);
commit 2ff0c7c3c2251e7e81e90c9556dda64261d033ec
Author: Richard Henderson <rth at twiddle.net>
Date:   Thu Aug 11 16:07:15 2011 -0700

    serial: Remove ioregister parameter from serial_mm_init
    
    All callers passed 1.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c
index 9a87a8e..1f3998f 100644
--- a/hw/mips_jazz.c
+++ b/hw/mips_jazz.c
@@ -265,11 +265,11 @@ static void mips_jazz_init(MemoryRegion *address_space,
     /* Serial ports */
     if (serial_hds[0]) {
         serial_mm_init(0x80006000, 0, rc4030[8], 8000000/16, serial_hds[0],
-                       1, DEVICE_NATIVE_ENDIAN);
+                       DEVICE_NATIVE_ENDIAN);
     }
     if (serial_hds[1]) {
         serial_mm_init(0x80007000, 0, rc4030[9], 8000000/16, serial_hds[1],
-                       1, DEVICE_NATIVE_ENDIAN);
+                       DEVICE_NATIVE_ENDIAN);
     }
 
     /* Parallel port */
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index 0b16914..84d1e47 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -447,7 +447,7 @@ static MaltaFPGAState *malta_fpga_init(MemoryRegion *address_space,
     s->display = qemu_chr_new("fpga", "vc:320x200", malta_fpga_led_init);
 
     s->uart = serial_mm_init(base + 0x900, 3, uart_irq, 230400, uart_chr,
-                             1, DEVICE_NATIVE_ENDIAN);
+                             DEVICE_NATIVE_ENDIAN);
 
     malta_fpga_reset(s);
     qemu_register_reset(malta_fpga_reset, s);
diff --git a/hw/musicpal.c b/hw/musicpal.c
index e79b07e..2131db1 100644
--- a/hw/musicpal.c
+++ b/hw/musicpal.c
@@ -1487,11 +1487,11 @@ static void musicpal_init(ram_addr_t ram_size,
 
     if (serial_hds[0]) {
         serial_mm_init(MP_UART1_BASE, 2, pic[MP_UART1_IRQ], 1825000,
-                       serial_hds[0], 1, DEVICE_NATIVE_ENDIAN);
+                       serial_hds[0], DEVICE_NATIVE_ENDIAN);
     }
     if (serial_hds[1]) {
         serial_mm_init(MP_UART2_BASE, 2, pic[MP_UART2_IRQ], 1825000,
-                       serial_hds[1], 1, DEVICE_NATIVE_ENDIAN);
+                       serial_hds[1], DEVICE_NATIVE_ENDIAN);
     }
 
     /* Register flash */
diff --git a/hw/omap_uart.c b/hw/omap_uart.c
index 66696ab..b43f04c 100644
--- a/hw/omap_uart.c
+++ b/hw/omap_uart.c
@@ -61,7 +61,7 @@ struct omap_uart_s *omap_uart_init(target_phys_addr_t base,
     s->fclk = fclk;
     s->irq = irq;
     s->serial = serial_mm_init(base, 2, irq, omap_clk_getrate(fclk)/16,
-                               chr ?: qemu_chr_new(label, "null", NULL), 1,
+                               chr ?: qemu_chr_new(label, "null", NULL),
                                DEVICE_NATIVE_ENDIAN);
     return s;
 }
@@ -178,6 +178,6 @@ void omap_uart_attach(struct omap_uart_s *s, CharDriverState *chr)
     /* TODO: Should reuse or destroy current s->serial */
     s->serial = serial_mm_init(s->base, 2, s->irq,
                                omap_clk_getrate(s->fclk) / 16,
-                               chr ?: qemu_chr_new("null", "null", NULL), 1,
+                               chr ?: qemu_chr_new("null", "null", NULL),
                                DEVICE_NATIVE_ENDIAN);
 }
diff --git a/hw/pc.h b/hw/pc.h
index d70b81a..a0d7265 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -17,8 +17,7 @@ SerialState *serial_init(int base, qemu_irq irq, int baudbase,
                          CharDriverState *chr);
 SerialState *serial_mm_init (target_phys_addr_t base, int it_shift,
                              qemu_irq irq, int baudbase,
-                             CharDriverState *chr, int ioregister,
-                             enum device_endian);
+                             CharDriverState *chr, enum device_endian);
 static inline bool serial_isa_init(int index, CharDriverState *chr)
 {
     ISADevice *dev;
diff --git a/hw/petalogix_ml605_mmu.c b/hw/petalogix_ml605_mmu.c
index 97ff33d..ab89341 100644
--- a/hw/petalogix_ml605_mmu.c
+++ b/hw/petalogix_ml605_mmu.c
@@ -185,7 +185,7 @@ petalogix_ml605_init(ram_addr_t ram_size,
     }
 
     serial_mm_init(UART16550_BASEADDR + 0x1000, 2, irq[5], 115200,
-                   serial_hds[0], 1, DEVICE_LITTLE_ENDIAN);
+                   serial_hds[0], DEVICE_LITTLE_ENDIAN);
 
     /* 2 timers at irq 2 @ 100 Mhz.  */
     xilinx_timer_create(TIMER_BASEADDR, irq[2], 2, 100 * 1000000);
diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c
index 35584df..924aada 100644
--- a/hw/ppc405_uc.c
+++ b/hw/ppc405_uc.c
@@ -2150,11 +2150,11 @@ CPUState *ppc405cr_init (MemoryRegion ram_memories[4],
     /* Serial ports */
     if (serial_hds[0] != NULL) {
         serial_mm_init(0xef600300, 0, pic[0], PPC_SERIAL_MM_BAUDBASE,
-                       serial_hds[0], 1, DEVICE_BIG_ENDIAN);
+                       serial_hds[0], DEVICE_BIG_ENDIAN);
     }
     if (serial_hds[1] != NULL) {
         serial_mm_init(0xef600400, 0, pic[1], PPC_SERIAL_MM_BAUDBASE,
-                       serial_hds[1], 1, DEVICE_BIG_ENDIAN);
+                       serial_hds[1], DEVICE_BIG_ENDIAN);
     }
     /* IIC controller */
     ppc405_i2c_init(0xef600500, pic[2]);
@@ -2505,11 +2505,11 @@ CPUState *ppc405ep_init (MemoryRegion ram_memories[2],
     /* Serial ports */
     if (serial_hds[0] != NULL) {
         serial_mm_init(0xef600300, 0, pic[0], PPC_SERIAL_MM_BAUDBASE,
-                       serial_hds[0], 1, DEVICE_BIG_ENDIAN);
+                       serial_hds[0], DEVICE_BIG_ENDIAN);
     }
     if (serial_hds[1] != NULL) {
         serial_mm_init(0xef600400, 0, pic[1], PPC_SERIAL_MM_BAUDBASE,
-                       serial_hds[1], 1, DEVICE_BIG_ENDIAN);
+                       serial_hds[1], DEVICE_BIG_ENDIAN);
     }
     /* OCM */
     ppc405_ocm_init(env);
diff --git a/hw/ppc440.c b/hw/ppc440.c
index 9dd9215..0cd7bca 100644
--- a/hw/ppc440.c
+++ b/hw/ppc440.c
@@ -93,11 +93,11 @@ CPUState *ppc440ep_init(ram_addr_t *ram_size, PCIBus **pcip,
 
     if (serial_hds[0] != NULL) {
         serial_mm_init(0xef600300, 0, pic[0], PPC_SERIAL_MM_BAUDBASE,
-                       serial_hds[0], 1, DEVICE_BIG_ENDIAN);
+                       serial_hds[0], DEVICE_BIG_ENDIAN);
     }
     if (serial_hds[1] != NULL) {
         serial_mm_init(0xef600400, 0, pic[1], PPC_SERIAL_MM_BAUDBASE,
-                       serial_hds[1], 1, DEVICE_BIG_ENDIAN);
+                       serial_hds[1], DEVICE_BIG_ENDIAN);
     }
 
     return env;
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index c3583f9..fc46991 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -276,13 +276,13 @@ static void mpc8544ds_init(ram_addr_t ram_size,
     if (serial_hds[0]) {
         serial_mm_init(MPC8544_SERIAL0_REGS_BASE,
                        0, mpic[12+26], 399193,
-                       serial_hds[0], 1, DEVICE_BIG_ENDIAN);
+                       serial_hds[0], DEVICE_BIG_ENDIAN);
     }
 
     if (serial_hds[1]) {
         serial_mm_init(MPC8544_SERIAL1_REGS_BASE,
                        0, mpic[12+26], 399193,
-                       serial_hds[0], 1, DEVICE_BIG_ENDIAN);
+                       serial_hds[0], DEVICE_BIG_ENDIAN);
     }
 
     /* General Utility device */
diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c
index 55b5d8c..60f4c34 100644
--- a/hw/pxa2xx.c
+++ b/hw/pxa2xx.c
@@ -2117,7 +2117,7 @@ PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision)
         if (serial_hds[i]) {
             serial_mm_init(pxa270_serial[i].io_base, 2,
                            qdev_get_gpio_in(s->pic, pxa270_serial[i].irqn),
-                           14857000 / 16, serial_hds[i], 1,
+                           14857000 / 16, serial_hds[i],
                            DEVICE_NATIVE_ENDIAN);
         } else {
             break;
@@ -2249,7 +2249,7 @@ PXA2xxState *pxa255_init(unsigned int sdram_size)
         if (serial_hds[i]) {
             serial_mm_init(pxa255_serial[i].io_base, 2,
                            qdev_get_gpio_in(s->pic, pxa255_serial[i].irqn),
-                           14745600 / 16, serial_hds[i], 1,
+                           14745600 / 16, serial_hds[i],
                            DEVICE_NATIVE_ENDIAN);
         } else {
             break;
diff --git a/hw/serial.c b/hw/serial.c
index a533c04..0fafc1d 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -857,8 +857,7 @@ static const MemoryRegionOps serial_mm_ops[3] = {
 
 SerialState *serial_mm_init (target_phys_addr_t base, int it_shift,
                              qemu_irq irq, int baudbase,
-                             CharDriverState *chr, int ioregister,
-                             enum device_endian end)
+                             CharDriverState *chr, enum device_endian end)
 {
     SerialState *s;
 
@@ -874,9 +873,8 @@ SerialState *serial_mm_init (target_phys_addr_t base, int it_shift,
 
     memory_region_init_io(&s->io, &serial_mm_ops[end], s,
                           "serial", 8 << it_shift);
-    if (ioregister) {
-        memory_region_add_subregion(get_system_memory(), base, &s->io);
-    }
+    memory_region_add_subregion(get_system_memory(), base, &s->io);
+
     serial_update_msl(s);
     return s;
 }
diff --git a/hw/sm501.c b/hw/sm501.c
index 26e2dfe..fddf21a 100644
--- a/hw/sm501.c
+++ b/hw/sm501.c
@@ -1442,7 +1442,7 @@ void sm501_init(uint32_t base, uint32_t local_mem_bytes, qemu_irq irq,
     if (chr) {
         serial_mm_init(base + MMIO_BASE_OFFSET + SM501_UART0, 2,
                        NULL, /* TODO : chain irq to IRL */
-                       115200, chr, 1, DEVICE_NATIVE_ENDIAN);
+                       115200, chr, DEVICE_NATIVE_ENDIAN);
     }
 
     /* create qemu graphic console */
diff --git a/hw/sun4u.c b/hw/sun4u.c
index b6d8171..60e1e9d 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -771,7 +771,7 @@ static void sun4uv_init(ram_addr_t RAM_size,
     i = 0;
     if (hwdef->console_serial_base) {
         serial_mm_init(hwdef->console_serial_base, 0, NULL, 115200,
-                       serial_hds[i], 1, DEVICE_BIG_ENDIAN);
+                       serial_hds[i], DEVICE_BIG_ENDIAN);
         i++;
     }
     for(; i < MAX_SERIAL_PORTS; i++) {
diff --git a/hw/virtex_ml507.c b/hw/virtex_ml507.c
index a4721e3..8c52a06 100644
--- a/hw/virtex_ml507.c
+++ b/hw/virtex_ml507.c
@@ -227,7 +227,7 @@ static void virtex_init(ram_addr_t ram_size,
     }
 
     serial_mm_init(0x83e01003ULL, 2, irq[9], 115200, serial_hds[0],
-                   1, DEVICE_LITTLE_ENDIAN);
+                   DEVICE_LITTLE_ENDIAN);
 
     /* 2 timers at irq 2 @ 62 Mhz.  */
     xilinx_timer_create(0x83c00000, irq[3], 2, 62 * 1000000);
commit fb50cfe44dbff7be1489c5ecf5428aabd401f2e0
Author: Richard Henderson <rth at twiddle.net>
Date:   Thu Aug 11 16:07:14 2011 -0700

    serial: Use enum device_endian in serial_mm_init parameter
    
    The use of DEVICE_NATIVE_ENDIAN cleans up lots of ifdefs in
    many of the callers.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c
index ea07d32..9a87a8e 100644
--- a/hw/mips_jazz.c
+++ b/hw/mips_jazz.c
@@ -264,18 +264,12 @@ static void mips_jazz_init(MemoryRegion *address_space,
 
     /* Serial ports */
     if (serial_hds[0]) {
-#ifdef TARGET_WORDS_BIGENDIAN
-        serial_mm_init(0x80006000, 0, rc4030[8], 8000000/16, serial_hds[0], 1, 1);
-#else
-        serial_mm_init(0x80006000, 0, rc4030[8], 8000000/16, serial_hds[0], 1, 0);
-#endif
+        serial_mm_init(0x80006000, 0, rc4030[8], 8000000/16, serial_hds[0],
+                       1, DEVICE_NATIVE_ENDIAN);
     }
     if (serial_hds[1]) {
-#ifdef TARGET_WORDS_BIGENDIAN
-        serial_mm_init(0x80007000, 0, rc4030[9], 8000000/16, serial_hds[1], 1, 1);
-#else
-        serial_mm_init(0x80007000, 0, rc4030[9], 8000000/16, serial_hds[1], 1, 0);
-#endif
+        serial_mm_init(0x80007000, 0, rc4030[9], 8000000/16, serial_hds[1],
+                       1, DEVICE_NATIVE_ENDIAN);
     }
 
     /* Parallel port */
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index 1ec1228..0b16914 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -446,11 +446,8 @@ static MaltaFPGAState *malta_fpga_init(MemoryRegion *address_space,
 
     s->display = qemu_chr_new("fpga", "vc:320x200", malta_fpga_led_init);
 
-#ifdef TARGET_WORDS_BIGENDIAN
-    s->uart = serial_mm_init(base + 0x900, 3, uart_irq, 230400, uart_chr, 1, 1);
-#else
-    s->uart = serial_mm_init(base + 0x900, 3, uart_irq, 230400, uart_chr, 1, 0);
-#endif
+    s->uart = serial_mm_init(base + 0x900, 3, uart_irq, 230400, uart_chr,
+                             1, DEVICE_NATIVE_ENDIAN);
 
     malta_fpga_reset(s);
     qemu_register_reset(malta_fpga_reset, s);
diff --git a/hw/musicpal.c b/hw/musicpal.c
index 9b1f380..e79b07e 100644
--- a/hw/musicpal.c
+++ b/hw/musicpal.c
@@ -1486,22 +1486,12 @@ static void musicpal_init(ram_addr_t ram_size,
                           pic[MP_TIMER4_IRQ], NULL);
 
     if (serial_hds[0]) {
-#ifdef TARGET_WORDS_BIGENDIAN
-        serial_mm_init(MP_UART1_BASE, 2, pic[MP_UART1_IRQ], 1825000,
-                       serial_hds[0], 1, 1);
-#else
         serial_mm_init(MP_UART1_BASE, 2, pic[MP_UART1_IRQ], 1825000,
-                       serial_hds[0], 1, 0);
-#endif
+                       serial_hds[0], 1, DEVICE_NATIVE_ENDIAN);
     }
     if (serial_hds[1]) {
-#ifdef TARGET_WORDS_BIGENDIAN
-        serial_mm_init(MP_UART2_BASE, 2, pic[MP_UART2_IRQ], 1825000,
-                       serial_hds[1], 1, 1);
-#else
         serial_mm_init(MP_UART2_BASE, 2, pic[MP_UART2_IRQ], 1825000,
-                       serial_hds[1], 1, 0);
-#endif
+                       serial_hds[1], 1, DEVICE_NATIVE_ENDIAN);
     }
 
     /* Register flash */
diff --git a/hw/omap_uart.c b/hw/omap_uart.c
index 191a0c2..66696ab 100644
--- a/hw/omap_uart.c
+++ b/hw/omap_uart.c
@@ -60,15 +60,9 @@ struct omap_uart_s *omap_uart_init(target_phys_addr_t base,
     s->base = base;
     s->fclk = fclk;
     s->irq = irq;
-#ifdef TARGET_WORDS_BIGENDIAN
     s->serial = serial_mm_init(base, 2, irq, omap_clk_getrate(fclk)/16,
                                chr ?: qemu_chr_new(label, "null", NULL), 1,
-                               1);
-#else
-    s->serial = serial_mm_init(base, 2, irq, omap_clk_getrate(fclk)/16,
-                               chr ?: qemu_chr_new(label, "null", NULL), 1,
-                               0);
-#endif
+                               DEVICE_NATIVE_ENDIAN);
     return s;
 }
 
@@ -182,15 +176,8 @@ struct omap_uart_s *omap2_uart_init(struct omap_target_agent_s *ta,
 void omap_uart_attach(struct omap_uart_s *s, CharDriverState *chr)
 {
     /* TODO: Should reuse or destroy current s->serial */
-#ifdef TARGET_WORDS_BIGENDIAN
-    s->serial = serial_mm_init(s->base, 2, s->irq,
-                               omap_clk_getrate(s->fclk) / 16,
-                               chr ?: qemu_chr_new("null", "null", NULL), 1,
-                               1);
-#else
     s->serial = serial_mm_init(s->base, 2, s->irq,
                                omap_clk_getrate(s->fclk) / 16,
                                chr ?: qemu_chr_new("null", "null", NULL), 1,
-                               0);
-#endif
+                               DEVICE_NATIVE_ENDIAN);
 }
diff --git a/hw/pc.h b/hw/pc.h
index 7e6ddba..d70b81a 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -18,7 +18,7 @@ SerialState *serial_init(int base, qemu_irq irq, int baudbase,
 SerialState *serial_mm_init (target_phys_addr_t base, int it_shift,
                              qemu_irq irq, int baudbase,
                              CharDriverState *chr, int ioregister,
-                             int be);
+                             enum device_endian);
 static inline bool serial_isa_init(int index, CharDriverState *chr)
 {
     ISADevice *dev;
diff --git a/hw/petalogix_ml605_mmu.c b/hw/petalogix_ml605_mmu.c
index 38db521..97ff33d 100644
--- a/hw/petalogix_ml605_mmu.c
+++ b/hw/petalogix_ml605_mmu.c
@@ -185,7 +185,7 @@ petalogix_ml605_init(ram_addr_t ram_size,
     }
 
     serial_mm_init(UART16550_BASEADDR + 0x1000, 2, irq[5], 115200,
-                   serial_hds[0], 1, 0);
+                   serial_hds[0], 1, DEVICE_LITTLE_ENDIAN);
 
     /* 2 timers at irq 2 @ 100 Mhz.  */
     xilinx_timer_create(TIMER_BASEADDR, irq[2], 2, 100 * 1000000);
diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c
index 9d5d2af..35584df 100644
--- a/hw/ppc405_uc.c
+++ b/hw/ppc405_uc.c
@@ -2150,11 +2150,11 @@ CPUState *ppc405cr_init (MemoryRegion ram_memories[4],
     /* Serial ports */
     if (serial_hds[0] != NULL) {
         serial_mm_init(0xef600300, 0, pic[0], PPC_SERIAL_MM_BAUDBASE,
-                       serial_hds[0], 1, 1);
+                       serial_hds[0], 1, DEVICE_BIG_ENDIAN);
     }
     if (serial_hds[1] != NULL) {
         serial_mm_init(0xef600400, 0, pic[1], PPC_SERIAL_MM_BAUDBASE,
-                       serial_hds[1], 1, 1);
+                       serial_hds[1], 1, DEVICE_BIG_ENDIAN);
     }
     /* IIC controller */
     ppc405_i2c_init(0xef600500, pic[2]);
@@ -2505,11 +2505,11 @@ CPUState *ppc405ep_init (MemoryRegion ram_memories[2],
     /* Serial ports */
     if (serial_hds[0] != NULL) {
         serial_mm_init(0xef600300, 0, pic[0], PPC_SERIAL_MM_BAUDBASE,
-                       serial_hds[0], 1, 1);
+                       serial_hds[0], 1, DEVICE_BIG_ENDIAN);
     }
     if (serial_hds[1] != NULL) {
         serial_mm_init(0xef600400, 0, pic[1], PPC_SERIAL_MM_BAUDBASE,
-                       serial_hds[1], 1, 1);
+                       serial_hds[1], 1, DEVICE_BIG_ENDIAN);
     }
     /* OCM */
     ppc405_ocm_init(env);
diff --git a/hw/ppc440.c b/hw/ppc440.c
index 5885ff0..9dd9215 100644
--- a/hw/ppc440.c
+++ b/hw/ppc440.c
@@ -93,11 +93,11 @@ CPUState *ppc440ep_init(ram_addr_t *ram_size, PCIBus **pcip,
 
     if (serial_hds[0] != NULL) {
         serial_mm_init(0xef600300, 0, pic[0], PPC_SERIAL_MM_BAUDBASE,
-                       serial_hds[0], 1, 1);
+                       serial_hds[0], 1, DEVICE_BIG_ENDIAN);
     }
     if (serial_hds[1] != NULL) {
         serial_mm_init(0xef600400, 0, pic[1], PPC_SERIAL_MM_BAUDBASE,
-                       serial_hds[1], 1, 1);
+                       serial_hds[1], 1, DEVICE_BIG_ENDIAN);
     }
 
     return env;
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 1274a3e..c3583f9 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -276,13 +276,13 @@ static void mpc8544ds_init(ram_addr_t ram_size,
     if (serial_hds[0]) {
         serial_mm_init(MPC8544_SERIAL0_REGS_BASE,
                        0, mpic[12+26], 399193,
-                       serial_hds[0], 1, 1);
+                       serial_hds[0], 1, DEVICE_BIG_ENDIAN);
     }
 
     if (serial_hds[1]) {
         serial_mm_init(MPC8544_SERIAL1_REGS_BASE,
                        0, mpic[12+26], 399193,
-                       serial_hds[0], 1, 1);
+                       serial_hds[0], 1, DEVICE_BIG_ENDIAN);
     }
 
     /* General Utility device */
diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c
index 2aa8760..55b5d8c 100644
--- a/hw/pxa2xx.c
+++ b/hw/pxa2xx.c
@@ -2113,19 +2113,16 @@ PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision)
                     qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_MMCI),
                     qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_MMCI));
 
-    for (i = 0; pxa270_serial[i].io_base; i ++)
-        if (serial_hds[i])
-#ifdef TARGET_WORDS_BIGENDIAN
-            serial_mm_init(pxa270_serial[i].io_base, 2,
-                            qdev_get_gpio_in(s->pic, pxa270_serial[i].irqn),
-                            14857000 / 16, serial_hds[i], 1, 1);
-#else
+    for (i = 0; pxa270_serial[i].io_base; i++) {
+        if (serial_hds[i]) {
             serial_mm_init(pxa270_serial[i].io_base, 2,
-                            qdev_get_gpio_in(s->pic, pxa270_serial[i].irqn),
-                            14857000 / 16, serial_hds[i], 1, 0);
-#endif
-        else
+                           qdev_get_gpio_in(s->pic, pxa270_serial[i].irqn),
+                           14857000 / 16, serial_hds[i], 1,
+                           DEVICE_NATIVE_ENDIAN);
+        } else {
             break;
+        }
+    }
     if (serial_hds[i])
         s->fir = pxa2xx_fir_init(0x40800000,
                         qdev_get_gpio_in(s->pic, PXA2XX_PIC_ICP),
@@ -2248,20 +2245,16 @@ PXA2xxState *pxa255_init(unsigned int sdram_size)
                     qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_MMCI),
                     qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_MMCI));
 
-    for (i = 0; pxa255_serial[i].io_base; i ++)
+    for (i = 0; pxa255_serial[i].io_base; i++) {
         if (serial_hds[i]) {
-#ifdef TARGET_WORDS_BIGENDIAN
-            serial_mm_init(pxa255_serial[i].io_base, 2,
-                            qdev_get_gpio_in(s->pic, pxa255_serial[i].irqn),
-                            14745600 / 16, serial_hds[i], 1, 1);
-#else
             serial_mm_init(pxa255_serial[i].io_base, 2,
-                            qdev_get_gpio_in(s->pic, pxa255_serial[i].irqn),
-                            14745600 / 16, serial_hds[i], 1, 0);
-#endif
+                           qdev_get_gpio_in(s->pic, pxa255_serial[i].irqn),
+                           14745600 / 16, serial_hds[i], 1,
+                           DEVICE_NATIVE_ENDIAN);
         } else {
             break;
         }
+    }
     if (serial_hds[i])
         s->fir = pxa2xx_fir_init(0x40800000,
                         qdev_get_gpio_in(s->pic, PXA2XX_PIC_ICP),
diff --git a/hw/serial.c b/hw/serial.c
index 310bfde..a533c04 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -858,10 +858,9 @@ static const MemoryRegionOps serial_mm_ops[3] = {
 SerialState *serial_mm_init (target_phys_addr_t base, int it_shift,
                              qemu_irq irq, int baudbase,
                              CharDriverState *chr, int ioregister,
-                             int be)
+                             enum device_endian end)
 {
     SerialState *s;
-    enum device_endian end;
 
     s = g_malloc0(sizeof(SerialState));
 
@@ -873,7 +872,6 @@ SerialState *serial_mm_init (target_phys_addr_t base, int it_shift,
     serial_init_core(s);
     vmstate_register(NULL, base, &vmstate_serial, s);
 
-    end = (be ? DEVICE_BIG_ENDIAN : DEVICE_LITTLE_ENDIAN);
     memory_region_init_io(&s->io, &serial_mm_ops[end], s,
                           "serial", 8 << it_shift);
     if (ioregister) {
diff --git a/hw/sm501.c b/hw/sm501.c
index 1ed0a7e..26e2dfe 100644
--- a/hw/sm501.c
+++ b/hw/sm501.c
@@ -1440,15 +1440,9 @@ void sm501_init(uint32_t base, uint32_t local_mem_bytes, qemu_irq irq,
 
     /* bridge to serial emulation module */
     if (chr) {
-#ifdef TARGET_WORDS_BIGENDIAN
         serial_mm_init(base + MMIO_BASE_OFFSET + SM501_UART0, 2,
                        NULL, /* TODO : chain irq to IRL */
-                       115200, chr, 1, 1);
-#else
-        serial_mm_init(base + MMIO_BASE_OFFSET + SM501_UART0, 2,
-                       NULL, /* TODO : chain irq to IRL */
-                       115200, chr, 1, 0);
-#endif
+                       115200, chr, 1, DEVICE_NATIVE_ENDIAN);
     }
 
     /* create qemu graphic console */
diff --git a/hw/sun4u.c b/hw/sun4u.c
index fbef350..b6d8171 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -771,7 +771,7 @@ static void sun4uv_init(ram_addr_t RAM_size,
     i = 0;
     if (hwdef->console_serial_base) {
         serial_mm_init(hwdef->console_serial_base, 0, NULL, 115200,
-                       serial_hds[i], 1, 1);
+                       serial_hds[i], 1, DEVICE_BIG_ENDIAN);
         i++;
     }
     for(; i < MAX_SERIAL_PORTS; i++) {
diff --git a/hw/virtex_ml507.c b/hw/virtex_ml507.c
index 7459b0b..a4721e3 100644
--- a/hw/virtex_ml507.c
+++ b/hw/virtex_ml507.c
@@ -226,7 +226,8 @@ static void virtex_init(ram_addr_t ram_size,
         irq[i] = qdev_get_gpio_in(dev, i);
     }
 
-    serial_mm_init(0x83e01003ULL, 2, irq[9], 115200, serial_hds[0], 1, 0);
+    serial_mm_init(0x83e01003ULL, 2, irq[9], 115200, serial_hds[0],
+                   1, DEVICE_LITTLE_ENDIAN);
 
     /* 2 timers at irq 2 @ 62 Mhz.  */
     xilinx_timer_create(0x83c00000, irq[3], 2, 62 * 1000000);
commit 8e8ffc44e8d0a4a41e4b0bee8b1c2a3e1a11cfc4
Author: Richard Henderson <rth at twiddle.net>
Date:   Thu Aug 11 16:18:59 2011 -0700

    serial: Convert serial_mm_init to MemoryRegion
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/serial.c b/hw/serial.c
index 2e6d212..310bfde 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -28,6 +28,7 @@
 #include "pc.h"
 #include "qemu-timer.h"
 #include "sysemu.h"
+#include "exec-memory.h"
 
 //#define DEBUG_SERIAL
 
@@ -153,11 +154,11 @@ struct SerialState {
     int poll_msl;
 
     struct QEMUTimer *modem_status_poll;
+    MemoryRegion io;
 };
 
 typedef struct ISASerialState {
     ISADevice dev;
-    MemoryRegion io;
     uint32_t index;
     uint32_t iobase;
     uint32_t isairq;
@@ -786,8 +787,8 @@ static int serial_isa_initfn(ISADevice *dev)
     serial_init_core(s);
     qdev_set_legacy_instance_id(&dev->qdev, isa->iobase, 3);
 
-    memory_region_init_io(&isa->io, &serial_io_ops, s, "serial", 8);
-    isa_register_ioport(dev, &isa->io, isa->iobase);
+    memory_region_init_io(&s->io, &serial_io_ops, s, "serial", 8);
+    isa_register_ioport(dev, &s->io, isa->iobase);
     return 0;
 }
 
@@ -821,115 +822,37 @@ SerialState *serial_init(int base, qemu_irq irq, int baudbase,
 }
 
 /* Memory mapped interface */
-static uint32_t serial_mm_readb(void *opaque, target_phys_addr_t addr)
-{
-    SerialState *s = opaque;
-
-    return serial_ioport_read(s, addr >> s->it_shift) & 0xFF;
-}
-
-static void serial_mm_writeb(void *opaque, target_phys_addr_t addr,
-                             uint32_t value)
-{
-    SerialState *s = opaque;
-
-    serial_ioport_write(s, addr >> s->it_shift, value & 0xFF);
-}
-
-static uint32_t serial_mm_readw_be(void *opaque, target_phys_addr_t addr)
-{
-    SerialState *s = opaque;
-    uint32_t val;
-
-    val = serial_ioport_read(s, addr >> s->it_shift) & 0xFFFF;
-    val = bswap16(val);
-    return val;
-}
-
-static uint32_t serial_mm_readw_le(void *opaque, target_phys_addr_t addr)
-{
-    SerialState *s = opaque;
-    uint32_t val;
-
-    val = serial_ioport_read(s, addr >> s->it_shift) & 0xFFFF;
-    return val;
-}
-
-static void serial_mm_writew_be(void *opaque, target_phys_addr_t addr,
-                                uint32_t value)
-{
-    SerialState *s = opaque;
-
-    value = bswap16(value);
-    serial_ioport_write(s, addr >> s->it_shift, value & 0xFFFF);
-}
-
-static void serial_mm_writew_le(void *opaque, target_phys_addr_t addr,
-                                uint32_t value)
-{
-    SerialState *s = opaque;
-
-    serial_ioport_write(s, addr >> s->it_shift, value & 0xFFFF);
-}
-
-static uint32_t serial_mm_readl_be(void *opaque, target_phys_addr_t addr)
-{
-    SerialState *s = opaque;
-    uint32_t val;
-
-    val = serial_ioport_read(s, addr >> s->it_shift);
-    val = bswap32(val);
-    return val;
-}
-
-static uint32_t serial_mm_readl_le(void *opaque, target_phys_addr_t addr)
-{
-    SerialState *s = opaque;
-    uint32_t val;
-
-    val = serial_ioport_read(s, addr >> s->it_shift);
-    return val;
-}
-
-static void serial_mm_writel_be(void *opaque, target_phys_addr_t addr,
-                                uint32_t value)
+static uint64_t serial_mm_read(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
 {
     SerialState *s = opaque;
-
-    value = bswap32(value);
-    serial_ioport_write(s, addr >> s->it_shift, value);
+    return serial_ioport_read(s, addr >> s->it_shift);
 }
 
-static void serial_mm_writel_le(void *opaque, target_phys_addr_t addr,
-                                uint32_t value)
+static void serial_mm_write(void *opaque, target_phys_addr_t addr,
+                            uint64_t value, unsigned size)
 {
     SerialState *s = opaque;
-
+    value &= ~0u >> (32 - (size * 8));
     serial_ioport_write(s, addr >> s->it_shift, value);
 }
 
-static CPUReadMemoryFunc * const serial_mm_read_be[] = {
-    &serial_mm_readb,
-    &serial_mm_readw_be,
-    &serial_mm_readl_be,
-};
-
-static CPUWriteMemoryFunc * const serial_mm_write_be[] = {
-    &serial_mm_writeb,
-    &serial_mm_writew_be,
-    &serial_mm_writel_be,
-};
-
-static CPUReadMemoryFunc * const serial_mm_read_le[] = {
-    &serial_mm_readb,
-    &serial_mm_readw_le,
-    &serial_mm_readl_le,
-};
-
-static CPUWriteMemoryFunc * const serial_mm_write_le[] = {
-    &serial_mm_writeb,
-    &serial_mm_writew_le,
-    &serial_mm_writel_le,
+static const MemoryRegionOps serial_mm_ops[3] = {
+    [DEVICE_NATIVE_ENDIAN] = {
+        .read = serial_mm_read,
+        .write = serial_mm_write,
+        .endianness = DEVICE_NATIVE_ENDIAN,
+    },
+    [DEVICE_LITTLE_ENDIAN] = {
+        .read = serial_mm_read,
+        .write = serial_mm_write,
+        .endianness = DEVICE_LITTLE_ENDIAN,
+    },
+    [DEVICE_BIG_ENDIAN] = {
+        .read = serial_mm_read,
+        .write = serial_mm_write,
+        .endianness = DEVICE_BIG_ENDIAN,
+    },
 };
 
 SerialState *serial_mm_init (target_phys_addr_t base, int it_shift,
@@ -938,7 +861,7 @@ SerialState *serial_mm_init (target_phys_addr_t base, int it_shift,
                              int be)
 {
     SerialState *s;
-    int s_io_memory;
+    enum device_endian end;
 
     s = g_malloc0(sizeof(SerialState));
 
@@ -950,17 +873,11 @@ SerialState *serial_mm_init (target_phys_addr_t base, int it_shift,
     serial_init_core(s);
     vmstate_register(NULL, base, &vmstate_serial, s);
 
+    end = (be ? DEVICE_BIG_ENDIAN : DEVICE_LITTLE_ENDIAN);
+    memory_region_init_io(&s->io, &serial_mm_ops[end], s,
+                          "serial", 8 << it_shift);
     if (ioregister) {
-        if (be) {
-            s_io_memory = cpu_register_io_memory(serial_mm_read_be,
-                                                 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,
-                                                 DEVICE_NATIVE_ENDIAN);
-        }
-        cpu_register_physical_memory(base, 8 << it_shift, s_io_memory);
+        memory_region_add_subregion(get_system_memory(), base, &s->io);
     }
     serial_update_msl(s);
     return s;
commit 06dccb82df3d01240671d2fde71a078f6006424e
Author: Edgar E. Iglesias <edgar.iglesias at gmail.com>
Date:   Thu Aug 11 13:47:48 2011 +0200

    etrax-eth: Convert to MemoryRegion
    
    Signed-off-by: Edgar E. Iglesias <edgar.iglesias at gmail.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c
index 48de6dc..246a279 100644
--- a/hw/etraxfs_eth.c
+++ b/hw/etraxfs_eth.c
@@ -320,6 +320,7 @@ static void mdio_cycle(struct qemu_mdio *bus)
 struct fs_eth
 {
 	SysBusDevice busdev;
+	MemoryRegion mmio;
 	NICState *nic;
 	NICConf conf;
 	int ethregs;
@@ -373,7 +374,8 @@ static void eth_validate_duplex(struct fs_eth *eth)
 	}
 }
 
-static uint32_t eth_readl (void *opaque, target_phys_addr_t addr)
+static uint64_t
+eth_read(void *opaque, target_phys_addr_t addr, unsigned int size)
 {
 	struct fs_eth *eth = opaque;
 	uint32_t r = 0;
@@ -417,9 +419,11 @@ static void eth_update_ma(struct fs_eth *eth, int ma)
 }
 
 static void
-eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+eth_write(void *opaque, target_phys_addr_t addr,
+          uint64_t val64, unsigned int size)
 {
 	struct fs_eth *eth = opaque;
+	uint32_t value = val64;
 
 	addr >>= 2;
 	switch (addr)
@@ -553,14 +557,14 @@ static void eth_set_link(VLANClientState *nc)
 	eth->phy.link = !nc->link_down;
 }
 
-static CPUReadMemoryFunc * const eth_read[] = {
-	NULL, NULL,
-	&eth_readl,
-};
-
-static CPUWriteMemoryFunc * const eth_write[] = {
-	NULL, NULL,
-	&eth_writel,
+static const MemoryRegionOps eth_ops = {
+	.read = eth_read,
+	.write = eth_write,
+	.endianness = DEVICE_LITTLE_ENDIAN,
+	.valid = {
+		.min_access_size = 4,
+		.max_access_size = 4
+	}
 };
 
 static void eth_cleanup(VLANClientState *nc)
@@ -589,7 +593,6 @@ static NetClientInfo net_etraxfs_info = {
 static int fs_eth_init(SysBusDevice *dev)
 {
 	struct fs_eth *s = FROM_SYSBUS(typeof(*s), dev);
-	int eth_regs;
 
 	if (!s->dma_out || !s->dma_in) {
 		hw_error("Unconnected ETRAX-FS Ethernet MAC.\n");
@@ -600,9 +603,8 @@ static int fs_eth_init(SysBusDevice *dev)
 	s->dma_in->client.opaque = s;
 	s->dma_in->client.pull = NULL;
 
-	eth_regs = cpu_register_io_memory(eth_read, eth_write, s,
-					  DEVICE_LITTLE_ENDIAN);
-	sysbus_init_mmio(dev, 0x5c, eth_regs);
+	memory_region_init_io(&s->mmio, &eth_ops, s, "etraxfs-eth", 0x5c);
+	sysbus_init_mmio_region(dev, &s->mmio);
 
 	qemu_macaddr_default_if_unset(&s->conf.macaddr);
 	s->nic = qemu_new_nic(&net_etraxfs_info, &s->conf,
commit 9dcb06ce1d8d55ddb579f53ebb463a2ed045e2f1
Author: Edgar E. Iglesias <edgar.iglesias at gmail.com>
Date:   Thu Aug 11 13:47:47 2011 +0200

    etrax-dma: Convert to MemoryRegion
    
    Signed-off-by: Edgar E. Iglesias <edgar.iglesias at gmail.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/etraxfs_dma.c b/hw/etraxfs_dma.c
index d3082ac..94bfb70 100644
--- a/hw/etraxfs_dma.c
+++ b/hw/etraxfs_dma.c
@@ -24,6 +24,7 @@
 #include <stdio.h>
 #include <sys/time.h>
 #include "hw.h"
+#include "exec-memory.h"
 #include "qemu-common.h"
 #include "sysemu.h"
 
@@ -185,7 +186,7 @@ struct fs_dma_channel
 
 struct fs_dma_ctrl
 {
-	int map;
+	MemoryRegion mmio;
 	int nr_channels;
 	struct fs_dma_channel *channels;
 
@@ -562,13 +563,17 @@ static uint32_t dma_rinvalid (void *opaque, target_phys_addr_t addr)
         return 0;
 }
 
-static uint32_t
-dma_readl (void *opaque, target_phys_addr_t addr)
+static uint64_t
+dma_read(void *opaque, target_phys_addr_t addr, unsigned int size)
 {
         struct fs_dma_ctrl *ctrl = opaque;
 	int c;
 	uint32_t r = 0;
 
+	if (size != 4) {
+		dma_rinvalid(opaque, addr);
+	}
+
 	/* Make addr relative to this channel and bounded to nr regs.  */
 	c = fs_channel(addr);
 	addr &= 0xff;
@@ -608,11 +613,17 @@ dma_update_state(struct fs_dma_ctrl *ctrl, int c)
 }
 
 static void
-dma_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+dma_write(void *opaque, target_phys_addr_t addr,
+	  uint64_t val64, unsigned int size)
 {
         struct fs_dma_ctrl *ctrl = opaque;
+	uint32_t value = val64;
 	int c;
 
+	if (size != 4) {
+		dma_winvalid(opaque, addr, value);
+	}
+
         /* Make addr relative to this channel and bounded to nr regs.  */
 	c = fs_channel(addr);
         addr &= 0xff;
@@ -668,16 +679,14 @@ dma_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
         }
 }
 
-static CPUReadMemoryFunc * const dma_read[] = {
-	&dma_rinvalid,
-	&dma_rinvalid,
-	&dma_readl,
-};
-
-static CPUWriteMemoryFunc * const dma_write[] = {
-	&dma_winvalid,
-	&dma_winvalid,
-	&dma_writel,
+static const MemoryRegionOps dma_ops = {
+	.read = dma_read,
+	.write = dma_write,
+	.endianness = DEVICE_NATIVE_ENDIAN,
+	.valid = {
+		.min_access_size = 1,
+		.max_access_size = 4
+	}
 };
 
 static int etraxfs_dmac_run(void *opaque)
@@ -750,7 +759,9 @@ void *etraxfs_dmac_init(target_phys_addr_t base, int nr_channels)
 	ctrl->nr_channels = nr_channels;
 	ctrl->channels = g_malloc0(sizeof ctrl->channels[0] * nr_channels);
 
-	ctrl->map = cpu_register_io_memory(dma_read, dma_write, ctrl, DEVICE_NATIVE_ENDIAN);
-	cpu_register_physical_memory(base, nr_channels * 0x2000, ctrl->map);
+	memory_region_init_io(&ctrl->mmio, &dma_ops, ctrl, "etraxfs-dma",
+			      nr_channels * 0x2000);
+	memory_region_add_subregion(get_system_memory(), base, &ctrl->mmio);
+
 	return ctrl;
 }
commit b8e5da2c59f9f87722994de0a0a15c93703a9abe
Author: Edgar E. Iglesias <edgar.iglesias at gmail.com>
Date:   Thu Aug 11 13:47:46 2011 +0200

    etrax-timer: Convert to MemoryRegion
    
    Signed-off-by: Edgar E. Iglesias <edgar.iglesias at gmail.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/etraxfs_timer.c b/hw/etraxfs_timer.c
index b08e574..57dc739 100644
--- a/hw/etraxfs_timer.c
+++ b/hw/etraxfs_timer.c
@@ -43,6 +43,7 @@
 
 struct etrax_timer {
     SysBusDevice busdev;
+    MemoryRegion mmio;
     qemu_irq irq;
     qemu_irq nmi;
 
@@ -72,7 +73,8 @@ struct etrax_timer {
     uint32_t r_masked_intr;
 };
 
-static uint32_t timer_readl (void *opaque, target_phys_addr_t addr)
+static uint64_t
+timer_read(void *opaque, target_phys_addr_t addr, unsigned int size)
 {
     struct etrax_timer *t = opaque;
     uint32_t r = 0;
@@ -239,9 +241,11 @@ static inline void timer_watchdog_update(struct etrax_timer *t, uint32_t value)
 }
 
 static void
-timer_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+timer_write(void *opaque, target_phys_addr_t addr,
+            uint64_t val64, unsigned int size)
 {
     struct etrax_timer *t = opaque;
+    uint32_t value = val64;
 
     switch (addr)
     {
@@ -281,14 +285,14 @@ timer_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
     }
 }
 
-static CPUReadMemoryFunc * const timer_read[] = {
-    NULL, NULL,
-    &timer_readl,
-};
-
-static CPUWriteMemoryFunc * const timer_write[] = {
-    NULL, NULL,
-    &timer_writel,
+static const MemoryRegionOps timer_ops = {
+    .read = timer_read,
+    .write = timer_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
 };
 
 static void etraxfs_timer_reset(void *opaque)
@@ -307,7 +311,6 @@ static void etraxfs_timer_reset(void *opaque)
 static int etraxfs_timer_init(SysBusDevice *dev)
 {
     struct etrax_timer *t = FROM_SYSBUS(typeof (*t), dev);
-    int timer_regs;
 
     t->bh_t0 = qemu_bh_new(timer0_hit, t);
     t->bh_t1 = qemu_bh_new(timer1_hit, t);
@@ -319,10 +322,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,
-                                        DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, 0x5c, timer_regs);
-
+    memory_region_init_io(&t->mmio, &timer_ops, t, "etraxfs-timer", 0x5c);
+    sysbus_init_mmio_region(dev, &t->mmio);
     qemu_register_reset(etraxfs_timer_reset, t);
     return 0;
 }
commit dbfb57f3b1119b9d898a9a0c6b329c59edf7e576
Author: Edgar E. Iglesias <edgar.iglesias at gmail.com>
Date:   Thu Aug 11 13:47:45 2011 +0200

    etrax-ser: Convert to MemoryRegion
    
    Signed-off-by: Edgar E. Iglesias <edgar.iglesias at gmail.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/etraxfs_ser.c b/hw/etraxfs_ser.c
index 0036037..298b985 100644
--- a/hw/etraxfs_ser.c
+++ b/hw/etraxfs_ser.c
@@ -47,6 +47,7 @@
 struct etrax_serial
 {
     SysBusDevice busdev;
+    MemoryRegion mmio;
     CharDriverState *chr;
     qemu_irq irq;
 
@@ -73,7 +74,8 @@ static void ser_update_irq(struct etrax_serial *s)
     qemu_set_irq(s->irq, !!s->regs[R_MASKED_INTR]);
 }
 
-static uint32_t ser_readl (void *opaque, target_phys_addr_t addr)
+static uint64_t
+ser_read(void *opaque, target_phys_addr_t addr, unsigned int size)
 {
     struct etrax_serial *s = opaque;
     D(CPUState *env = s->env);
@@ -108,10 +110,12 @@ static uint32_t ser_readl (void *opaque, target_phys_addr_t addr)
 }
 
 static void
-ser_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+ser_write(void *opaque, target_phys_addr_t addr,
+          uint64_t val64, unsigned int size)
 {
     struct etrax_serial *s = opaque;
-    unsigned char ch = value;
+    uint32_t value = val64;
+    unsigned char ch = val64;
     D(CPUState *env = s->env);
 
     D(qemu_log("%s " TARGET_FMT_plx "=%x\n",  __func__, addr, value));
@@ -142,14 +146,14 @@ ser_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
     ser_update_irq(s);
 }
 
-static CPUReadMemoryFunc * const ser_read[] = {
-    NULL, NULL,
-    &ser_readl,
-};
-
-static CPUWriteMemoryFunc * const ser_write[] = {
-    NULL, NULL,
-    &ser_writel,
+static const MemoryRegionOps ser_ops = {
+    .read = ser_read,
+    .write = ser_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
 };
 
 static void serial_receive(void *opaque, const uint8_t *buf, int size)
@@ -207,12 +211,11 @@ static void etraxfs_ser_reset(DeviceState *d)
 static int etraxfs_ser_init(SysBusDevice *dev)
 {
     struct etrax_serial *s = FROM_SYSBUS(typeof (*s), dev);
-    int ser_regs;
 
     sysbus_init_irq(dev, &s->irq);
-    ser_regs = cpu_register_io_memory(ser_read, ser_write, s,
-                                      DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, R_MAX * 4, ser_regs);
+    memory_region_init_io(&s->mmio, &ser_ops, s, "etraxfs-serial", R_MAX * 4);
+    sysbus_init_mmio_region(dev, &s->mmio);
+
     s->chr = qdev_init_chardev(&dev->qdev);
     if (s->chr)
         qemu_chr_add_handlers(s->chr,
commit 5dd25f368cfe1940a7c5aab635574877887282f6
Author: Edgar E. Iglesias <edgar.iglesias at gmail.com>
Date:   Thu Aug 11 13:47:44 2011 +0200

    etrax-pic: Convert to MemoryRegion
    
    Signed-off-by: Edgar E. Iglesias <edgar.iglesias at gmail.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/etraxfs_pic.c b/hw/etraxfs_pic.c
index 4feffda..47a56d7 100644
--- a/hw/etraxfs_pic.c
+++ b/hw/etraxfs_pic.c
@@ -39,6 +39,7 @@
 struct etrax_pic
 {
     SysBusDevice busdev;
+    MemoryRegion mmio;
     void *interrupt_vector;
     qemu_irq parent_irq;
     qemu_irq parent_nmi;
@@ -77,7 +78,8 @@ static void pic_update(struct etrax_pic *fs)
     qemu_set_irq(fs->parent_irq, !!vector);
 }
 
-static uint32_t pic_readl (void *opaque, target_phys_addr_t addr)
+static uint64_t
+pic_read(void *opaque, target_phys_addr_t addr, unsigned int size)
 {
     struct etrax_pic *fs = opaque;
     uint32_t rval;
@@ -87,8 +89,8 @@ static uint32_t pic_readl (void *opaque, target_phys_addr_t addr)
     return rval;
 }
 
-static void
-pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+static void pic_write(void *opaque, target_phys_addr_t addr,
+                      uint64_t value, unsigned int size)
 {
     struct etrax_pic *fs = opaque;
     D(printf("%s addr=%x val=%x\n", __func__, addr, value));
@@ -99,14 +101,14 @@ pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
     }
 }
 
-static CPUReadMemoryFunc * const pic_read[] = {
-    NULL, NULL,
-    &pic_readl,
-};
-
-static CPUWriteMemoryFunc * const pic_write[] = {
-    NULL, NULL,
-    &pic_writel,
+static const MemoryRegionOps pic_ops = {
+    .read = pic_read,
+    .write = pic_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
 };
 
 static void nmi_handler(void *opaque, int irq, int level)
@@ -139,15 +141,13 @@ static void irq_handler(void *opaque, int irq, int level)
 static int etraxfs_pic_init(SysBusDevice *dev)
 {
     struct etrax_pic *s = FROM_SYSBUS(typeof (*s), dev);
-    int intr_vect_regs;
 
     qdev_init_gpio_in(&dev->qdev, irq_handler, 32);
     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,
-                                            DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, R_MAX * 4, intr_vect_regs);
+    memory_region_init_io(&s->mmio, &pic_ops, s, "etraxfs-pic", R_MAX * 4);
+    sysbus_init_mmio_region(dev, &s->mmio);
     return 0;
 }
 
commit 3917149d96cfa5f619de770af6059f37b6e1df77
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Wed Sep 21 18:13:16 2011 +0000

    Move GETPC from dyngen-exec.h to exec-all.h
    
    GETPC() can be used even from outside of helper code. Move the macro to
    a more accessible location. Avoid a compile warning from redefining it in exec.c.
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/dyngen-exec.h b/dyngen-exec.h
index 8beb7f3..fbde29e 100644
--- a/dyngen-exec.h
+++ b/dyngen-exec.h
@@ -57,16 +57,4 @@
 
 register CPUState *env asm(AREG0);
 
-/* The return address may point to the start of the next instruction.
-   Subtracting one gets us the call instruction itself.  */
-#if defined(__s390__) && !defined(__s390x__)
-# define GETPC() ((void*)(((unsigned long)__builtin_return_address(0) & 0x7fffffffUL) - 1))
-#elif defined(__arm__)
-/* Thumb return addresses have the low bit set, so we need to subtract two.
-   This is still safe in ARM mode because instructions are 4 bytes.  */
-# define GETPC() ((void *)((unsigned long)__builtin_return_address(0) - 2))
-#else
-# define GETPC() ((void *)((unsigned long)__builtin_return_address(0) - 1))
-#endif
-
 #endif /* !defined(__DYNGEN_EXEC_H__) */
diff --git a/exec-all.h b/exec-all.h
index b1dfe10..1120f84 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -267,6 +267,18 @@ extern spinlock_t tb_lock;
 
 extern int tb_invalidated_flag;
 
+/* The return address may point to the start of the next instruction.
+   Subtracting one gets us the call instruction itself.  */
+#if defined(__s390__) && !defined(__s390x__)
+# define GETPC() ((void*)(((unsigned long)__builtin_return_address(0) & 0x7fffffffUL) - 1))
+#elif defined(__arm__)
+/* Thumb return addresses have the low bit set, so we need to subtract two.
+   This is still safe in ARM mode because instructions are 4 bytes.  */
+# define GETPC() ((void *)((unsigned long)__builtin_return_address(0) - 2))
+#else
+# define GETPC() ((void *)((unsigned long)__builtin_return_address(0) - 1))
+#endif
+
 #if !defined(CONFIG_USER_ONLY)
 
 extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
diff --git a/exec.c b/exec.c
index 1e6f732..d0cbf15 100644
--- a/exec.c
+++ b/exec.c
@@ -4763,6 +4763,7 @@ void dump_exec_info(FILE *f, fprintf_function cpu_fprintf)
 }
 
 #define MMUSUFFIX _cmmu
+#undef GETPC
 #define GETPC() NULL
 #define env cpu_single_env
 #define SOFTMMU_CODE_ACCESS
commit bccd9ec5f098668576342c83d90d6d6833d61d33
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Mon Jul 4 20:57:05 2011 +0000

    softmmu_header: pass CPUState to tlb_fill
    
    Pass CPUState pointer to tlb_fill() instead of architecture local
    cpu_single_env hacks.
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/exec-all.h b/exec-all.h
index 9b8d62c..b1dfe10 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -273,7 +273,7 @@ extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
 extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
 extern void *io_mem_opaque[IO_MEM_NB_ENTRIES];
 
-void tlb_fill(target_ulong addr, int is_write, int mmu_idx,
+void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
               void *retaddr);
 
 #include "softmmu_defs.h"
diff --git a/softmmu_template.h b/softmmu_template.h
index ae0ccf2..36eb2e8 100644
--- a/softmmu_template.h
+++ b/softmmu_template.h
@@ -136,7 +136,7 @@ DATA_TYPE REGPARM glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
         if ((addr & (DATA_SIZE - 1)) != 0)
             do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
 #endif
-        tlb_fill(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
+        tlb_fill(env, addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
         goto redo;
     }
     return res;
@@ -186,7 +186,7 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
         }
     } else {
         /* the page is not in the TLB : fill it */
-        tlb_fill(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
+        tlb_fill(env, addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
         goto redo;
     }
     return res;
@@ -274,7 +274,7 @@ void REGPARM glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr,
         if ((addr & (DATA_SIZE - 1)) != 0)
             do_unaligned_access(addr, 1, mmu_idx, retaddr);
 #endif
-        tlb_fill(addr, 1, mmu_idx, retaddr);
+        tlb_fill(env, addr, 1, mmu_idx, retaddr);
         goto redo;
     }
 }
@@ -321,7 +321,7 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr,
         }
     } else {
         /* the page is not in the TLB : fill it */
-        tlb_fill(addr, 1, mmu_idx, retaddr);
+        tlb_fill(env, addr, 1, mmu_idx, retaddr);
         goto redo;
     }
 }
diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c
index 38be234..d8945dc 100644
--- a/target-alpha/op_helper.c
+++ b/target-alpha/op_helper.c
@@ -1335,15 +1335,14 @@ void QEMU_NORETURN cpu_unassigned_access(CPUState *env1,
    NULL, it means that the function was called in C code (i.e. not
    from generated code or from helper.c) */
 /* XXX: fix it to restore all registers */
-void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
+              void *retaddr)
 {
     CPUState *saved_env;
     int ret;
 
-    /* XXX: hack to restore env in all cases, even if not called from
-       generated code */
     saved_env = env;
-    env = cpu_single_env;
+    env = env1;
     ret = cpu_alpha_handle_mmu_fault(env, addr, is_write, mmu_idx);
     if (unlikely(ret != 0)) {
         do_restore_state(retaddr);
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index 37b77e1..ab9c923 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -75,17 +75,15 @@ uint32_t HELPER(neon_tbl)(uint32_t ireg, uint32_t def,
    NULL, it means that the function was called in C code (i.e. not
    from generated code or from helper.c) */
 /* XXX: fix it to restore all registers */
-void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
+              void *retaddr)
 {
     TranslationBlock *tb;
     CPUState *saved_env;
     unsigned long pc;
     int ret;
 
-    /* XXX: hack to restore env in all cases, even if not called from
-       generated code */
     saved_env = env;
-    env = cpu_single_env;
     ret = cpu_arm_handle_mmu_fault(env, addr, is_write, mmu_idx);
     if (unlikely(ret)) {
         if (retaddr) {
diff --git a/target-cris/op_helper.c b/target-cris/op_helper.c
index 0cfe1b1..1eacc5f 100644
--- a/target-cris/op_helper.c
+++ b/target-cris/op_helper.c
@@ -56,17 +56,16 @@
    NULL, it means that the function was called in C code (i.e. not
    from generated code or from helper.c) */
 /* XXX: fix it to restore all registers */
-void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
+              void *retaddr)
 {
     TranslationBlock *tb;
     CPUState *saved_env;
     unsigned long pc;
     int ret;
 
-    /* XXX: hack to restore env in all cases, even if not called from
-       generated code */
     saved_env = env;
-    env = cpu_single_env;
+    env = env1;
 
     D_LOG("%s pc=%x tpc=%x ra=%x\n", __func__, 
 	     env->pc, env->debug1, retaddr);
diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c
index 1fc248f..3bb5a91 100644
--- a/target-i386/op_helper.c
+++ b/target-i386/op_helper.c
@@ -4997,17 +4997,16 @@ void helper_boundl(target_ulong a0, int v)
    NULL, it means that the function was called in C code (i.e. not
    from generated code or from helper.c) */
 /* XXX: fix it to restore all registers */
-void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
+              void *retaddr)
 {
     TranslationBlock *tb;
     int ret;
     unsigned long pc;
     CPUX86State *saved_env;
 
-    /* XXX: hack to restore env in all cases, even if not called from
-       generated code */
     saved_env = env;
-    env = cpu_single_env;
+    env = env1;
 
     ret = cpu_x86_handle_mmu_fault(env, addr, is_write, mmu_idx);
     if (ret) {
diff --git a/target-lm32/op_helper.c b/target-lm32/op_helper.c
index 557da6c..02be134 100644
--- a/target-lm32/op_helper.c
+++ b/target-lm32/op_helper.c
@@ -75,17 +75,16 @@ uint32_t helper_rcsr_jrx(void)
    NULL, it means that the function was called in C code (i.e. not
    from generated code or from helper.c) */
 /* XXX: fix it to restore all registers */
-void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
+              void *retaddr)
 {
     TranslationBlock *tb;
     CPUState *saved_env;
     unsigned long pc;
     int ret;
 
-    /* XXX: hack to restore env in all cases, even if not called from
-       generated code */
     saved_env = env;
-    env = cpu_single_env;
+    env = env1;
 
     ret = cpu_lm32_handle_mmu_fault(env, addr, is_write, mmu_idx);
     if (unlikely(ret)) {
diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c
index c66fa0c..2f7fe6b 100644
--- a/target-m68k/op_helper.c
+++ b/target-m68k/op_helper.c
@@ -55,17 +55,16 @@ extern int semihosting_enabled;
    NULL, it means that the function was called in C code (i.e. not
    from generated code or from helper.c) */
 /* XXX: fix it to restore all registers */
-void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
+              void *retaddr)
 {
     TranslationBlock *tb;
     CPUState *saved_env;
     unsigned long pc;
     int ret;
 
-    /* XXX: hack to restore env in all cases, even if not called from
-       generated code */
     saved_env = env;
-    env = cpu_single_env;
+    env = env1;
     ret = cpu_m68k_handle_mmu_fault(env, addr, is_write, mmu_idx);
     if (unlikely(ret)) {
         if (retaddr) {
diff --git a/target-microblaze/op_helper.c b/target-microblaze/op_helper.c
index 8a7deac..7433cec 100644
--- a/target-microblaze/op_helper.c
+++ b/target-microblaze/op_helper.c
@@ -42,17 +42,16 @@
    NULL, it means that the function was called in C code (i.e. not
    from generated code or from helper.c) */
 /* XXX: fix it to restore all registers */
-void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
+              void *retaddr)
 {
     TranslationBlock *tb;
     CPUState *saved_env;
     unsigned long pc;
     int ret;
 
-    /* XXX: hack to restore env in all cases, even if not called from
-       generated code */
     saved_env = env;
-    env = cpu_single_env;
+    env = env1;
 
     ret = cpu_mb_handle_mmu_fault(env, addr, is_write, mmu_idx);
     if (unlikely(ret)) {
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 96e40c6..c51b9cb 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -2316,17 +2316,16 @@ static void do_unaligned_access (target_ulong addr, int is_write, int is_user, v
     helper_raise_exception ((is_write == 1) ? EXCP_AdES : EXCP_AdEL);
 }
 
-void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
+              void *retaddr)
 {
     TranslationBlock *tb;
     CPUState *saved_env;
     unsigned long pc;
     int ret;
 
-    /* XXX: hack to restore env in all cases, even if not called from
-       generated code */
     saved_env = env;
-    env = cpu_single_env;
+    env = env1;
     ret = cpu_mips_handle_mmu_fault(env, addr, is_write, mmu_idx);
     if (ret) {
         if (retaddr) {
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index c5e0601..134b0c6 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -3714,17 +3714,16 @@ uint32_t helper_efdcmpeq (uint64_t op1, uint64_t op2)
    NULL, it means that the function was called in C code (i.e. not
    from generated code or from helper.c) */
 /* XXX: fix it to restore all registers */
-void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
+              void *retaddr)
 {
     TranslationBlock *tb;
     CPUState *saved_env;
     unsigned long pc;
     int ret;
 
-    /* XXX: hack to restore env in all cases, even if not called from
-       generated code */
     saved_env = env;
-    env = cpu_single_env;
+    env = env1;
     ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx);
     if (unlikely(ret != 0)) {
         if (likely(retaddr)) {
diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c
index b3ac630..cd57678 100644
--- a/target-s390x/op_helper.c
+++ b/target-s390x/op_helper.c
@@ -52,17 +52,16 @@
    NULL, it means that the function was called in C code (i.e. not
    from generated code or from helper.c) */
 /* XXX: fix it to restore all registers */
-void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
+              void *retaddr)
 {
     TranslationBlock *tb;
     CPUState *saved_env;
     unsigned long pc;
     int ret;
 
-    /* XXX: hack to restore env in all cases, even if not called from
-       generated code */
     saved_env = env;
-    env = cpu_single_env;
+    env = env1;
     ret = cpu_s390x_handle_mmu_fault(env, addr, is_write, mmu_idx);
     if (unlikely(ret != 0)) {
         if (likely(retaddr)) {
diff --git a/target-sh4/op_helper.c b/target-sh4/op_helper.c
index 163858f..b299576 100644
--- a/target-sh4/op_helper.c
+++ b/target-sh4/op_helper.c
@@ -55,15 +55,14 @@ static void cpu_restore_state_from_retaddr(void *retaddr)
 #define SHIFT 3
 #include "softmmu_template.h"
 
-void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
+              void *retaddr)
 {
     CPUState *saved_env;
     int ret;
 
-    /* XXX: hack to restore env in all cases, even if not called from
-       generated code */
     saved_env = env;
-    env = cpu_single_env;
+    env = env1;
     ret = cpu_sh4_handle_mmu_fault(env, addr, is_write, mmu_idx);
     if (ret) {
         /* now we have a real cpu fault */
diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
index 48e1db8..1cb0636 100644
--- a/target-sparc/op_helper.c
+++ b/target-sparc/op_helper.c
@@ -4225,15 +4225,14 @@ static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
    NULL, it means that the function was called in C code (i.e. not
    from generated code or from helper.c) */
 /* XXX: fix it to restore all registers */
-void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
+              void *retaddr)
 {
     int ret;
     CPUState *saved_env;
 
-    /* XXX: hack to restore env in all cases, even if not called from
-       generated code */
     saved_env = env;
-    env = cpu_single_env;
+    env = env1;
 
     ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, mmu_idx);
     if (ret) {
diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c
index d02706d..64847fc 100644
--- a/target-xtensa/op_helper.c
+++ b/target-xtensa/op_helper.c
@@ -70,11 +70,12 @@ static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
     }
 }
 
-void tlb_fill(target_ulong vaddr, int is_write, int mmu_idx, void *retaddr)
+void tlb_fill(CPUState *env1, target_ulong vaddr, int is_write, int mmu_idx,
+              void *retaddr)
 {
     CPUState *saved_env = env;
 
-    env = cpu_single_env;
+    env = env1;
     {
         uint32_t paddr;
         uint32_t page_size;
commit efbf29b6816416731e5dc420901a90430b6ea92d
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Wed Sep 21 20:00:18 2011 +0000

    Document softmmu templates
    
    Add some comments to describe each file.
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/softmmu_defs.h b/softmmu_defs.h
index e38bb75..c5a2bcd 100644
--- a/softmmu_defs.h
+++ b/softmmu_defs.h
@@ -1,3 +1,11 @@
+/*
+ *  Software MMU support
+ *
+ * Declare helpers used by TCG for qemu_ld/st ops.
+ *
+ * Used by softmmu_exec.h, TCG targets and exec-all.h.
+ *
+ */
 #ifndef SOFTMMU_DEFS_H
 #define SOFTMMU_DEFS_H
 
diff --git a/softmmu_exec.h b/softmmu_exec.h
index 28d1d53..8c73985 100644
--- a/softmmu_exec.h
+++ b/softmmu_exec.h
@@ -1,4 +1,14 @@
-/* Common softmmu definitions and inline routines.  */
+/*
+ *  Software MMU support
+ *
+ * Generate inline load/store functions for all MMU modes (typically
+ * at least _user and _kernel) as well as _data versions, for all data
+ * sizes.
+ *
+ * Used by target op helpers.
+ *
+ * MMU mode suffixes are defined in target cpu.h.
+ */
 
 /* XXX: find something cleaner.
  * Furthermore, this is false for 64 bits targets
diff --git a/softmmu_header.h b/softmmu_header.h
index 2f95c33..818d7b6 100644
--- a/softmmu_header.h
+++ b/softmmu_header.h
@@ -1,6 +1,15 @@
 /*
  *  Software MMU support
  *
+ * Generate inline load/store functions for one MMU mode and data
+ * size.
+ *
+ * Generate a store function as well as signed and unsigned loads. For
+ * 32 and 64 bit cases, also generate floating point functions with
+ * the same size.
+ *
+ * Not used directly but included from softmmu_exec.h and exec-all.h.
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
diff --git a/softmmu_template.h b/softmmu_template.h
index c2df9ec..ae0ccf2 100644
--- a/softmmu_template.h
+++ b/softmmu_template.h
@@ -1,6 +1,11 @@
 /*
  *  Software MMU support
  *
+ * Generate helpers used by TCG for qemu_ld/st ops and code load
+ * functions.
+ *
+ * Included from target op helpers and exec.c.
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
commit bf4b9889ab02f528a7e3944d7cf64ddd77f9ad46
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Sep 11 15:54:18 2011 +0000

    ESP: convert to trace framework
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/esp.c b/hw/esp.c
index ca41f80..697c2c5 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -25,9 +25,7 @@
 #include "sysbus.h"
 #include "scsi.h"
 #include "esp.h"
-
-/* debug ESP card */
-//#define DEBUG_ESP
+#include "trace.h"
 
 /*
  * On Sparc32, this is the ESP (NCR53C90) part of chip STP2000 (Master I/O),
@@ -37,13 +35,6 @@
  * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR53C9X.txt
  */
 
-#ifdef DEBUG_ESP
-#define DPRINTF(fmt, ...)                                       \
-    do { printf("ESP: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while (0)
-#endif
-
 #define ESP_ERROR(fmt, ...)                                             \
     do { printf("ESP ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } while (0)
 
@@ -158,7 +149,7 @@ static void esp_raise_irq(ESPState *s)
     if (!(s->rregs[ESP_RSTAT] & STAT_INT)) {
         s->rregs[ESP_RSTAT] |= STAT_INT;
         qemu_irq_raise(s->irq);
-        DPRINTF("Raise IRQ\n");
+        trace_esp_raise_irq();
     }
 }
 
@@ -167,7 +158,7 @@ static void esp_lower_irq(ESPState *s)
     if (s->rregs[ESP_RSTAT] & STAT_INT) {
         s->rregs[ESP_RSTAT] &= ~STAT_INT;
         qemu_irq_lower(s->irq);
-        DPRINTF("Lower IRQ\n");
+        trace_esp_lower_irq();
     }
 }
 
@@ -178,13 +169,13 @@ static void esp_dma_enable(void *opaque, int irq, int level)
 
     if (level) {
         s->dma_enabled = 1;
-        DPRINTF("Raise enable\n");
+        trace_esp_dma_enable();
         if (s->dma_cb) {
             s->dma_cb(s);
             s->dma_cb = NULL;
         }
     } else {
-        DPRINTF("Lower enable\n");
+        trace_esp_dma_disable();
         s->dma_enabled = 0;
     }
 }
@@ -214,7 +205,7 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf)
         memcpy(buf, s->ti_buf, dmalen);
         buf[0] = buf[2] >> 5;
     }
-    DPRINTF("get_cmd: len %d target %d\n", dmalen, target);
+    trace_esp_get_cmd(dmalen, target);
 
     s->ti_size = 0;
     s->ti_rptr = 0;
@@ -243,7 +234,7 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
     int32_t datalen;
     int lun;
 
-    DPRINTF("do_busid_cmd: busid 0x%x\n", busid);
+    trace_esp_do_busid_cmd(busid);
     lun = busid & 7;
     s->current_req = scsi_req_new(s->current_dev, 0, lun, buf, NULL);
     datalen = scsi_req_enqueue(s->current_req);
@@ -308,7 +299,7 @@ static void handle_satn_stop(ESPState *s)
     }
     s->cmdlen = get_cmd(s, s->cmdbuf);
     if (s->cmdlen) {
-        DPRINTF("Set ATN & Stop: cmdlen %d\n", s->cmdlen);
+        trace_esp_handle_satn_stop(s->cmdlen);
         s->do_cmd = 1;
         s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD;
         s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
@@ -319,7 +310,7 @@ static void handle_satn_stop(ESPState *s)
 
 static void write_response(ESPState *s)
 {
-    DPRINTF("Transfer status (status=%d)\n", s->status);
+    trace_esp_write_response(s->status);
     s->ti_buf[0] = s->status;
     s->ti_buf[1] = 0;
     if (s->dma) {
@@ -355,7 +346,7 @@ static void esp_do_dma(ESPState *s)
     to_device = (s->ti_size < 0);
     len = s->dma_left;
     if (s->do_cmd) {
-        DPRINTF("command len %d + %d\n", s->cmdlen, len);
+        trace_esp_do_dma(s->cmdlen, len);
         s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len);
         s->ti_size = 0;
         s->cmdlen = 0;
@@ -400,15 +391,15 @@ static void esp_command_complete(SCSIRequest *req, uint32_t status)
 {
     ESPState *s = DO_UPCAST(ESPState, busdev.qdev, req->bus->qbus.parent);
 
-    DPRINTF("SCSI Command complete\n");
+    trace_esp_command_complete();
     if (s->ti_size != 0) {
-        DPRINTF("SCSI command completed unexpectedly\n");
+        trace_esp_command_complete_unexpected();
     }
     s->ti_size = 0;
     s->dma_left = 0;
     s->async_len = 0;
     if (status) {
-        DPRINTF("Command failed\n");
+        trace_esp_command_complete_fail();
     }
     s->status = status;
     s->rregs[ESP_RSTAT] = STAT_ST;
@@ -424,7 +415,7 @@ static void esp_transfer_data(SCSIRequest *req, uint32_t len)
 {
     ESPState *s = DO_UPCAST(ESPState, busdev.qdev, req->bus->qbus.parent);
 
-    DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size);
+    trace_esp_transfer_data(s->dma_left, s->ti_size);
     s->async_len = len;
     s->async_buf = scsi_req_get_buf(req);
     if (s->dma_left) {
@@ -452,13 +443,13 @@ static void handle_ti(ESPState *s)
         minlen = (dmalen < -s->ti_size) ? dmalen : -s->ti_size;
     else
         minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
-    DPRINTF("Transfer Information len %d\n", minlen);
+    trace_esp_handle_ti(minlen);
     if (s->dma) {
         s->dma_left = minlen;
         s->rregs[ESP_RSTAT] &= ~STAT_TC;
         esp_do_dma(s);
     } else if (s->do_cmd) {
-        DPRINTF("command len %d\n", s->cmdlen);
+        trace_esp_handle_ti_cmd(s->cmdlen);
         s->ti_size = 0;
         s->cmdlen = 0;
         s->do_cmd = 0;
@@ -517,7 +508,7 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
     uint32_t saddr, old_val;
 
     saddr = addr >> s->it_shift;
-    DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]);
+    trace_esp_mem_readb(saddr, s->rregs[saddr]);
     switch (saddr) {
     case ESP_FIFO:
         if (s->ti_size > 0) {
@@ -558,8 +549,7 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
     uint32_t saddr;
 
     saddr = addr >> s->it_shift;
-    DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr],
-            val);
+    trace_esp_mem_writeb(saddr, s->wregs[saddr], val);
     switch (saddr) {
     case ESP_TCLO:
     case ESP_TCMID:
@@ -587,21 +577,21 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
         }
         switch(val & CMD_CMD) {
         case CMD_NOP:
-            DPRINTF("NOP (%2.2x)\n", val);
+            trace_esp_mem_writeb_cmd_nop(val);
             break;
         case CMD_FLUSH:
-            DPRINTF("Flush FIFO (%2.2x)\n", val);
+            trace_esp_mem_writeb_cmd_flush(val);
             //s->ti_size = 0;
             s->rregs[ESP_RINTR] = INTR_FC;
             s->rregs[ESP_RSEQ] = 0;
             s->rregs[ESP_RFLAGS] = 0;
             break;
         case CMD_RESET:
-            DPRINTF("Chip reset (%2.2x)\n", val);
+            trace_esp_mem_writeb_cmd_reset(val);
             esp_soft_reset(&s->busdev.qdev);
             break;
         case CMD_BUSRESET:
-            DPRINTF("Bus reset (%2.2x)\n", val);
+            trace_esp_mem_writeb_cmd_bus_reset(val);
             s->rregs[ESP_RINTR] = INTR_RST;
             if (!(s->wregs[ESP_CFG1] & CFG1_RESREPT)) {
                 esp_raise_irq(s);
@@ -611,41 +601,41 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
             handle_ti(s);
             break;
         case CMD_ICCS:
-            DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val);
+            trace_esp_mem_writeb_cmd_iccs(val);
             write_response(s);
             s->rregs[ESP_RINTR] = INTR_FC;
             s->rregs[ESP_RSTAT] |= STAT_MI;
             break;
         case CMD_MSGACC:
-            DPRINTF("Message Accepted (%2.2x)\n", val);
+            trace_esp_mem_writeb_cmd_msgacc(val);
             s->rregs[ESP_RINTR] = INTR_DC;
             s->rregs[ESP_RSEQ] = 0;
             s->rregs[ESP_RFLAGS] = 0;
             esp_raise_irq(s);
             break;
         case CMD_PAD:
-            DPRINTF("Transfer padding (%2.2x)\n", val);
+            trace_esp_mem_writeb_cmd_pad(val);
             s->rregs[ESP_RSTAT] = STAT_TC;
             s->rregs[ESP_RINTR] = INTR_FC;
             s->rregs[ESP_RSEQ] = 0;
             break;
         case CMD_SATN:
-            DPRINTF("Set ATN (%2.2x)\n", val);
+            trace_esp_mem_writeb_cmd_satn(val);
             break;
         case CMD_SEL:
-            DPRINTF("Select without ATN (%2.2x)\n", val);
+            trace_esp_mem_writeb_cmd_sel(val);
             handle_s_without_atn(s);
             break;
         case CMD_SELATN:
-            DPRINTF("Select with ATN (%2.2x)\n", val);
+            trace_esp_mem_writeb_cmd_selatn(val);
             handle_satn(s);
             break;
         case CMD_SELATNS:
-            DPRINTF("Select with ATN & stop (%2.2x)\n", val);
+            trace_esp_mem_writeb_cmd_selatns(val);
             handle_satn_stop(s);
             break;
         case CMD_ENSEL:
-            DPRINTF("Enable selection (%2.2x)\n", val);
+            trace_esp_mem_writeb_cmd_ensel(val);
             s->rregs[ESP_RINTR] = 0;
             break;
         default:
diff --git a/trace-events b/trace-events
index a31d9aa..b7ddf14 100644
--- a/trace-events
+++ b/trace-events
@@ -502,3 +502,34 @@ escc_sunkbd_event_in(int ch) "Untranslated keycode %2.2x"
 escc_sunkbd_event_out(int ch) "Translated keycode %2.2x"
 escc_kbd_command(int val) "Command %d"
 escc_sunmouse_event(int dx, int dy, int buttons_state) "dx=%d dy=%d buttons=%01x"
+
+# hw/esp.c
+esp_raise_irq(void) "Raise IRQ"
+esp_lower_irq(void) "Lower IRQ"
+esp_dma_enable(void) "Raise enable"
+esp_dma_disable(void) "Lower enable"
+esp_get_cmd(uint32_t dmalen, int target) "len %d target %d"
+esp_do_busid_cmd(uint8_t busid) "busid 0x%x"
+esp_handle_satn_stop(uint32_t cmdlen) "cmdlen %d"
+esp_write_response(uint32_t status) "Transfer status (status=%d)"
+esp_do_dma(uint32_t cmdlen, uint32_t len) "command len %d + %d"
+esp_command_complete(void) "SCSI Command complete"
+esp_command_complete_unexpected(void) "SCSI command completed unexpectedly"
+esp_command_complete_fail(void) "Command failed"
+esp_transfer_data(uint32_t dma_left, int32_t ti_size) "transfer %d/%d"
+esp_handle_ti(uint32_t minlen) "Transfer Information len %d"
+esp_handle_ti_cmd(uint32_t cmdlen) "command len %d"
+esp_mem_readb(uint32_t saddr, uint8_t reg) "reg[%d]: 0x%2.2x"
+esp_mem_writeb(uint32_t saddr, uint8_t reg, uint32_t val) "reg[%d]: 0x%2.2x -> 0x%2.2x"
+esp_mem_writeb_cmd_nop(uint32_t val) "NOP (%2.2x)"
+esp_mem_writeb_cmd_flush(uint32_t val) "Flush FIFO (%2.2x)"
+esp_mem_writeb_cmd_reset(uint32_t val) "Chip reset (%2.2x)"
+esp_mem_writeb_cmd_bus_reset(uint32_t val) "Bus reset (%2.2x)"
+esp_mem_writeb_cmd_iccs(uint32_t val) "Initiator Command Complete Sequence (%2.2x)"
+esp_mem_writeb_cmd_msgacc(uint32_t val) "Message Accepted (%2.2x)"
+esp_mem_writeb_cmd_pad(uint32_t val) "Transfer padding (%2.2x)"
+esp_mem_writeb_cmd_satn(uint32_t val) "Set ATN (%2.2x)"
+esp_mem_writeb_cmd_sel(uint32_t val) "Select without ATN (%2.2x)"
+esp_mem_writeb_cmd_selatn(uint32_t val) "Select with ATN (%2.2x)"
+esp_mem_writeb_cmd_selatns(uint32_t val) "Select with ATN & stop (%2.2x)"
+esp_mem_writeb_cmd_ensel(uint32_t val) "Enable selection (%2.2x)"
commit b39491a83d0b9d573d5fd21163f61f66a11b54b9
Author: Alexander Graf <agraf at suse.de>
Date:   Fri Sep 30 15:29:12 2011 +0200

    PPC: Drop initial ESCC mapping
    
    We are mapping ESCC to a static (incorrect) address on machine init. This
    overlaps with our vram, rendering the screen barely usable.
    
    Since openBIOS is clever enough to map ESCC to where it needs to be, we can
    just drop that invalid map and everyone's happy.
    
    Signed-off-by: Alexander Graf <agraf at suse.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c
index 69718cf..b1cc3d7 100644
--- a/hw/ppc_newworld.c
+++ b/hw/ppc_newworld.c
@@ -325,7 +325,7 @@ static void ppc_core99_init (ram_addr_t ram_size,
     /* init basic PC hardware */
     pci_vga_init(pci_bus);
 
-    escc_mem = escc_init(0x80013000, pic[0x25], pic[0x24],
+    escc_mem = escc_init(0, pic[0x25], pic[0x24],
                          serial_hds[0], serial_hds[1], ESCC_CLOCK, 4);
     memory_region_init_alias(escc_bar, "escc-bar",
                              escc_mem, 0, memory_region_size(escc_mem));
diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c
index e127d21..fa2c1e7 100644
--- a/hw/ppc_oldworld.c
+++ b/hw/ppc_oldworld.c
@@ -237,7 +237,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
                                get_system_io());
     pci_vga_init(pci_bus);
 
-    escc_mem = escc_init(0x80013000, pic[0x0f], pic[0x10], serial_hds[0],
+    escc_mem = escc_init(0, pic[0x0f], pic[0x10], serial_hds[0],
                                serial_hds[1], ESCC_CLOCK, 4);
     memory_region_init_alias(escc_bar, "escc-bar",
                              escc_mem, 0, memory_region_size(escc_mem));
commit a4773324b4bc5f15fe9b438e4cfff05e1ab16dfa
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Thu Sep 29 18:52:11 2011 +0200

    tcg-i386: Introduce limited deposit support
    
    x86 cannot provide an optimized generic deposit implementation. But at
    least for a few special cases, namely for writing bits 0..7, 8..15, and
    0..15, versions using only a single instruction are feasible.
    Introducing such limited support improves emulating 16-bit x86 code on
    x86, but also rarer cases where 32-bit or 64-bit code accesses bytes or
    words.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c
index 281f87d..3069e53 100644
--- a/tcg/i386/tcg-target.c
+++ b/tcg/i386/tcg-target.c
@@ -168,6 +168,10 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
             tcg_regset_set32(ct->u.regs, 0, 0xf);
         }
         break;
+    case 'Q':
+        ct->ct |= TCG_CT_REG;
+        tcg_regset_set32(ct->u.regs, 0, 0xf);
+        break;
     case 'r':
         ct->ct |= TCG_CT_REG;
         if (TCG_TARGET_REG_BITS == 64) {
@@ -1747,6 +1751,22 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
         break;
 #endif
 
+    OP_32_64(deposit):
+        if (args[3] == 0 && args[4] == 8) {
+            /* load bits 0..7 */
+            tcg_out_modrm(s, OPC_MOVB_EvGv | P_REXB_R | P_REXB_RM,
+                          args[2], args[0]);
+        } else if (args[3] == 8 && args[4] == 8) {
+            /* load bits 8..15 */
+            tcg_out_modrm(s, OPC_MOVB_EvGv, args[2], args[0] + 4);
+        } else if (args[3] == 0 && args[4] == 16) {
+            /* load bits 0..15 */
+            tcg_out_modrm(s, OPC_MOVL_EvGv | P_DATA16, args[2], args[0]);
+        } else {
+            tcg_abort();
+        }
+        break;
+
     default:
         tcg_abort();
     }
@@ -1802,6 +1822,8 @@ static const TCGTargetOpDef x86_op_defs[] = {
 
     { INDEX_op_setcond_i32, { "q", "r", "ri" } },
 
+    { INDEX_op_deposit_i32, { "Q", "0", "Q" } },
+
 #if TCG_TARGET_REG_BITS == 32
     { INDEX_op_mulu2_i32, { "a", "d", "a", "r" } },
     { INDEX_op_add2_i32, { "r", "r", "0", "1", "ri", "ri" } },
@@ -1853,6 +1875,8 @@ static const TCGTargetOpDef x86_op_defs[] = {
     { INDEX_op_ext8u_i64, { "r", "r" } },
     { INDEX_op_ext16u_i64, { "r", "r" } },
     { INDEX_op_ext32u_i64, { "r", "r" } },
+
+    { INDEX_op_deposit_i64, { "Q", "0", "Q" } },
 #endif
 
 #if TCG_TARGET_REG_BITS == 64
diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h
index 5088e47..b9c9d4e 100644
--- a/tcg/i386/tcg-target.h
+++ b/tcg/i386/tcg-target.h
@@ -90,7 +90,7 @@ enum {
 #define TCG_TARGET_HAS_eqv_i32          0
 #define TCG_TARGET_HAS_nand_i32         0
 #define TCG_TARGET_HAS_nor_i32          0
-#define TCG_TARGET_HAS_deposit_i32      0
+#define TCG_TARGET_HAS_deposit_i32      1
 
 #if TCG_TARGET_REG_BITS == 64
 #define TCG_TARGET_HAS_div2_i64         1
@@ -111,9 +111,14 @@ enum {
 #define TCG_TARGET_HAS_eqv_i64          0
 #define TCG_TARGET_HAS_nand_i64         0
 #define TCG_TARGET_HAS_nor_i64          0
-#define TCG_TARGET_HAS_deposit_i64      0
+#define TCG_TARGET_HAS_deposit_i64      1
 #endif
 
+#define TCG_TARGET_deposit_i32_valid(ofs, len) \
+    (((ofs) == 0 && (len) == 8) || ((ofs) == 8 && (len) == 8) || \
+     ((ofs) == 0 && (len) == 16))
+#define TCG_TARGET_deposit_i64_valid    TCG_TARGET_deposit_i32_valid
+
 #define TCG_TARGET_HAS_GUEST_BASE
 
 /* Note: must be synced with dyngen-exec.h */
diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h
index 404b637..fea5983 100644
--- a/tcg/tcg-op.h
+++ b/tcg/tcg-op.h
@@ -2045,7 +2045,7 @@ static inline void tcg_gen_deposit_i32(TCGv_i32 ret, TCGv_i32 arg1,
 				       TCGv_i32 arg2, unsigned int ofs,
 				       unsigned int len)
 {
-    if (TCG_TARGET_HAS_deposit_i32) {
+    if (TCG_TARGET_HAS_deposit_i32 && TCG_TARGET_deposit_i32_valid(ofs, len)) {
         tcg_gen_op5ii_i32(INDEX_op_deposit_i32, ret, arg1, arg2, ofs, len);
     } else {
         uint32_t mask = (1u << len) - 1;
@@ -2064,7 +2064,7 @@ static inline void tcg_gen_deposit_i64(TCGv_i64 ret, TCGv_i64 arg1,
 				       TCGv_i64 arg2, unsigned int ofs,
 				       unsigned int len)
 {
-    if (TCG_TARGET_HAS_deposit_i64) {
+    if (TCG_TARGET_HAS_deposit_i64 && TCG_TARGET_deposit_i64_valid(ofs, len)) {
         tcg_gen_op5ii_i64(INDEX_op_deposit_i64, ret, arg1, arg2, ofs, len);
     } else {
         uint64_t mask = (1ull << len) - 1;
diff --git a/tcg/tcg.h b/tcg/tcg.h
index 1859fae..de8a1d5 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -81,6 +81,13 @@ typedef uint64_t TCGRegSet;
 #define TCG_TARGET_HAS_deposit_i64      0
 #endif
 
+#ifndef TCG_TARGET_deposit_i32_valid
+#define TCG_TARGET_deposit_i32_valid(ofs, len) 1
+#endif
+#ifndef TCG_TARGET_deposit_i64_valid
+#define TCG_TARGET_deposit_i64_valid(ofs, len) 1
+#endif
+
 /* Only one of DIV or DIV2 should be defined.  */
 #if defined(TCG_TARGET_HAS_div_i32)
 #define TCG_TARGET_HAS_div2_i32         0
commit 7e17a217061e402243499d96fc8dec92162d8b4a
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Wed Sep 28 11:19:02 2011 +0200

    mips_fulong2e: Reorder ISA bus and i8259 creation
    
    Missed during memory region conversion: The i8259 now depends on the ISA
    bus being created first. Reorder the initialization.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/mips_fulong2e.c b/hw/mips_fulong2e.c
index f52b8c5..04921c1 100644
--- a/hw/mips_fulong2e.c
+++ b/hw/mips_fulong2e.c
@@ -331,10 +331,6 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device,
     cpu_mips_irq_init_cpu(env);
     cpu_mips_clock_init(env);
 
-    /* Interrupt controller */
-    /* The 8259 -> IP5  */
-    i8259 = i8259_init(env->irq[5]);
-
     /* North bridge, Bonito --> IP2 */
     pci_bus = bonito_init((qemu_irq *)&(env->irq[2]));
 
@@ -347,7 +343,11 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device,
         exit(1);
     }
 
+    /* Interrupt controller */
+    /* The 8259 -> IP5  */
+    i8259 = i8259_init(env->irq[5]);
     isa_bus_irqs(i8259);
+
     vt82c686b_ide_init(pci_bus, hd, PCI_DEVFN(FULONG2E_VIA_SLOT, 1));
     usb_uhci_vt82c686b_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 2));
     usb_uhci_vt82c686b_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 3));
commit 86ce7a5e7eedb7b1f18b24159fde20d47259b619
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Mon Sep 26 19:20:00 2011 +0200

    target-i386: Remove redundant word mask in port out instructions
    
    T0 was already masked to 16 bits when loading it.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-i386/translate.c b/target-i386/translate.c
index b894e97..1ef8d16 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -6116,7 +6116,6 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
         if (use_icount)
             gen_io_start();
         tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
-        tcg_gen_andi_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0xffff);
         tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T[1]);
         gen_helper_out_func(ot, cpu_tmp2_i32, cpu_tmp3_i32);
         if (use_icount) {
@@ -6159,7 +6158,6 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
         if (use_icount)
             gen_io_start();
         tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
-        tcg_gen_andi_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0xffff);
         tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T[1]);
         gen_helper_out_func(ot, cpu_tmp2_i32, cpu_tmp3_i32);
         if (use_icount) {
commit 2ac8bd03c55422a7505ece2a0d39a396eb09c6e5
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Mon Sep 26 16:56:55 2011 +0100

    softfloat: Reinstate accidentally disabled target-specific NaN handling
    
    Include config.h in softfloat.c, so that the target specific ifdefs in
    softfloat-specialize.h are evaluated correctly. This was accidentally
    broken in commit 789ec7ce2 when config-target.h was removed from
    softfloat.h, and means that most targets will have been returning the
    wrong results for calculations involving NaNs.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index 2b20085..3aafa81 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -35,6 +35,11 @@ these four paragraphs for those parts of this code that are retained.
 
 =============================================================================*/
 
+/* softfloat (and in particular the code in softfloat-specialize.h) is
+ * target-dependent and needs the TARGET_* macros.
+ */
+#include "config.h"
+
 #include "softfloat.h"
 
 /*----------------------------------------------------------------------------
commit df0eda9b73420363ad9dbf8c7eff47a0c4e47ff3
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Mon Sep 12 11:03:45 2011 +0100

    tcg/arm: Remove unused tcg_out_addi()
    
    Remove the unused function tcg_out_addi() from the ARM TCG backend;
    this fixes a compilation failure on ARM hosts with newer gcc.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c
index 93eb0f1..ce4760d 100644
--- a/tcg/arm/tcg-target.c
+++ b/tcg/arm/tcg-target.c
@@ -1820,21 +1820,6 @@ static inline void tcg_out_st(TCGContext *s, TCGType type, int arg,
     tcg_out_st32(s, COND_AL, arg, arg1, arg2);
 }
 
-static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
-{
-    if (val > 0)
-        if (val < 0x100)
-            tcg_out_dat_imm(s, COND_AL, ARITH_ADD, reg, reg, val);
-        else
-            tcg_abort();
-    else if (val < 0) {
-        if (val > -0x100)
-            tcg_out_dat_imm(s, COND_AL, ARITH_SUB, reg, reg, -val);
-        else
-            tcg_abort();
-    }
-}
-
 static inline void tcg_out_mov(TCGContext *s, TCGType type, int ret, int arg)
 {
     tcg_out_dat_reg(s, COND_AL, ARITH_MOV, ret, 0, arg, SHIFT_IMM_LSL(0));
commit f28ffed52cd0fd4231adbf9b229a0c1bba1b2e3f
Author: Brad <brad at comstyle.com>
Date:   Wed Sep 7 21:24:56 2011 -0400

    configure: Detect predefined compiler symbols for ARM and HPPA
    
    To be able to detect some ARM / HPPA based architectures such as with
    OpenBSD/(armish / zaurus) or OpenBSD/hppa.
    
    Signed-off-by: Brad Smith <brad at comstyle.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/configure b/configure
index 24b8df4..59b1494 100755
--- a/configure
+++ b/configure
@@ -284,6 +284,12 @@ elif check_define __s390__ ; then
   else
     cpu="s390"
   fi
+elif check_define __ARMEB__ ; then
+  cpu="armv4b"
+elif check_define __ARMEL__ ; then
+  cpu="armv4l"
+elif check_define __hppa__ ; then
+  cpu="hppa"
 else
   cpu=`uname -m`
 fi
@@ -304,7 +310,7 @@ case "$cpu" in
   armv*l)
     cpu="armv4l"
   ;;
-  parisc|parisc64)
+  hppa|parisc|parisc64)
     cpu="hppa"
   ;;
   mips*)
commit 7f6f0ae5b95adfa76e10eabe2c34424a955fd10c
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Sat Sep 17 22:00:30 2011 +0200

    tcg: Add some assertions
    
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/tcg/tcg.c b/tcg/tcg.c
index bdd7a67..30f3aef 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -794,7 +794,9 @@ static char *tcg_get_arg_str_idx(TCGContext *s, char *buf, int buf_size,
 {
     TCGTemp *ts;
 
+    assert(idx >= 0 && idx < s->nb_temps);
     ts = &s->temps[idx];
+    assert(ts);
     if (idx < s->nb_globals) {
         pstrcpy(buf, buf_size, ts->name);
     } else {
commit c0ad3001bf12292b137b05e1c4643f31c6b0a727
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Sat Sep 17 22:00:29 2011 +0200

    tcg: Add forward declarations for local functions
    
    These functions are defined in the tcg target specific file
    tcg-target.c.
    
    The forward declarations assert that every tcg target uses
    the same function prototype.
    
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/tcg/tcg.c b/tcg/tcg.c
index 411f971..bdd7a67 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -63,11 +63,27 @@
 #error GUEST_BASE not supported on this host.
 #endif
 
+/* Forward declarations for functions declared in tcg-target.c and used here. */
 static void tcg_target_init(TCGContext *s);
 static void tcg_target_qemu_prologue(TCGContext *s);
 static void patch_reloc(uint8_t *code_ptr, int type, 
                         tcg_target_long value, tcg_target_long addend);
 
+/* Forward declarations for functions declared and used in tcg-target.c. */
+static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str);
+static void tcg_out_ld(TCGContext *s, TCGType type, int ret, int arg1,
+                       tcg_target_long arg2);
+static void tcg_out_mov(TCGContext *s, TCGType type, int ret, int arg);
+static void tcg_out_movi(TCGContext *s, TCGType type,
+                         int ret, tcg_target_long arg);
+static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
+                       const int *const_args);
+static void tcg_out_st(TCGContext *s, TCGType type, int arg, int arg1,
+                       tcg_target_long arg2);
+static int tcg_target_const_match(tcg_target_long val,
+                                  const TCGArgConstraint *arg_ct);
+static int tcg_target_get_call_iarg_regs_count(int flags);
+
 TCGOpDef tcg_op_defs[] = {
 #define DEF(s, oargs, iargs, cargs, flags) { #s, oargs, iargs, cargs, iargs + oargs + cargs, flags },
 #include "tcg-opc.h"
commit 840f58617b12a536ec56e5775ab42d730d0d6259
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Sat Sep 17 22:00:28 2011 +0200

    tcg: Don't declare TCG_TARGET_REG_BITS in tcg-target.h
    
    It is now declared for all tcg targets in tcg.h,
    so the tcg target specific declarations are redundant.
    
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h
index 0e0f69a..33afd97 100644
--- a/tcg/arm/tcg-target.h
+++ b/tcg/arm/tcg-target.h
@@ -24,7 +24,6 @@
  */
 #define TCG_TARGET_ARM 1
 
-#define TCG_TARGET_REG_BITS 32
 #undef TCG_TARGET_WORDS_BIGENDIAN
 #undef TCG_TARGET_STACK_GROWSUP
 
diff --git a/tcg/hppa/tcg-target.h b/tcg/hppa/tcg-target.h
index ed90efc..ec9a7bf 100644
--- a/tcg/hppa/tcg-target.h
+++ b/tcg/hppa/tcg-target.h
@@ -24,9 +24,7 @@
 
 #define TCG_TARGET_HPPA 1
 
-#if defined(_PA_RISC1_1)
-#define TCG_TARGET_REG_BITS 32
-#else
+#if TCG_TARGET_REG_BITS != 32
 #error unsupported
 #endif
 
diff --git a/tcg/ia64/tcg-target.h b/tcg/ia64/tcg-target.h
index ddc93c1..578cf29 100644
--- a/tcg/ia64/tcg-target.h
+++ b/tcg/ia64/tcg-target.h
@@ -24,8 +24,6 @@
  */
 #define TCG_TARGET_IA64 1
 
-#define TCG_TARGET_REG_BITS 64
-
 /* We only map the first 64 registers */
 #define TCG_TARGET_NB_REGS 64
 enum {
diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h
index 43c5501..e2a2571 100644
--- a/tcg/mips/tcg-target.h
+++ b/tcg/mips/tcg-target.h
@@ -25,7 +25,6 @@
  */
 #define TCG_TARGET_MIPS 1
 
-#define TCG_TARGET_REG_BITS 32
 #ifdef __MIPSEB__
 # define TCG_TARGET_WORDS_BIGENDIAN
 #endif
diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h
index f9a88c4..5c2d612 100644
--- a/tcg/ppc/tcg-target.h
+++ b/tcg/ppc/tcg-target.h
@@ -23,7 +23,6 @@
  */
 #define TCG_TARGET_PPC 1
 
-#define TCG_TARGET_REG_BITS 32
 #define TCG_TARGET_WORDS_BIGENDIAN
 #define TCG_TARGET_NB_REGS 32
 
diff --git a/tcg/ppc64/tcg-target.h b/tcg/ppc64/tcg-target.h
index 5395131..8d1fb73 100644
--- a/tcg/ppc64/tcg-target.h
+++ b/tcg/ppc64/tcg-target.h
@@ -23,7 +23,6 @@
  */
 #define TCG_TARGET_PPC64 1
 
-#define TCG_TARGET_REG_BITS 64
 #define TCG_TARGET_WORDS_BIGENDIAN
 #define TCG_TARGET_NB_REGS 32
 
diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h
index 35ebac3..e4cd641 100644
--- a/tcg/s390/tcg-target.h
+++ b/tcg/s390/tcg-target.h
@@ -23,12 +23,6 @@
  */
 #define TCG_TARGET_S390 1
 
-#ifdef __s390x__
-#define TCG_TARGET_REG_BITS 64
-#else
-#define TCG_TARGET_REG_BITS 32
-#endif
-
 #define TCG_TARGET_WORDS_BIGENDIAN
 
 typedef enum TCGReg {
diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h
index 7b4e7f9..1464ef4 100644
--- a/tcg/sparc/tcg-target.h
+++ b/tcg/sparc/tcg-target.h
@@ -23,12 +23,6 @@
  */
 #define TCG_TARGET_SPARC 1
 
-#if defined(__sparc_v9__) && !defined(__sparc_v8plus__)
-#define TCG_TARGET_REG_BITS 64
-#else
-#define TCG_TARGET_REG_BITS 32
-#endif
-
 #define TCG_TARGET_WORDS_BIGENDIAN
 
 #define TCG_TARGET_NB_REGS 32
commit 817b838e3c9faca4eca7e878f901ba8122f02043
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Sat Sep 17 22:00:27 2011 +0200

    tcg: Declare TCG_TARGET_REG_BITS in tcg.h
    
    TCG_TARGET_REG_BITS can be determined by the compiler,
    so there is no need to declare it for each individual tcg target.
    
    This is especially important for new tcg targets
    which will be supported by the tcg interpreter.
    
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/tcg/tcg.h b/tcg/tcg.h
index dc5e9c9..1859fae 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -22,6 +22,16 @@
  * THE SOFTWARE.
  */
 #include "qemu-common.h"
+
+/* Target word size (must be identical to pointer size). */
+#if UINTPTR_MAX == UINT32_MAX
+# define TCG_TARGET_REG_BITS 32
+#elif UINTPTR_MAX == UINT64_MAX
+# define TCG_TARGET_REG_BITS 64
+#else
+# error Unknown pointer size for tcg target
+#endif
+
 #include "tcg-target.h"
 #include "tcg-runtime.h"
 
commit 8f440cda08c6df574ad153c3558a81c7d3ad5845
Merge: 62ec607... 2b44043...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Sep 29 13:33:47 2011 -0500

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

commit 62ec6073cd07b847c296b3a1fa19894293f8155d
Merge: 0bce98d... 5f54222...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Sep 29 13:32:05 2011 -0500

    Merge remote-tracking branch 'aneesh/for-upstream-5' into staging

commit 0bce98df2639aef1e8af90b271aa91e16d695408
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Mon Aug 29 21:13:29 2011 +0000

    Add OpenBIOS as a submodule
    
    Update OpenBIOS images to r1047 built from submodule.
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/.gitmodules b/.gitmodules
index 7884471..c3faa38 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -10,3 +10,6 @@
 [submodule "roms/ipxe"]
 	path = roms/ipxe
 	url = git://git.qemu.org/ipxe.git
+[submodule "roms/openbios"]
+	path = roms/openbios
+	url = git://git.qemu.org/openbios.git
diff --git a/pc-bios/README b/pc-bios/README
index f74b246..02651fe 100644
--- a/pc-bios/README
+++ b/pc-bios/README
@@ -10,9 +10,9 @@
 - OpenBIOS (http://www.openbios.org/) is a free (GPL v2) portable
   firmware implementation. The goal is to implement a 100% IEEE
   1275-1994 (referred to as Open Firmware) compliant firmware.
-  The included image for PowerPC (for 32 and 64 bit PPC CPUs)
-  is built from OpenBIOS SVN revision 1044 and Sparc32 and Sparc64
-  images are built from OpenBIOS SVN revision 1045.
+  The included images for PowerPC (for 32 and 64 bit PPC CPUs),
+  Sparc32 and Sparc64 are built from OpenBIOS SVN revision
+  1047.
 
 - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
   implementation for certain IBM POWER hardware.  The sources are at
diff --git a/pc-bios/openbios-ppc b/pc-bios/openbios-ppc
index 6525a91..83b7794 100644
Binary files a/pc-bios/openbios-ppc and b/pc-bios/openbios-ppc differ
diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32
index ea9cc32..03353c9 100644
Binary files a/pc-bios/openbios-sparc32 and b/pc-bios/openbios-sparc32 differ
diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64
index 7e746b4..c8972ac 100644
Binary files a/pc-bios/openbios-sparc64 and b/pc-bios/openbios-sparc64 differ
diff --git a/roms/openbios b/roms/openbios
new file mode 160000
index 0000000..ff61d97
--- /dev/null
+++ b/roms/openbios
@@ -0,0 +1 @@
+Subproject commit ff61d973e5a4a68b29e485b3f88e6a2d1d96cf45
commit 2b4404326598bec4cb954bfc54fc5e9740a51f7b
Author: Thomas Huth <thuth at linux.vnet.ibm.com>
Date:   Tue Sep 27 11:20:38 2011 +0200

    slirp: Fix packet expiration
    
    The two new variables "arp_requested" and "expiration_date" in the mbuf
    structure have been added after the variable-sized "m_dat_" array. The
    variables have to be added before the m_dat_ array instead.
    Without this patch, the expiration_date gets clobbered by code that
    accesses the m_dat_ array.
    I experienced this problem with the code in slirp/tftp.c: The
    tftp_send_data() function created a new packet with the m_get()
    function (which fills-in a default expiration_date value). Then the
    TFTP code cleared the data section of the packet, which accidentially
    also cleared the expiration_date. This zeroed expiration_date then
    finally causes the packet to be discarded during if_start(), so that
    TFTP packets were not transmitted anymore.
    
    [Jan: added comment as suggested by Fabien ]
    
    CC: Fabien Chouteau <chouteau at adacore.com>
    Signed-off-by: Thomas Huth <thuth at linux.vnet.ibm.com>
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>

diff --git a/slirp/mbuf.h b/slirp/mbuf.h
index 55170e5..0708840 100644
--- a/slirp/mbuf.h
+++ b/slirp/mbuf.h
@@ -82,12 +82,13 @@ struct m_hdr {
 struct mbuf {
 	struct	m_hdr m_hdr;
 	Slirp *slirp;
+	bool	arp_requested;
+	uint64_t expiration_date;
+	/* start of dynamic buffer area, must be last element */
 	union M_dat {
 		char	m_dat_[1]; /* ANSI don't like 0 sized arrays */
 		char	*m_ext_;
 	} M_dat;
-    bool     arp_requested;
-    uint64_t expiration_date;
 };
 
 #define m_next		m_hdr.mh_next
commit 8d06d69bc448301d27cab1405efba9d876dd39da
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Mon Sep 26 21:29:56 2011 +0200

    slirp: Fix use after release on tcp_input
    
    ti points into the m buffer. But the latter may already be released
    right after the dodata: label. Move the test before the potential
    release.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>

diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c
index 2f1a196..942aaf4 100644
--- a/slirp/tcp_input.c
+++ b/slirp/tcp_input.c
@@ -1157,6 +1157,16 @@ step6:
 dodata:
 
 	/*
+	 * If this is a small packet, then ACK now - with Nagel
+	 *      congestion avoidance sender won't send more until
+	 *      he gets an ACK.
+	 */
+	if (ti->ti_len && (unsigned)ti->ti_len <= 5 &&
+	    ((struct tcpiphdr_2 *)ti)->first_char == (char)27) {
+		tp->t_flags |= TF_ACKNOW;
+	}
+
+	/*
 	 * Process the segment text, merging it into the TCP sequencing queue,
 	 * and arranging for acknowledgment of receipt if necessary.
 	 * This process logically involves adjusting tp->rcv_wnd as data
@@ -1235,18 +1245,6 @@ dodata:
 	}
 
 	/*
-	 * If this is a small packet, then ACK now - with Nagel
-	 *      congestion avoidance sender won't send more until
-	 *      he gets an ACK.
-	 *
-	 * See above.
-	 */
-	if (ti->ti_len && (unsigned)ti->ti_len <= 5 &&
-	    ((struct tcpiphdr_2 *)ti)->first_char == (char)27) {
-		tp->t_flags |= TF_ACKNOW;
-	}
-
-	/*
 	 * Return any desired output.
 	 */
 	if (needoutput || (tp->t_flags & TF_ACKNOW)) {
commit 46f3069cba94aab44b3b4f87bc270759b4a700fa
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sat Sep 17 20:30:50 2011 +0000

    PPC: use memory API to construct the PCI hole
    
    Avoid vga.chain4 mapping by constructing a PCI hole for upper
    2G of the PCI space.
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c
index 9d3ff7d..94a608e 100644
--- a/hw/grackle_pci.c
+++ b/hw/grackle_pci.c
@@ -41,6 +41,8 @@
 typedef struct GrackleState {
     SysBusDevice busdev;
     PCIHostState host_state;
+    MemoryRegion pci_mmio;
+    MemoryRegion pci_hole;
 } GrackleState;
 
 /* Don't know if this matches real hardware, but it agrees with OHW.  */
@@ -73,11 +75,18 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic,
     qdev_init_nofail(dev);
     s = sysbus_from_qdev(dev);
     d = FROM_SYSBUS(GrackleState, s);
+
+    memory_region_init(&d->pci_mmio, "pci-mmio", 0x100000000ULL);
+    memory_region_init_alias(&d->pci_hole, "pci-hole", &d->pci_mmio,
+                             0x80000000ULL, 0x7e000000ULL);
+    memory_region_add_subregion(address_space_mem, 0x80000000ULL,
+                                &d->pci_hole);
+
     d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
                                          pci_grackle_set_irq,
                                          pci_grackle_map_irq,
                                          pic,
-                                         address_space_mem,
+                                         &d->pci_mmio,
                                          address_space_io,
                                          0, 4);
 
diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c
index fbd443d..69718cf 100644
--- a/hw/ppc_newworld.c
+++ b/hw/ppc_newworld.c
@@ -262,8 +262,6 @@ 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);
 
diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c
index 235d2ef..e127d21 100644
--- a/hw/ppc_oldworld.c
+++ b/hw/ppc_oldworld.c
@@ -207,8 +207,6 @@ 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);
 
diff --git a/hw/unin_pci.c b/hw/unin_pci.c
index 600cd1e..4299052 100644
--- a/hw/unin_pci.c
+++ b/hw/unin_pci.c
@@ -41,6 +41,8 @@ static const int unin_irq_line[] = { 0x1b, 0x1c, 0x1d, 0x1e };
 typedef struct UNINState {
     SysBusDevice busdev;
     PCIHostState host_state;
+    MemoryRegion pci_mmio;
+    MemoryRegion pci_hole;
 } UNINState;
 
 static int pci_unin_map_irq(PCIDevice *pci_dev, int irq_num)
@@ -215,10 +217,16 @@ PCIBus *pci_pmac_init(qemu_irq *pic,
     qdev_init_nofail(dev);
     s = sysbus_from_qdev(dev);
     d = FROM_SYSBUS(UNINState, s);
+    memory_region_init(&d->pci_mmio, "pci-mmio", 0x100000000ULL);
+    memory_region_init_alias(&d->pci_hole, "pci-hole", &d->pci_mmio,
+                             0x80000000ULL, 0x70000000ULL);
+    memory_region_add_subregion(address_space_mem, 0x80000000ULL,
+                                &d->pci_hole);
+
     d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
                                          pci_unin_set_irq, pci_unin_map_irq,
                                          pic,
-                                         address_space_mem,
+                                         &d->pci_mmio,
                                          address_space_io,
                                          PCI_DEVFN(11, 0), 4);
 
@@ -272,10 +280,16 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic,
     s = sysbus_from_qdev(dev);
     d = FROM_SYSBUS(UNINState, s);
 
+    memory_region_init(&d->pci_mmio, "pci-mmio", 0x100000000ULL);
+    memory_region_init_alias(&d->pci_hole, "pci-hole", &d->pci_mmio,
+                             0x80000000ULL, 0x70000000ULL);
+    memory_region_add_subregion(address_space_mem, 0x80000000ULL,
+                                &d->pci_hole);
+
     d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
                                          pci_unin_set_irq, pci_unin_map_irq,
                                          pic,
-                                         address_space_mem,
+                                         &d->pci_mmio,
                                          address_space_io,
                                          PCI_DEVFN(11, 0), 4);
 
commit 3b7653ac48e6d1edfa4ae2496dbefbe422a94eb6
Merge: 4c54661... 12da94f...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon Sep 26 08:00:47 2011 -0500

    Merge remote-tracking branch 'qemu-kvm-tmp/memory/urgent' into staging

commit 4c54661feb0437eab99186a0e462524e18592b9c
Merge: 04970fd... 2f290a8...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon Sep 26 08:00:40 2011 -0500

    Merge remote-tracking branch 'qemu-kvm-tmp/memory/batch' into staging

commit 04970fd9339f75f5d21c094ab816a8e429dc1ff1
Merge: 2f977dd... fb1cd6f...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon Sep 26 08:00:29 2011 -0500

    Merge remote-tracking branch 'qemu-kvm-tmp/memory/core' into staging

commit 2f977dd7e8e31b85f8d5942e25387540ed4fa15e
Merge: 11ddeea... f5f487b...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon Sep 26 08:00:00 2011 -0500

    Merge remote-tracking branch 'pmaydell/omap-for-upstream' into staging

commit 11ddeea91a3b22bd4d4647c732bed32cb6d5112c
Merge: 1ce9ce6... fc9c541...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Mon Sep 26 07:59:13 2011 -0500

    Merge remote-tracking branch 'riku/linux-user-for-upstream' into staging

commit 12da94ff8f847d9e7f13f3cf247d37f3f9dbe1f6
Author: Avi Kivity <avi at redhat.com>
Date:   Sun Sep 25 17:15:43 2011 +0300

    ppc_prep: fix pci config space initialization
    
    Use data_mem for the data mmio region, not conf_mem.
    
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/prep_pci.c b/hw/prep_pci.c
index 55e4e25..149807a 100644
--- a/hw/prep_pci.c
+++ b/hw/prep_pci.c
@@ -130,7 +130,7 @@ PCIBus *pci_prep_init(qemu_irq *pic,
     memory_region_add_subregion(address_space_io, 0xcf8, &s->conf_mem);
     sysbus_init_ioports(&s->busdev, 0xcf8, 1);
 
-    memory_region_init_io(&s->conf_mem, &pci_host_data_be_ops, s,
+    memory_region_init_io(&s->data_mem, &pci_host_data_be_ops, s,
                           "pci-conf-data", 1);
     memory_region_add_subregion(address_space_io, 0xcfc, &s->data_mem);
     sysbus_init_ioports(&s->busdev, 0xcfc, 1);
commit 2f290a8c3db977056e4840810d0dd42032745f21
Author: Richard Henderson <rth at twiddle.net>
Date:   Wed Aug 10 15:28:20 2011 -0700

    fdc: Convert isabus_fdc_init1 to MemoryRegion
    
    This requires some amount of hoop-jumping, so that we don't
    inadvertently claim port 0x3f6, which is used by ISA IDE.
    
    The sysbus initialization path is as yet unconverted.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/fdc.c b/hw/fdc.c
index 433af73..0f1cee9 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -424,6 +424,7 @@ typedef struct FDCtrlSysBus {
 
 typedef struct FDCtrlISABus {
     ISADevice busdev;
+    MemoryRegion io_0, io_7;
     struct FDCtrl state;
     int32_t bootindexA;
     int32_t bootindexB;
@@ -489,16 +490,6 @@ static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value)
     }
 }
 
-static uint32_t fdctrl_read_port (void *opaque, uint32_t reg)
-{
-    return fdctrl_read(opaque, reg & 7);
-}
-
-static void fdctrl_write_port (void *opaque, uint32_t reg, uint32_t value)
-{
-    fdctrl_write(opaque, reg & 7, value);
-}
-
 static uint32_t fdctrl_read_mem (void *opaque, target_phys_addr_t reg)
 {
     return fdctrl_read(opaque, (uint32_t)reg);
@@ -1889,6 +1880,34 @@ static int fdctrl_init_common(FDCtrl *fdctrl)
     return fdctrl_connect_drives(fdctrl);
 }
 
+static uint32_t fdctrl_read_port_7(void *opaque, uint32_t reg)
+{
+    return fdctrl_read(opaque, reg + 7);
+}
+
+static void fdctrl_write_port_7(void *opaque, uint32_t reg, uint32_t value)
+{
+    fdctrl_write(opaque, reg + 7, value);
+}
+
+static const MemoryRegionPortio fdc_portio_0[] = {
+    { 1, 5, 1, .read = fdctrl_read, .write = fdctrl_write },
+    PORTIO_END_OF_LIST()
+};
+
+static const MemoryRegionPortio fdc_portio_7[] = {
+    { 0, 1, 1, .read = fdctrl_read_port_7, .write = fdctrl_write_port_7 },
+    PORTIO_END_OF_LIST()
+};
+
+static const MemoryRegionOps fdc_ioport_0_ops = {
+    .old_portio = fdc_portio_0
+};
+
+static const MemoryRegionOps fdc_ioport_7_ops = {
+    .old_portio = fdc_portio_7
+};
+
 static int isabus_fdc_init1(ISADevice *dev)
 {
     FDCtrlISABus *isa = DO_UPCAST(FDCtrlISABus, busdev, dev);
@@ -1898,16 +1917,10 @@ static int isabus_fdc_init1(ISADevice *dev)
     int dma_chann = 2;
     int ret;
 
-    register_ioport_read(iobase + 0x01, 5, 1,
-                         &fdctrl_read_port, fdctrl);
-    register_ioport_read(iobase + 0x07, 1, 1,
-                         &fdctrl_read_port, fdctrl);
-    register_ioport_write(iobase + 0x01, 5, 1,
-                          &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);
+    memory_region_init_io(&isa->io_0, &fdc_ioport_0_ops, fdctrl, "fdc", 6);
+    memory_region_init_io(&isa->io_7, &fdc_ioport_7_ops, fdctrl, "fdc", 1);
+    isa_register_ioport(dev, &isa->io_0, iobase);
+    isa_register_ioport(dev, &isa->io_7, iobase + 7);
 
     isa_init_irq(&isa->busdev, &fdctrl->irq, isairq);
     fdctrl->dma_chann = dma_chann;
commit a941ae45155d5e78889129183d5dd695329983c0
Author: Richard Henderson <rth at twiddle.net>
Date:   Wed Aug 10 15:28:18 2011 -0700

    serial: Convert serial_isa_initfn to MemoryRegion
    
    The serial_mm_init path is as yet unconverted.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/serial.c b/hw/serial.c
index ed7fd0a..2e6d212 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -157,6 +157,7 @@ struct SerialState {
 
 typedef struct ISASerialState {
     ISADevice dev;
+    MemoryRegion io;
     uint32_t index;
     uint32_t iobase;
     uint32_t isairq;
@@ -755,6 +756,15 @@ void serial_set_frequency(SerialState *s, uint32_t frequency)
 static const int isa_serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
 static const int isa_serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 };
 
+static const MemoryRegionPortio serial_portio[] = {
+    { 0, 8, 1, .read = serial_ioport_read, .write = serial_ioport_write },
+    PORTIO_END_OF_LIST()
+};
+
+static const MemoryRegionOps serial_io_ops = {
+    .old_portio = serial_portio
+};
+
 static int serial_isa_initfn(ISADevice *dev)
 {
     static int index;
@@ -776,9 +786,8 @@ static int serial_isa_initfn(ISADevice *dev)
     serial_init_core(s);
     qdev_set_legacy_instance_id(&dev->qdev, isa->iobase, 3);
 
-    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);
+    memory_region_init_io(&isa->io, &serial_io_ops, s, "serial", 8);
+    isa_register_ioport(dev, &isa->io, isa->iobase);
     return 0;
 }
 
commit dbff76ac330b61ff304f3d188391ec6824b2ed8b
Author: Richard Henderson <rth at twiddle.net>
Date:   Wed Aug 10 15:28:17 2011 -0700

    pckbd: Convert to MemoryRegion
    
    Slightly non-obvious with mips_jazz passing in the region
    structure to populate.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c
index 2b911c7..ea07d32 100644
--- a/hw/mips_jazz.c
+++ b/hw/mips_jazz.c
@@ -115,6 +115,7 @@ static void mips_jazz_init(MemoryRegion *address_space,
     rc4030_dma *dmas;
     void* rc4030_opaque;
     MemoryRegion *rtc = g_new(MemoryRegion, 1);
+    MemoryRegion *i8042 = g_new(MemoryRegion, 1);
     MemoryRegion *dma_dummy = g_new(MemoryRegion, 1);
     NICInfo *nd;
     DeviceState *dev;
@@ -258,7 +259,8 @@ static void mips_jazz_init(MemoryRegion *address_space,
     memory_region_add_subregion(address_space, 0x80004000, rtc);
 
     /* Keyboard (i8042) */
-    i8042_mm_init(rc4030[6], rc4030[7], 0x80005000, 0x1000, 0x1);
+    i8042_mm_init(rc4030[6], rc4030[7], i8042, 0x1000, 0x1);
+    memory_region_add_subregion(address_space, 0x80005000, i8042);
 
     /* Serial ports */
     if (serial_hds[0]) {
diff --git a/hw/pc.h b/hw/pc.h
index 8e75c71..7e6ddba 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -118,7 +118,7 @@ void vmmouse_set_data(const uint32_t *data);
 
 void i8042_init(qemu_irq kbd_irq, qemu_irq mouse_irq, uint32_t io_base);
 void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
-                   target_phys_addr_t base, ram_addr_t size,
+                   MemoryRegion *region, ram_addr_t size,
                    target_phys_addr_t mask);
 void i8042_isa_mouse_fake_event(void *opaque);
 void i8042_setup_a20_line(ISADevice *dev, qemu_irq *a20_out);
diff --git a/hw/pckbd.c b/hw/pckbd.c
index a272ccd..06b40c5 100644
--- a/hw/pckbd.c
+++ b/hw/pckbd.c
@@ -400,33 +400,27 @@ static void kbd_mm_writeb (void *opaque, target_phys_addr_t addr, uint32_t value
         kbd_write_data(s, 0, value & 0xff);
 }
 
-static CPUReadMemoryFunc * const kbd_mm_read[] = {
-    &kbd_mm_readb,
-    &kbd_mm_readb,
-    &kbd_mm_readb,
-};
-
-static CPUWriteMemoryFunc * const kbd_mm_write[] = {
-    &kbd_mm_writeb,
-    &kbd_mm_writeb,
-    &kbd_mm_writeb,
+static const MemoryRegionOps i8042_mmio_ops = {
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .old_mmio = {
+        .read = { kbd_mm_readb, kbd_mm_readb, kbd_mm_readb },
+        .write = { kbd_mm_writeb, kbd_mm_writeb, kbd_mm_writeb },
+    },
 };
 
 void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
-                   target_phys_addr_t base, ram_addr_t size,
+                   MemoryRegion *region, ram_addr_t size,
                    target_phys_addr_t mask)
 {
     KBDState *s = g_malloc0(sizeof(KBDState));
-    int s_io_memory;
 
     s->irq_kbd = kbd_irq;
     s->irq_mouse = 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,
-                                         DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, size, s_io_memory);
+
+    memory_region_init_io(region, &i8042_mmio_ops, s, "i8042", size);
 
     s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
     s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
@@ -435,7 +429,8 @@ void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
 
 typedef struct ISAKBDState {
     ISADevice dev;
-    KBDState  kbd;
+    KBDState kbd;
+    MemoryRegion io[2];
 } ISAKBDState;
 
 void i8042_isa_mouse_fake_event(void *opaque)
@@ -464,19 +459,37 @@ static const VMStateDescription vmstate_kbd_isa = {
     }
 };
 
+static const MemoryRegionPortio i8042_data_portio[] = {
+    { 0, 1, 1, .read = kbd_read_data, .write = kbd_write_data },
+    PORTIO_END_OF_LIST()
+};
+
+static const MemoryRegionPortio i8042_cmd_portio[] = {
+    { 0, 1, 1, .read = kbd_read_status, .write = kbd_write_command },
+    PORTIO_END_OF_LIST()
+};
+
+static const MemoryRegionOps i8042_data_ops = {
+    .old_portio = i8042_data_portio
+};
+
+static const MemoryRegionOps i8042_cmd_ops = {
+    .old_portio = i8042_cmd_portio
+};
+
 static int i8042_initfn(ISADevice *dev)
 {
-    KBDState *s = &(DO_UPCAST(ISAKBDState, dev, dev)->kbd);
+    ISAKBDState *isa_s = DO_UPCAST(ISAKBDState, dev, dev);
+    KBDState *s = &isa_s->kbd;
 
     isa_init_irq(dev, &s->irq_kbd, 1);
     isa_init_irq(dev, &s->irq_mouse, 12);
 
-    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);
+    memory_region_init_io(isa_s->io + 0, &i8042_data_ops, s, "i8042-data", 1);
+    isa_register_ioport(dev, isa_s->io + 0, 0x60);
+
+    memory_region_init_io(isa_s->io + 1, &i8042_cmd_ops, s, "i8042-cmd", 1);
+    isa_register_ioport(dev, isa_s->io + 1, 0x64);
 
     s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
     s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
commit 098d314a3263693ec31e227f4018646e74d439a0
Author: Richard Henderson <rth at twiddle.net>
Date:   Wed Aug 10 15:28:16 2011 -0700

    i8259: Convert to MemoryRegion
    
    The only non-obvious part is pic_poll_read which used
    "addr1 >> 7" to detect whether one referred to either
    the master or slave PIC.  Instead, test this directly.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/i8259.c b/hw/i8259.c
index c0b96ab..e5323ff 100644
--- a/hw/i8259.c
+++ b/hw/i8259.c
@@ -59,6 +59,8 @@ typedef struct PicState {
     uint8_t elcr; /* PIIX edge/trigger selection*/
     uint8_t elcr_mask;
     PicState2 *pics_state;
+    MemoryRegion base_io;
+    MemoryRegion elcr_io;
 } PicState;
 
 struct PicState2 {
@@ -284,13 +286,15 @@ static void pic_reset(void *opaque)
     /* Note: ELCR is not reset */
 }
 
-static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+static void pic_ioport_write(void *opaque, target_phys_addr_t addr64,
+                             uint64_t val64, unsigned size)
 {
     PicState *s = opaque;
+    uint32_t addr = addr64;
+    uint32_t val = val64;
     int priority, cmd, irq;
 
     DPRINTF("write: addr=0x%02x val=0x%02x\n", addr, val);
-    addr &= 1;
     if (addr == 0) {
         if (val & 0x10) {
             /* init */
@@ -374,19 +378,21 @@ static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
     }
 }
 
-static uint32_t pic_poll_read (PicState *s, uint32_t addr1)
+static uint32_t pic_poll_read(PicState *s)
 {
     int ret;
 
     ret = pic_get_irq(s);
     if (ret >= 0) {
-        if (addr1 >> 7) {
+        bool slave = (s == &isa_pic->pics[1]);
+
+        if (slave) {
             s->pics_state->pics[0].isr &= ~(1 << 2);
             s->pics_state->pics[0].irr &= ~(1 << 2);
         }
         s->irr &= ~(1 << ret);
         s->isr &= ~(1 << ret);
-        if (addr1 >> 7 || ret != 2)
+        if (slave || ret != 2)
             pic_update_irq(s->pics_state);
     } else {
         ret = 0x07;
@@ -396,16 +402,15 @@ static uint32_t pic_poll_read (PicState *s, uint32_t addr1)
     return ret;
 }
 
-static uint32_t pic_ioport_read(void *opaque, uint32_t addr1)
+static uint64_t pic_ioport_read(void *opaque, target_phys_addr_t addr1,
+                                unsigned size)
 {
     PicState *s = opaque;
-    unsigned int addr;
+    unsigned int addr = addr1;
     int ret;
 
-    addr = addr1;
-    addr &= 1;
     if (s->poll) {
-        ret = pic_poll_read(s, addr1);
+        ret = pic_poll_read(s);
         s->poll = 0;
     } else {
         if (addr == 0) {
@@ -417,7 +422,7 @@ static uint32_t pic_ioport_read(void *opaque, uint32_t addr1)
             ret = s->imr;
         }
     }
-    DPRINTF("read: addr=0x%02x val=0x%02x\n", addr1, ret);
+    DPRINTF("read: addr=0x%02x val=0x%02x\n", addr, ret);
     return ret;
 }
 
@@ -427,22 +432,24 @@ uint32_t pic_intack_read(PicState2 *s)
 {
     int ret;
 
-    ret = pic_poll_read(&s->pics[0], 0x00);
+    ret = pic_poll_read(&s->pics[0]);
     if (ret == 2)
-        ret = pic_poll_read(&s->pics[1], 0x80) + 8;
+        ret = pic_poll_read(&s->pics[1]) + 8;
     /* Prepare for ISR read */
     s->pics[0].read_reg_select = 1;
 
     return ret;
 }
 
-static void elcr_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+static void elcr_ioport_write(void *opaque, target_phys_addr_t addr,
+                              uint64_t val, unsigned size)
 {
     PicState *s = opaque;
     s->elcr = val & s->elcr_mask;
 }
 
-static uint32_t elcr_ioport_read(void *opaque, uint32_t addr1)
+static uint64_t elcr_ioport_read(void *opaque, target_phys_addr_t addr,
+                                 unsigned size)
 {
     PicState *s = opaque;
     return s->elcr;
@@ -474,15 +481,35 @@ static const VMStateDescription vmstate_pic = {
     }
 };
 
+static const MemoryRegionOps pic_base_ioport_ops = {
+    .read = pic_ioport_read,
+    .write = pic_ioport_write,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static const MemoryRegionOps pic_elcr_ioport_ops = {
+    .read = elcr_ioport_read,
+    .write = elcr_ioport_write,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
 /* XXX: add generic master/slave system */
 static void pic_init1(int io_addr, int elcr_addr, PicState *s)
 {
-    register_ioport_write(io_addr, 2, 1, pic_ioport_write, s);
-    register_ioport_read(io_addr, 2, 1, pic_ioport_read, s);
+    memory_region_init_io(&s->base_io, &pic_base_ioport_ops, s, "pic", 2);
+    memory_region_init_io(&s->elcr_io, &pic_elcr_ioport_ops, s, "elcr", 1);
+
+    isa_register_ioport(NULL, &s->base_io, io_addr);
     if (elcr_addr >= 0) {
-        register_ioport_write(elcr_addr, 1, 1, elcr_ioport_write, s);
-        register_ioport_read(elcr_addr, 1, 1, elcr_ioport_read, s);
+        isa_register_ioport(NULL, &s->elcr_io, elcr_addr);
     }
+
     vmstate_register(NULL, io_addr, &vmstate_pic, s);
     qemu_register_reset(pic_reset, s);
 }
commit bac8ad41ab22880e8318cb9ce27083ce0560000c
Author: Avi Kivity <avi at redhat.com>
Date:   Sun Sep 18 16:13:38 2011 +0300

    ppc_prep: initialize i8259 after the ISA bus
    
    Succeeding i8259 conversion to ISA requires this.
    
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index f9325bd..d26049b 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -648,10 +648,10 @@ static void ppc_prep_init (ram_addr_t ram_size,
     if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) {
         hw_error("Only 6xx bus is supported on PREP machine\n");
     }
-    i8259 = i8259_init(first_cpu->irq_inputs[PPC6xx_INPUT_INT]);
-    pci_bus = pci_prep_init(i8259, get_system_memory(), get_system_io());
     /* Hmm, prep has no pci-isa bridge ??? */
     isa_bus_new(NULL, get_system_io());
+    i8259 = i8259_init(first_cpu->irq_inputs[PPC6xx_INPUT_INT]);
+    pci_bus = pci_prep_init(i8259, get_system_memory(), get_system_io());
     isa_bus_irqs(i8259);
     //    pci_bus = i440fx_init();
     /* Register 8 MB of ISA IO space (needed for non-contiguous map) */
commit a4ac5e64de1b676e0b377792528580065a574815
Author: Avi Kivity <avi at redhat.com>
Date:   Sun Sep 18 16:13:38 2011 +0300

    mips_r4k: initialize i8259 after the ISA bus
    
    Succeeding i8259 conversion to ISA requires this.
    
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c
index a7dc487..d0564d4 100644
--- a/hw/mips_r4k.c
+++ b/hw/mips_r4k.c
@@ -256,8 +256,8 @@ void mips_r4k_init (ram_addr_t ram_size,
     cpu_mips_clock_init(env);
 
     /* The PIC is attached to the MIPS CPU INT0 pin */
-    i8259 = i8259_init(env->irq[2]);
     isa_bus_new(NULL, get_system_io());
+    i8259 = i8259_init(env->irq[2]);
     isa_bus_irqs(i8259);
 
     rtc_init(2000, NULL);
commit e155c99be9439f1fdf245b0b05251f2e225cde62
Author: Avi Kivity <avi at redhat.com>
Date:   Sun Sep 18 16:13:38 2011 +0300

    mips_jazz: initialize i8259 after the ISA bus
    
    Succeeding i8259 conversion to ISA requires this.
    
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c
index e1ac147..2b911c7 100644
--- a/hw/mips_jazz.c
+++ b/hw/mips_jazz.c
@@ -181,8 +181,8 @@ static void mips_jazz_init(MemoryRegion *address_space,
     memory_region_add_subregion(address_space, 0x8000d000, dma_dummy);
 
     /* ISA devices */
-    i8259 = i8259_init(env->irq[4]);
     isa_bus_new(NULL, address_space_io);
+    i8259 = i8259_init(env->irq[4]);
     isa_bus_irqs(i8259);
     cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
     DMA_init(0, cpu_exit_irq);
commit 5632ae46d5bda798e971dae48ebb318ac2c3686a
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Sep 12 13:00:05 2011 +0300

    mips_malta: move i8259 initialization after piix4 initialization
    
    i8259 is an ISA device (or at least, depends on the ISA infrastructure to
    register its ioport); and the ISA bus is supplied by piix4.  Later patches
    make this dependency explicit.
    
    Use qemu_irq_proxy() to stop the cycle by adding an extra layer of
    indirection.
    
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index 0110daa..1ec1228 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -778,7 +778,7 @@ void mips_malta_init (ram_addr_t ram_size,
     int64_t kernel_entry;
     PCIBus *pci_bus;
     CPUState *env;
-    qemu_irq *i8259;
+    qemu_irq *i8259 = NULL, *isa_irq;
     qemu_irq *cpu_exit_irq;
     int piix4_devfn;
     i2c_bus *smbus;
@@ -928,17 +928,27 @@ void mips_malta_init (ram_addr_t ram_size,
     cpu_mips_irq_init_cpu(env);
     cpu_mips_clock_init(env);
 
-    /* Interrupt controller */
-    /* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */
-    i8259 = i8259_init(env->irq[2]);
+    /*
+     * We have a circular dependency problem: pci_bus depends on isa_irq,
+     * isa_irq is provided by i8259, i8259 depends on ISA, ISA depends
+     * on piix4, and piix4 depends on pci_bus.  To stop the cycle we have
+     * qemu_irq_proxy() adds an extra bit of indirection, allowing us
+     * to resolve the isa_irq -> i8259 dependency after i8259 is initialized.
+     */
+    isa_irq = qemu_irq_proxy(&i8259, 16);
 
     /* Northbridge */
-    pci_bus = gt64120_register(i8259);
+    pci_bus = gt64120_register(isa_irq);
 
     /* Southbridge */
     ide_drive_get(hd, MAX_IDE_BUS);
 
     piix4_devfn = piix4_init(pci_bus, 80);
+
+    /* Interrupt controller */
+    /* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */
+    i8259 = i8259_init(env->irq[2]);
+
     isa_bus_irqs(i8259);
     pci_piix4_ide_init(pci_bus, hd, piix4_devfn + 1);
     usb_uhci_piix4_init(pci_bus, piix4_devfn + 2);
commit 60ea6aa8fcf1bc678b13bf8cff5848e0c8eb8430
Author: Richard Henderson <rth at twiddle.net>
Date:   Wed Aug 10 15:28:15 2011 -0700

    i8254: Convert to MemoryRegion
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/i8254.c b/hw/i8254.c
index a9ca9f6..12571ef 100644
--- a/hw/i8254.c
+++ b/hw/i8254.c
@@ -55,6 +55,7 @@ typedef struct PITChannelState {
 
 typedef struct PITState {
     ISADevice dev;
+    MemoryRegion ioports;
     uint32_t irq;
     uint32_t iobase;
     PITChannelState channels[3];
@@ -506,6 +507,16 @@ void hpet_pit_enable(void)
     pit_load_count(s, 0);
 }
 
+static const MemoryRegionPortio pit_portio[] = {
+    { 0, 4, 1, .write = pit_ioport_write },
+    { 0, 3, 1, .read = pit_ioport_read },
+    PORTIO_END_OF_LIST()
+};
+
+static const MemoryRegionOps pit_ioport_ops = {
+    .old_portio = pit_portio
+};
+
 static int pit_initfn(ISADevice *dev)
 {
     PITState *pit = DO_UPCAST(PITState, dev, dev);
@@ -516,9 +527,8 @@ static int pit_initfn(ISADevice *dev)
     s->irq_timer = qemu_new_timer_ns(vm_clock, pit_irq_timer, s);
     s->irq = isa_get_irq(pit->irq);
 
-    register_ioport_write(pit->iobase, 4, 1, pit_ioport_write, pit);
-    register_ioport_read(pit->iobase, 3, 1, pit_ioport_read, pit);
-    isa_init_ioport(dev, pit->iobase);
+    memory_region_init_io(&pit->ioports, &pit_ioport_ops, pit, "pit", 4);
+    isa_register_ioport(dev, &pit->ioports, pit->iobase);
 
     qdev_set_legacy_instance_id(&dev->qdev, pit->iobase, 2);
 
commit beae3979451219e8dc288ae7d7a14e8b438cb5fb
Author: Richard Henderson <rth at twiddle.net>
Date:   Wed Aug 10 15:28:14 2011 -0700

    cs4231a: Convert to MemoryRegion
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/cs4231a.c b/hw/cs4231a.c
index 598f032..e16665e 100644
--- a/hw/cs4231a.c
+++ b/hw/cs4231a.c
@@ -59,6 +59,7 @@ static struct {
 typedef struct CSState {
     ISADevice dev;
     QEMUSoundCard card;
+    MemoryRegion ioports;
     qemu_irq pic;
     uint32_t regs[CS_REGS];
     uint8_t dregs[CS_DREGS];
@@ -74,14 +75,6 @@ typedef struct CSState {
     int16_t *tab;
 } CSState;
 
-#define IO_READ_PROTO(name)                             \
-    static uint32_t name (void *opaque, uint32_t addr)
-
-#define IO_WRITE_PROTO(name)                                            \
-    static void name (void *opaque, uint32_t addr, uint32_t val)
-
-#define GET_SADDR(addr) (addr & 3)
-
 #define MODE2 (1 << 6)
 #define MCE (1 << 6)
 #define PMCE (1 << 4)
@@ -353,12 +346,12 @@ static void cs_reset_voices (CSState *s, uint32_t val)
     }
 }
 
-IO_READ_PROTO (cs_read)
+static uint64_t cs_read(void *opaque, target_phys_addr_t addr, unsigned size)
 {
     CSState *s = opaque;
     uint32_t saddr, iaddr, ret;
 
-    saddr = GET_SADDR (addr);
+    saddr = addr;
     iaddr = ~0U;
 
     switch (saddr) {
@@ -390,12 +383,14 @@ IO_READ_PROTO (cs_read)
     return ret;
 }
 
-IO_WRITE_PROTO (cs_write)
+static void cs_write(void *opaque, target_phys_addr_t addr,
+                     uint64_t val64, unsigned size)
 {
     CSState *s = opaque;
-    uint32_t saddr, iaddr;
+    uint32_t saddr, iaddr, val;
 
-    saddr = GET_SADDR (addr);
+    saddr = addr;
+    val = val64;
 
     switch (saddr) {
     case Index_Address:
@@ -637,18 +632,23 @@ static const VMStateDescription vmstate_cs4231a = {
     }
 };
 
+static const MemoryRegionOps cs_ioport_ops = {
+    .read = cs_read,
+    .write = cs_write,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    }
+};
+
 static int cs4231a_initfn (ISADevice *dev)
 {
     CSState *s = DO_UPCAST (CSState, dev, dev);
-    int i;
 
     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);
-    }
+    memory_region_init_io(&s->ioports, &cs_ioport_ops, s, "cs4231a", 4);
+    isa_register_ioport(dev, &s->ioports, s->port);
 
     DMA_register_channel (s->dma, cs_dma_read, s);
 
commit 4bae1efe63a507b99cad4f8c8b8cf6fa8d203881
Author: Richard Henderson <rth at twiddle.net>
Date:   Wed Aug 10 15:28:13 2011 -0700

    pc: Re-order pc_init1 to initialize the ISA bus before ISA devices
    
    In particular, the i8259 was being initialized before the ISA bus,
    leading to a crash.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 1056cc7..ce1c87f 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -130,17 +130,7 @@ static void pc_init1(MemoryRegion *system_memory,
                        pci_enabled ? rom_memory : system_memory, &ram_memory);
     }
 
-    if (!xen_enabled()) {
-        cpu_irq = pc_allocate_cpu_irq();
-        i8259 = i8259_init(cpu_irq[0]);
-    } else {
-        i8259 = xen_interrupt_controller_init();
-    }
     isa_irq_state = g_malloc0(sizeof(*isa_irq_state));
-    isa_irq_state->i8259 = i8259;
-    if (pci_enabled) {
-        ioapic_init(isa_irq_state);
-    }
     isa_irq = qemu_allocate_irqs(isa_irq_handler, isa_irq_state, 24);
 
     if (pci_enabled) {
@@ -161,6 +151,18 @@ static void pc_init1(MemoryRegion *system_memory,
     }
     isa_bus_irqs(isa_irq);
 
+    if (!xen_enabled()) {
+        cpu_irq = pc_allocate_cpu_irq();
+        i8259 = i8259_init(cpu_irq[0]);
+    } else {
+        i8259 = xen_interrupt_controller_init();
+    }
+
+    isa_irq_state->i8259 = i8259;
+    if (pci_enabled) {
+        ioapic_init(isa_irq_state);
+    }
+
     pc_register_ferr_irq(isa_get_irq(13));
 
     pc_vga_init(pci_enabled? pci_bus: NULL);
commit 78e20593527ce35c5be9d89d686ba9d8e95041b6
Author: Richard Henderson <rth at twiddle.net>
Date:   Wed Aug 10 15:28:12 2011 -0700

    isa: add isa_register_ioport()
    
    To replace isa_init_ioport and isa_init_ioport_range
    as the ISA devices are converted to the memory api.
    
    [avi: use memory_region_size()]
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/isa-bus.c b/hw/isa-bus.c
index d067505..6c15a31 100644
--- a/hw/isa-bus.c
+++ b/hw/isa-bus.c
@@ -108,6 +108,16 @@ void isa_init_ioport(ISADevice *dev, uint16_t ioport)
     isa_init_ioport_range(dev, ioport, 1);
 }
 
+void isa_register_ioport(ISADevice *dev, MemoryRegion *io, uint16_t start)
+{
+    memory_region_add_subregion(isabus->address_space_io, start, io);
+    if (dev != NULL) {
+        assert(dev->nio < ARRAY_SIZE(dev->io));
+        dev->io[dev->nio++] = io;
+        isa_init_ioport_range(dev, start, memory_region_size(io));
+    }
+}
+
 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 390e2d4..432d17a 100644
--- a/hw/isa.h
+++ b/hw/isa.h
@@ -13,10 +13,12 @@ typedef struct ISADeviceInfo ISADeviceInfo;
 
 struct ISADevice {
     DeviceState qdev;
+    MemoryRegion *io[32];
     uint32_t isairq[2];
-    int nirqs;
     uint16_t ioports[32];
+    int nirqs;
     int nioports;
+    int nio;
 };
 
 typedef int (*isa_qdev_initfn)(ISADevice *dev);
@@ -29,6 +31,7 @@ ISABus *isa_bus_new(DeviceState *dev, MemoryRegion *address_space_io);
 void isa_bus_irqs(qemu_irq *irqs);
 qemu_irq isa_get_irq(int isairq);
 void isa_init_irq(ISADevice *dev, qemu_irq *p, int isairq);
+void isa_register_ioport(ISADevice *dev, MemoryRegion *io, uint16_t start);
 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);
commit c2d0d01202e07f87bf17ec9a9f43232c982aa1c2
Author: Richard Henderson <rth at twiddle.net>
Date:   Wed Aug 10 15:28:11 2011 -0700

    isa: Pass i/o address space to isa_bus_new
    
    Not used yet, but at least we're provided with the correct region.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/isa-bus.c b/hw/isa-bus.c
index 1cb497f..d067505 100644
--- a/hw/isa-bus.c
+++ b/hw/isa-bus.c
@@ -24,6 +24,7 @@
 
 struct ISABus {
     BusState qbus;
+    MemoryRegion *address_space_io;
     qemu_irq *irqs;
 };
 static ISABus *isabus;
@@ -39,7 +40,7 @@ static struct BusInfo isa_bus_info = {
     .get_fw_dev_path = isabus_get_fw_dev_path,
 };
 
-ISABus *isa_bus_new(DeviceState *dev)
+ISABus *isa_bus_new(DeviceState *dev, MemoryRegion *address_space_io)
 {
     if (isabus) {
         fprintf(stderr, "Can't create a second ISA bus\n");
@@ -51,6 +52,7 @@ ISABus *isa_bus_new(DeviceState *dev)
     }
 
     isabus = FROM_QBUS(ISABus, qbus_create(&isa_bus_info, dev, NULL));
+    isabus->address_space_io = address_space_io;
     return isabus;
 }
 
diff --git a/hw/isa.h b/hw/isa.h
index f344699..390e2d4 100644
--- a/hw/isa.h
+++ b/hw/isa.h
@@ -25,7 +25,7 @@ struct ISADeviceInfo {
     isa_qdev_initfn init;
 };
 
-ISABus *isa_bus_new(DeviceState *dev);
+ISABus *isa_bus_new(DeviceState *dev, MemoryRegion *address_space_io);
 void isa_bus_irqs(qemu_irq *irqs);
 qemu_irq isa_get_irq(int isairq);
 void isa_init_irq(ISADevice *dev, qemu_irq *p, int isairq);
diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c
index 7cac5da..e1ac147 100644
--- a/hw/mips_jazz.c
+++ b/hw/mips_jazz.c
@@ -102,10 +102,11 @@ static void cpu_request_exit(void *opaque, int irq, int level)
     }
 }
 
-static
-void mips_jazz_init (MemoryRegion *address_space, ram_addr_t ram_size,
-                     const char *cpu_model,
-                     enum jazz_model_e jazz_model)
+static void mips_jazz_init(MemoryRegion *address_space,
+                           MemoryRegion *address_space_io,
+                           ram_addr_t ram_size,
+                           const char *cpu_model,
+                           enum jazz_model_e jazz_model)
 {
     char *filename;
     int bios_size, n;
@@ -181,7 +182,7 @@ void mips_jazz_init (MemoryRegion *address_space, ram_addr_t ram_size,
 
     /* ISA devices */
     i8259 = i8259_init(env->irq[4]);
-    isa_bus_new(NULL);
+    isa_bus_new(NULL, address_space_io);
     isa_bus_irqs(i8259);
     cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
     DMA_init(0, cpu_exit_irq);
@@ -299,7 +300,8 @@ void mips_magnum_init (ram_addr_t ram_size,
                        const char *kernel_filename, const char *kernel_cmdline,
                        const char *initrd_filename, const char *cpu_model)
 {
-    mips_jazz_init(get_system_memory(), ram_size, cpu_model, JAZZ_MAGNUM);
+        mips_jazz_init(get_system_memory(), get_system_io(),
+                       ram_size, cpu_model, JAZZ_MAGNUM);
 }
 
 static
@@ -308,7 +310,8 @@ void mips_pica61_init (ram_addr_t ram_size,
                        const char *kernel_filename, const char *kernel_cmdline,
                        const char *initrd_filename, const char *cpu_model)
 {
-    mips_jazz_init(get_system_memory(), ram_size, cpu_model, JAZZ_PICA61);
+    mips_jazz_init(get_system_memory(), get_system_io(),
+                   ram_size, cpu_model, JAZZ_PICA61);
 }
 
 static QEMUMachine mips_magnum_machine = {
diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c
index 805d02a..a7dc487 100644
--- a/hw/mips_r4k.c
+++ b/hw/mips_r4k.c
@@ -257,7 +257,7 @@ void mips_r4k_init (ram_addr_t ram_size,
 
     /* The PIC is attached to the MIPS CPU INT0 pin */
     i8259 = i8259_init(env->irq[2]);
-    isa_bus_new(NULL);
+    isa_bus_new(NULL, get_system_io());
     isa_bus_irqs(i8259);
 
     rtc_init(2000, NULL);
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 0144534..1056cc7 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -156,7 +156,7 @@ static void pc_init1(MemoryRegion *system_memory,
     } else {
         pci_bus = NULL;
         i440fx_state = NULL;
-        isa_bus_new(NULL);
+        isa_bus_new(NULL, system_io);
         no_hpet = 1;
     }
     isa_bus_irqs(isa_irq);
diff --git a/hw/piix4.c b/hw/piix4.c
index 9590e7b..2fd1171 100644
--- a/hw/piix4.c
+++ b/hw/piix4.c
@@ -87,7 +87,7 @@ static int piix4_initfn(PCIDevice *dev)
 {
     PIIX4State *d = DO_UPCAST(PIIX4State, dev, dev);
 
-    isa_bus_new(&d->dev.qdev);
+    isa_bus_new(&d->dev.qdev, pci_address_space_io(dev));
     piix4_dev = &d->dev;
     qemu_register_reset(piix4_reset, d);
     return 0;
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index 8f6ea42..d183443 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -504,7 +504,7 @@ static int piix3_initfn(PCIDevice *dev)
 {
     PIIX3State *d = DO_UPCAST(PIIX3State, dev, dev);
 
-    isa_bus_new(&d->dev.qdev);
+    isa_bus_new(&d->dev.qdev, pci_address_space_io(dev));
     qemu_register_reset(piix3_reset, d);
     return 0;
 }
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 515de42..f9325bd 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -651,7 +651,7 @@ static void ppc_prep_init (ram_addr_t ram_size,
     i8259 = i8259_init(first_cpu->irq_inputs[PPC6xx_INPUT_INT]);
     pci_bus = pci_prep_init(i8259, get_system_memory(), get_system_io());
     /* Hmm, prep has no pci-isa bridge ??? */
-    isa_bus_new(NULL);
+    isa_bus_new(NULL, get_system_io());
     isa_bus_irqs(i8259);
     //    pci_bus = i440fx_init();
     /* Register 8 MB of ISA IO space (needed for non-contiguous map) */
diff --git a/hw/sun4u.c b/hw/sun4u.c
index 6afb0e7..fbef350 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -548,7 +548,7 @@ pci_ebus_init1(PCIDevice *pci_dev)
 {
     EbusState *s = DO_UPCAST(EbusState, pci_dev, pci_dev);
 
-    isa_bus_new(&pci_dev->qdev);
+    isa_bus_new(&pci_dev->qdev, pci_address_space_io(pci_dev));
 
     pci_dev->config[0x04] = 0x06; // command = bus master, pci mem
     pci_dev->config[0x05] = 0x00;
diff --git a/hw/vt82c686.c b/hw/vt82c686.c
index b9fcc0e..2845959 100644
--- a/hw/vt82c686.c
+++ b/hw/vt82c686.c
@@ -490,7 +490,7 @@ static int vt82c686b_initfn(PCIDevice *d)
     uint8_t *wmask;
     int i;
 
-    isa_bus_new(&d->qdev);
+    isa_bus_new(&d->qdev, pci_address_space_io(d));
 
     pci_conf = d->config;
     pci_config_set_prog_interface(pci_conf, 0x0);
commit e11d64390ba076d8a293e422dad3027f9adb9430
Author: Richard Henderson <rth at twiddle.net>
Date:   Wed Aug 10 15:28:10 2011 -0700

    pci: add pci_address_space_io()
    
    Returns the I/O address space.  Useful for implementing
    PCI-ISA bridge devices.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/pci.c b/hw/pci.c
index 5c4f071..749e8d8 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -2124,3 +2124,8 @@ MemoryRegion *pci_address_space(PCIDevice *dev)
 {
     return dev->bus->address_space_mem;
 }
+
+MemoryRegion *pci_address_space_io(PCIDevice *dev)
+{
+    return dev->bus->address_space_io;
+}
diff --git a/hw/pci.h b/hw/pci.h
index 7b62df1..86a81c8 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -218,6 +218,7 @@ void pci_default_write_config(PCIDevice *d,
 void pci_device_save(PCIDevice *s, QEMUFile *f);
 int pci_device_load(PCIDevice *s, QEMUFile *f);
 MemoryRegion *pci_address_space(PCIDevice *dev);
+MemoryRegion *pci_address_space_io(PCIDevice *dev);
 
 typedef void (*pci_set_irq_fn)(void *opaque, int irq_num, int level);
 typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num);
commit fb1cd6f998fe7dba889e5c77962f94bb1a15d202
Author: Avi Kivity <avi at redhat.com>
Date:   Sun Sep 25 14:48:47 2011 +0300

    memory: implement memory_region_set_readonly()
    
    The property is inheritable, but only if set to true.  This is so
    that memory routers can mark sections of RAM as read-only via aliases.
    
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/memory.c b/memory.c
index ba74435..71e769e 100644
--- a/memory.c
+++ b/memory.c
@@ -126,6 +126,7 @@ struct FlatRange {
     AddrRange addr;
     uint8_t dirty_log_mask;
     bool readable;
+    bool readonly;
 };
 
 /* Flattened global view of current active memory hierarchy.  Kept in sorted
@@ -166,7 +167,8 @@ static bool flatrange_equal(FlatRange *a, FlatRange *b)
     return a->mr == b->mr
         && addrrange_equal(a->addr, b->addr)
         && a->offset_in_region == b->offset_in_region
-        && a->readable == b->readable;
+        && a->readable == b->readable
+        && a->readonly == b->readonly;
 }
 
 static void flatview_init(FlatView *view)
@@ -203,7 +205,8 @@ static bool can_merge(FlatRange *r1, FlatRange *r2)
         && r1->mr == r2->mr
         && r1->offset_in_region + r1->addr.size == r2->offset_in_region
         && r1->dirty_log_mask == r2->dirty_log_mask
-        && r1->readable == r2->readable;
+        && r1->readable == r2->readable
+        && r1->readonly == r2->readonly;
 }
 
 /* Attempt to simplify a view by merging ajacent ranges */
@@ -307,6 +310,10 @@ static void as_memory_range_add(AddressSpace *as, FlatRange *fr)
         phys_offset &= ~TARGET_PAGE_MASK & ~IO_MEM_ROMD;
     }
 
+    if (fr->readonly) {
+        phys_offset |= IO_MEM_ROM;
+    }
+
     cpu_register_physical_memory_log(fr->addr.start,
                                      fr->addr.size,
                                      phys_offset,
@@ -484,7 +491,8 @@ static AddressSpace address_space_io = {
 static void render_memory_region(FlatView *view,
                                  MemoryRegion *mr,
                                  target_phys_addr_t base,
-                                 AddrRange clip)
+                                 AddrRange clip,
+                                 bool readonly)
 {
     MemoryRegion *subregion;
     unsigned i;
@@ -495,6 +503,7 @@ static void render_memory_region(FlatView *view,
     AddrRange tmp;
 
     base += mr->addr;
+    readonly |= mr->readonly;
 
     tmp = addrrange_make(base, mr->size);
 
@@ -507,13 +516,13 @@ static void render_memory_region(FlatView *view,
     if (mr->alias) {
         base -= mr->alias->addr;
         base -= mr->alias_offset;
-        render_memory_region(view, mr->alias, base, clip);
+        render_memory_region(view, mr->alias, base, clip, readonly);
         return;
     }
 
     /* Render subregions in priority order. */
     QTAILQ_FOREACH(subregion, &mr->subregions, subregions_link) {
-        render_memory_region(view, subregion, base, clip);
+        render_memory_region(view, subregion, base, clip, readonly);
     }
 
     if (!mr->terminates) {
@@ -536,6 +545,7 @@ static void render_memory_region(FlatView *view,
             fr.addr = addrrange_make(base, now);
             fr.dirty_log_mask = mr->dirty_log_mask;
             fr.readable = mr->readable;
+            fr.readonly = readonly;
             flatview_insert(view, i, &fr);
             ++i;
             base += now;
@@ -555,6 +565,7 @@ static void render_memory_region(FlatView *view,
         fr.addr = addrrange_make(base, remain);
         fr.dirty_log_mask = mr->dirty_log_mask;
         fr.readable = mr->readable;
+        fr.readonly = readonly;
         flatview_insert(view, i, &fr);
     }
 }
@@ -566,7 +577,7 @@ static FlatView generate_memory_topology(MemoryRegion *mr)
 
     flatview_init(&view);
 
-    render_memory_region(&view, mr, 0, addrrange_make(0, INT64_MAX));
+    render_memory_region(&view, mr, 0, addrrange_make(0, INT64_MAX), false);
     flatview_simplify(&view);
 
     return view;
@@ -772,6 +783,7 @@ void memory_region_init(MemoryRegion *mr,
     mr->offset = 0;
     mr->terminates = false;
     mr->readable = true;
+    mr->readonly = false;
     mr->destructor = memory_region_destructor_none;
     mr->priority = 0;
     mr->may_overlap = false;
@@ -1035,7 +1047,10 @@ void memory_region_sync_dirty_bitmap(MemoryRegion *mr)
 
 void memory_region_set_readonly(MemoryRegion *mr, bool readonly)
 {
-    /* FIXME */
+    if (mr->readonly != readonly) {
+        mr->readonly = readonly;
+        memory_region_update_topology();
+    }
 }
 
 void memory_region_rom_device_set_readable(MemoryRegion *mr, bool readable)
diff --git a/memory.h b/memory.h
index 06b83ae..e93e65a 100644
--- a/memory.h
+++ b/memory.h
@@ -114,6 +114,7 @@ struct MemoryRegion {
     IORange iorange;
     bool terminates;
     bool readable;
+    bool readonly; /* For RAM regions */
     MemoryRegion *alias;
     target_phys_addr_t alias_offset;
     unsigned priority;
commit 1ce9ce6a6184f0192015ba9adf1123d89cd47a7b
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Tue Sep 20 16:18:46 2011 +0100

    MAINTAINERS: update maintainer for target-arm and ARM devboards
    
    Add myself as co-maintainer alongside Paul Brook for the TCG ARM
    guest implementation (target-arm) and the ARM dev boards (integratorcp,
    realview, stellaris, versatilepb).
    
    Acked-by: Edgar E. Iglesias <edgar.iglesias at gmail.com>
    Acked-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/MAINTAINERS b/MAINTAINERS
index 7c5ea87..d034ce4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -62,6 +62,7 @@ F: target-alpha/
 
 ARM
 M: Paul Brook <paul at codesourcery.com>
+M: Peter Maydell <peter.maydell at linaro.org>
 S: Maintained
 F: target-arm/
 
@@ -168,6 +169,7 @@ F: hw/gumstix.c
 
 Integrator CP
 M: Paul Brook <paul at codesourcery.com>
+M: Peter Maydell <peter.maydell at linaro.org>
 S: Maintained
 F: hw/integratorcp.c
 
@@ -193,6 +195,7 @@ F: hw/palm.c
 
 Real View
 M: Paul Brook <paul at codesourcery.com>
+M: Peter Maydell <peter.maydell at linaro.org>
 S: Maintained
 F: hw/realview*
 
@@ -203,11 +206,13 @@ F: hw/spitz.c
 
 Stellaris
 M: Paul Brook <paul at codesourcery.com>
+M: Peter Maydell <peter.maydell at linaro.org>
 S: Maintained
 F: hw/stellaris.c
 
 Versatile PB
 M: Paul Brook <paul at codesourcery.com>
+M: Peter Maydell <peter.maydell at linaro.org>
 S: Maintained
 F: hw/versatilepb.c
 
commit 63467ddb616f3c94e1c689adce2817f138b80ffd
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Fri Sep 16 15:40:16 2011 +0100

    Makefile: Remove 'tarbin' target
    
    Remove the 'tarbin' target -- it isn't used as part of the official
    QEMU release process, and it's out of date (various new bios files
    were never added to its list of files). It's better not to provide
    it at all than to have a broken makefile target we never use or test.
    
    (Creating a tarball by just pulling in binaries that have been installed
    directly to the system you're running the build on is a bad idea anyway:
    the better way to create a binary tarball would be just to install to
    a temporary DESTDIR and then tar up that.)
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/Makefile b/Makefile
index a211158..6ed3194 100644
--- a/Makefile
+++ b/Makefile
@@ -368,41 +368,5 @@ tar:
 	cd /tmp && tar zcvf ~/$(FILE).tar.gz $(FILE) --exclude CVS --exclude .git --exclude .svn
 	rm -rf /tmp/$(FILE)
 
-SYSTEM_TARGETS=$(filter %-softmmu,$(TARGET_DIRS))
-SYSTEM_PROGS=$(patsubst %-softmmu,qemu-system-%, \
-             $(SYSTEM_TARGETS))
-
-USER_TARGETS=$(filter %-user,$(TARGET_DIRS))
-USER_PROGS=$(patsubst %-bsd-user,qemu-%, \
-           $(patsubst %-darwin-user,qemu-%, \
-           $(patsubst %-linux-user,qemu-%, \
-           $(USER_TARGETS))))
-
-# generate a binary distribution
-tarbin:
-	cd / && tar zcvf ~/qemu-$(VERSION)-$(ARCH).tar.gz \
-	$(patsubst %,$(bindir)/%, $(SYSTEM_PROGS)) \
-	$(patsubst %,$(bindir)/%, $(USER_PROGS)) \
-	$(bindir)/qemu-img \
-	$(bindir)/qemu-nbd \
-	$(datadir)/bios.bin \
-	$(datadir)/vgabios.bin \
-	$(datadir)/vgabios-cirrus.bin \
-	$(datadir)/ppc_rom.bin \
-	$(datadir)/openbios-sparc32 \
-	$(datadir)/openbios-sparc64 \
-	$(datadir)/openbios-ppc \
-	$(datadir)/pxe-e1000.rom \
-	$(datadir)/pxe-eepro100.rom \
-	$(datadir)/pxe-ne2k_pci.rom \
-	$(datadir)/pxe-pcnet.rom \
-	$(datadir)/pxe-rtl8139.rom \
-	$(datadir)/pxe-virtio.rom \
-	$(docdir)/qemu-doc.html \
-	$(docdir)/qemu-tech.html \
-	$(mandir)/man1/qemu.1 \
-	$(mandir)/man1/qemu-img.1 \
-	$(mandir)/man8/qemu-nbd.8
-
 # Include automatically generated dependency files
 -include $(wildcard *.d audio/*.d slirp/*.d block/*.d net/*.d ui/*.d qapi/*.d qga/*.d)
commit 069c159e3935daea714f7b77bbe5f20bd99c4445
Author: Marcelo Tosatti <mtosatti at redhat.com>
Date:   Fri Sep 16 18:19:55 2011 -0300

    qemu-char: use qemu_set_fd_handler/2 consistently
    
    Now that qemu_set_fd_handler and qemu_set_fd_handler2 have different
    implementations, one using qemu iohandlers and the other glib, it is not
    safe to mix the two when inserting/deleting handlers.
    
    Fixes kvm-autotest.
    
    Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/qemu-char.c b/qemu-char.c
index c9e5c41..09d2309 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -1881,7 +1881,7 @@ static void udp_chr_close(CharDriverState *chr)
 {
     NetCharDriver *s = chr->opaque;
     if (s->fd >= 0) {
-        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+        qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
         closesocket(s->fd);
     }
     g_free(s);
@@ -2093,9 +2093,9 @@ static void tcp_chr_read(void *opaque)
         /* connection closed */
         s->connected = 0;
         if (s->listen_fd >= 0) {
-            qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
+            qemu_set_fd_handler2(s->listen_fd, NULL, tcp_chr_accept, NULL, chr);
         }
-        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+        qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
         closesocket(s->fd);
         s->fd = -1;
         qemu_chr_event(chr, CHR_EVENT_CLOSED);
@@ -2156,7 +2156,7 @@ static int tcp_chr_add_client(CharDriverState *chr, int fd)
     if (s->do_nodelay)
         socket_set_nodelay(fd);
     s->fd = fd;
-    qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
+    qemu_set_fd_handler2(s->listen_fd, NULL, NULL, NULL, NULL);
     tcp_chr_connect(chr);
 
     return 0;
@@ -2202,11 +2202,11 @@ static void tcp_chr_close(CharDriverState *chr)
 {
     TCPCharDriver *s = chr->opaque;
     if (s->fd >= 0) {
-        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+        qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
         closesocket(s->fd);
     }
     if (s->listen_fd >= 0) {
-        qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
+        qemu_set_fd_handler2(s->listen_fd, NULL, NULL, NULL, NULL);
         closesocket(s->listen_fd);
     }
     g_free(s);
@@ -2272,7 +2272,7 @@ static int qemu_chr_open_socket(QemuOpts *opts, CharDriverState **_chr)
 
     if (is_listen) {
         s->listen_fd = fd;
-        qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
+        qemu_set_fd_handler2(s->listen_fd, NULL, tcp_chr_accept, NULL, chr);
         if (is_telnet)
             s->do_telnetopt = 1;
 
commit e8beeae4c0f42de9f72dcd7ba156dbb99ab4cc4c
Author: Hervé Poussineau <hpoussin at reactos.org>
Date:   Sun Sep 18 16:27:23 2011 +0200

    adlib: remove write-only variable
    
    Signed-off-by: Hervé Poussineau <hpoussin at reactos.org>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/adlib.c b/hw/adlib.c
index c1c46e3..e4bfcc6 100644
--- a/hw/adlib.c
+++ b/hw/adlib.c
@@ -119,7 +119,6 @@ static IO_WRITE_PROTO (adlib_write)
 {
     AdlibState *s = opaque;
     int a = nport & 3;
-    int status;
 
     s->active = 1;
     AUD_set_active_out (s->voice, 1);
@@ -127,9 +126,9 @@ static IO_WRITE_PROTO (adlib_write)
     adlib_kill_timers (s);
 
 #ifdef HAS_YMF262
-    status = YMF262Write (0, a, val);
+    YMF262Write (0, a, val);
 #else
-    status = OPLWrite (s->opl, a, val);
+    OPLWrite (s->opl, a, val);
 #endif
 }
 
commit 22ec3283efba9ba0792790da786d6776d83f2a92
Author: Avi Kivity <avi at redhat.com>
Date:   Sun Sep 18 15:58:26 2011 +0300

    irq: introduce qemu_irq_proxy()
    
    In some cases we have a circular dependency involving irqs - the irq
    controller depends on a bus, which in turn depends on the irq controller.
    Add qemu_irq_proxy() which acts as a passthrough, except that the target
    irq may be set later on.
    
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/irq.c b/hw/irq.c
index 60eabe8..62f766e 100644
--- a/hw/irq.c
+++ b/hw/irq.c
@@ -90,3 +90,17 @@ qemu_irq qemu_irq_split(qemu_irq irq1, qemu_irq irq2)
     s[1] = irq2;
     return qemu_allocate_irqs(qemu_splitirq, s, 1)[0];
 }
+
+static void proxy_irq_handler(void *opaque, int n, int level)
+{
+    qemu_irq **target = opaque;
+
+    if (*target) {
+        qemu_set_irq((*target)[n], level);
+    }
+}
+
+qemu_irq *qemu_irq_proxy(qemu_irq **target, int n)
+{
+    return qemu_allocate_irqs(proxy_irq_handler, target, n);
+}
diff --git a/hw/irq.h b/hw/irq.h
index 389ed7a..64da2fd 100644
--- a/hw/irq.h
+++ b/hw/irq.h
@@ -33,4 +33,9 @@ qemu_irq qemu_irq_invert(qemu_irq irq);
 /* Returns a new IRQ which feeds into both the passed IRQs */
 qemu_irq qemu_irq_split(qemu_irq irq1, qemu_irq irq2);
 
+/* Returns a new IRQ set which connects 1:1 to another IRQ set, which
+ * may be set later.
+ */
+qemu_irq *qemu_irq_proxy(qemu_irq **target, int n);
+
 #endif
commit e22517086bbdf8d09de2b9ba8b3dfa4c42ec0f6c
Author: David Gibson <david at gibson.dropbear.id.au>
Date:   Tue Sep 20 12:05:21 2011 +1000

    Barriers in qemu-barrier.h should not be x86 specific
    
    qemu-barrier.h contains a few macros implementing memory barrier
    primitives used in several places throughout qemu.  However, apart
    from the compiler-only barrier, the defined wmb() is correct only for
    x86, or platforms which are similarly strongly ordered.
    
    This patch addresses the FIXME about this by making the wmb() macro
    arch dependent.  On x86, it remains a compiler barrier only, but with
    a comment explaining in more detail the conditions under which this is
    correct.  On weakly-ordered powerpc, an "eieio" instruction is used,
    again with explanation of the conditions under which it is sufficient.
    
    On other platforms, we use the __sync_synchronize() primitive,
    available in sufficiently recent gcc (4.2 and after?).  This should
    implement a full barrier which will be sufficient on all platforms,
    although it may be overkill in some cases.  Other platforms can add
    optimized versions in future if it's worth it for them.
    
    Without proper memory barriers, it is easy to reproduce ordering
    problems with virtio on powerpc; specifically, the QEMU puts new
    element into the "used" ring and then updates the ring free-running
    counter.  Without a barrier between these under the right
    circumstances, the guest linux driver can receive an interrupt, read
    the counter change but find the ring element to be handled still has
    an old value, leading to an "id %u is not a head!\n" error message.
    Similar problems are likely to be possible with kvm on other weakly
    ordered platforms.
    
    Signed-off-by: Alexey Kardashevskiy <aik at ozlabs.ru>
    Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/qemu-barrier.h b/qemu-barrier.h
index b77fce2..735eea6 100644
--- a/qemu-barrier.h
+++ b/qemu-barrier.h
@@ -1,10 +1,38 @@
 #ifndef __QEMU_BARRIER_H
 #define __QEMU_BARRIER_H 1
 
-/* FIXME: arch dependant, x86 version */
-#define smp_wmb()   asm volatile("" ::: "memory")
-
 /* Compiler barrier */
 #define barrier()   asm volatile("" ::: "memory")
 
+#if defined(__i386__) || defined(__x86_64__)
+
+/*
+ * Because of the strongly ordered x86 storage model, wmb() is a nop
+ * on x86(well, a compiler barrier only).  Well, at least as long as
+ * qemu doesn't do accesses to write-combining memory or non-temporal
+ * load/stores from C code.
+ */
+#define smp_wmb()   barrier()
+
+#elif defined(__powerpc__)
+
+/*
+ * We use an eieio() for a wmb() on powerpc.  This assumes we don't
+ * need to order cacheable and non-cacheable stores with respect to
+ * each other
+ */
+#define smp_wmb()   asm volatile("eieio" ::: "memory")
+
+#else
+
+/*
+ * For (host) platforms we don't have explicit barrier definitions
+ * for, we use the gcc __sync_synchronize() primitive to generate a
+ * full barrier.  This should be safe on all platforms, though it may
+ * be overkill.
+ */
+#define smp_wmb()   __sync_synchronize()
+
+#endif
+
 #endif
commit b90d2f35125490b8f62484c5ea7e6bbecbe43b6f
Author: David Gibson <david at gibson.dropbear.id.au>
Date:   Tue Sep 20 12:05:20 2011 +1000

    virtio: Use global memory barrier macros
    
    The virtio code uses wmb() macros in several places, as required by the
    SMP-aware virtio protocol.  However the wmb() macro is locally defined
    to be a compiler barrier only.  This is probably sufficient on x86
    due to its strong storage ordering model, but it certainly isn't on other
    platforms, such as ppc.
    
    In any case, qemu already has some globally defined memory barrier macros
    in qemu-barrier.h.  This patch, therefore converts virtio.c to use those
    barrier macros.  The macros in qemu-barrier.h are also wrong (or at least,
    safe for x86 only) but this way at least there's only one place to fix
    them.
    
    Signed-off-by: Alexey Kardashevskiy <aik at ozlabs.ru>
    Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
    Signed-off-by: Alexey Kardashevskiy <aik at ozlabs.ru>
    Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/virtio.c b/hw/virtio.c
index d9bf266..7011b5b 100644
--- a/hw/virtio.c
+++ b/hw/virtio.c
@@ -16,20 +16,12 @@
 #include "trace.h"
 #include "qemu-error.h"
 #include "virtio.h"
+#include "qemu-barrier.h"
 
 /* The alignment to use between consumer and producer parts of vring.
  * x86 pagesize again. */
 #define VIRTIO_PCI_VRING_ALIGN         4096
 
-/* QEMU doesn't strictly need write barriers since everything runs in
- * lock-step.  We'll leave the calls to wmb() in though to make it obvious for
- * KVM or if kqemu gets SMP support.
- * In any case, we must prevent the compiler from reordering the code.
- * TODO: we likely need some rmb()/mb() as well.
- */
-
-#define wmb() __asm__ __volatile__("": : :"memory")
-
 typedef struct VRingDesc
 {
     uint64_t addr;
@@ -264,7 +256,7 @@ void virtqueue_flush(VirtQueue *vq, unsigned int count)
 {
     uint16_t old, new;
     /* Make sure buffer is written before we update index. */
-    wmb();
+    smp_wmb();
     trace_virtqueue_flush(vq, count);
     old = vring_used_idx(vq);
     new = old + count;
@@ -324,7 +316,7 @@ static unsigned virtqueue_next_desc(target_phys_addr_t desc_pa,
     /* Check they're not leading us off end of descriptors. */
     next = vring_desc_next(desc_pa, i);
     /* Make sure compiler knows to grab that: we don't want it changing! */
-    wmb();
+    smp_wmb();
 
     if (next >= max) {
         error_report("Desc next is %u", next);
commit 87751797c707092108700159b570e917bae346b9
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Fri Sep 16 22:03:08 2011 +0200

    Fix and clean code which tests the gcc version
    
    The code which tests whether gcc supports warn_unused_result was wrong.
    Remove the wrong test from configure and replace it by code using
    macro QEMU_GNUC_PREREQ in compiler.h.
    
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/compiler.h b/compiler.h
index 3a9b8a1..a1c0794 100644
--- a/compiler.h
+++ b/compiler.h
@@ -18,7 +18,7 @@
 
 #define QEMU_NORETURN __attribute__ ((__noreturn__))
 
-#ifdef CONFIG_GCC_ATTRIBUTE_WARN_UNUSED_RESULT
+#if QEMU_GNUC_PREREQ(3, 4)
 #define QEMU_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
 #else
 #define QEMU_WARN_UNUSED_RESULT
diff --git a/configure b/configure
index 8507846..24b8df4 100755
--- a/configure
+++ b/configure
@@ -2359,23 +2359,6 @@ if compile_prog "" "" ; then
     need_offsetof=no
 fi
 
-##########################################
-# check if the compiler understands attribute warn_unused_result
-#
-# This could be smarter, but gcc -Werror does not error out even when warning
-# about attribute warn_unused_result
-
-gcc_attribute_warn_unused_result=no
-cat > $TMPC << EOF
-#if defined(__GNUC__) && (__GNUC__ < 4) && defined(__GNUC_MINOR__) && (__GNUC__ < 4)
-#error gcc 3.3 or older
-#endif
-int main(void) { return 0;}
-EOF
-if compile_prog "" ""; then
-    gcc_attribute_warn_unused_result=yes
-fi
-
 # spice probe
 if test "$spice" != "no" ; then
   cat > $TMPC << EOF
@@ -2998,9 +2981,6 @@ fi
 if test "$need_offsetof" = "yes" ; then
   echo "CONFIG_NEED_OFFSETOF=y" >> $config_host_mak
 fi
-if test "$gcc_attribute_warn_unused_result" = "yes" ; then
-  echo "CONFIG_GCC_ATTRIBUTE_WARN_UNUSED_RESULT=y" >> $config_host_mak
-fi
 if test "$fdatasync" = "yes" ; then
   echo "CONFIG_FDATASYNC=y" >> $config_host_mak
 fi
commit f8b72754c21789293eb655641459ab43ebd69c66
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Fri Sep 16 22:03:07 2011 +0200

    Move macro QEMU_GNUC_PREREQ to compiler.h
    
    The macro is compiler specific and does not depend on the operating system.
    
    Move macro QEMU_GNUC_PREREQ from osdep.h to compiler.h
    and use it to simplify existing code.
    
    host-utils.h uses this macro, so it now needs compiler.h
    instead of osdep.h.
    
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/compiler.h b/compiler.h
index a2d5959..3a9b8a1 100644
--- a/compiler.h
+++ b/compiler.h
@@ -5,7 +5,19 @@
 
 #include "config-host.h"
 
+/*----------------------------------------------------------------------------
+| The macro QEMU_GNUC_PREREQ tests for minimum version of the GNU C compiler.
+| The code is a copy of SOFTFLOAT_GNUC_PREREQ, see softfloat-macros.h.
+*----------------------------------------------------------------------------*/
+#if defined(__GNUC__) && defined(__GNUC_MINOR__)
+# define QEMU_GNUC_PREREQ(maj, min) \
+         ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
+#else
+# define QEMU_GNUC_PREREQ(maj, min) 0
+#endif
+
 #define QEMU_NORETURN __attribute__ ((__noreturn__))
+
 #ifdef CONFIG_GCC_ATTRIBUTE_WARN_UNUSED_RESULT
 #define QEMU_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
 #else
@@ -22,8 +34,7 @@
     typedef char qemu_build_bug_on__##__LINE__[(x)?-1:1];
 
 #if defined __GNUC__
-# if (__GNUC__ < 4) || \
-     defined(__GNUC_MINOR__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 4)
+# if !QEMU_GNUC_PREREQ(4, 4)
    /* gcc versions before 4.4.x don't support gnu_printf, so use printf. */
 #  define GCC_ATTR __attribute__((__unused__, format(printf, 1, 2)))
 #  define GCC_FMT_ATTR(n, m) __attribute__((format(printf, n, m)))
diff --git a/host-utils.h b/host-utils.h
index 0ddc176..821db93 100644
--- a/host-utils.h
+++ b/host-utils.h
@@ -23,7 +23,7 @@
  * THE SOFTWARE.
  */
 
-#include "osdep.h"
+#include "compiler.h"   /* QEMU_GNUC_PREREQ */
 
 #if defined(__x86_64__)
 #define __HAVE_FAST_MULU64__
diff --git a/osdep.h b/osdep.h
index 252d050..432b91e 100644
--- a/osdep.h
+++ b/osdep.h
@@ -81,13 +81,6 @@
 
 #define qemu_printf printf
 
-#if defined (__GNUC__) && defined (__GNUC_MINOR__)
-# define QEMU_GNUC_PREREQ(maj, min) \
-         ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
-#else
-# define QEMU_GNUC_PREREQ(maj, min) 0
-#endif
-
 int qemu_daemon(int nochdir, int noclose);
 void *qemu_memalign(size_t alignment, size_t size);
 void *qemu_vmalloc(size_t size);
commit ffe3ce1173e71ca299d08f6542839cc31ea3e3cf
Author: Donald Dutile <ddutile at redhat.com>
Date:   Wed Sep 21 15:25:11 2011 -0400

    pci-devfn: check that device/slot number is within range
    
    Need to check that guest slot/device number is not > 31 or walk off
    the devfn table when checking if a devfn is available or not in a guest.
    
    before this fix, passing in an addr=abc  or addr=34,
    can crash qemu, sometimes fail gracefully if data past end
    of devfn table fails the availability test.
    
    with this fix, get clean error:
    Property 'pci-assign.addr' doesn't take value '34'
    
    also tested when no addr= param passed for guest (pcicfg) address,
    and that worked as well.
    
    Signed-off-by: Don Dutile <ddutile at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index 7ce95b6..e0e54aa 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -524,6 +524,8 @@ static int parse_pci_devfn(DeviceState *dev, Property *prop, const char *str)
         return -EINVAL;
     if (fn > 7)
         return -EINVAL;
+    if (slot > 31)
+        return -EINVAL;
     *ptr = slot << 3 | fn;
     return 0;
 }
commit c1d23eaccc5020bb546a4391a0b2abf8ee861923
Author: Hervé Poussineau <hpoussin at reactos.org>
Date:   Sun Sep 18 18:04:51 2011 +0200

    isapc: give system address space when pci is disabled
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Hervé Poussineau <hpoussin at reactos.org>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index ec7da6d..0144534 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -127,7 +127,7 @@ static void pc_init1(MemoryRegion *system_memory,
         pc_memory_init(system_memory,
                        kernel_filename, kernel_cmdline, initrd_filename,
                        below_4g_mem_size, above_4g_mem_size,
-                       rom_memory, &ram_memory);
+                       pci_enabled ? rom_memory : system_memory, &ram_memory);
     }
 
     if (!xen_enabled()) {
commit e098fc3fd2a5c9be6b38f6f54bd466f218b7c4e9
Author: Michael Roth <mdroth at linux.vnet.ibm.com>
Date:   Wed Sep 7 18:40:52 2011 -0500

    build: fix race with creating qapi-generated
    
    Since qapi-generated/ is a global QEMU include path, we need to make
    sure it is created before anything is compiled, so do this in the
    configure phase rather than via the Makefile.
    
    Signed-off-by: Michael Roth <mdroth at linux.vnet.ibm.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/configure b/configure
index 9ab3ab4..8507846 100755
--- a/configure
+++ b/configure
@@ -3622,7 +3622,7 @@ DIRS="tests tests/cris slirp audio block net pc-bios/optionrom"
 DIRS="$DIRS pc-bios/spapr-rtas"
 DIRS="$DIRS roms/seabios roms/vgabios"
 DIRS="$DIRS fsdev ui"
-DIRS="$DIRS qapi"
+DIRS="$DIRS qapi qapi-generated"
 DIRS="$DIRS qga trace"
 FILES="Makefile tests/Makefile qdict-test-data.txt"
 FILES="$FILES tests/cris/Makefile tests/cris/.gdbinit"
commit 4c08fd1e42a886bccc02e5fe18e98b948c252986
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Wed Sep 21 20:49:32 2011 +0200

    cirrus: Unbreak ISA support
    
    Do not try to map against the PCI bar in the ISA version of the device.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index ec7ea82..c7e365b 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -2401,7 +2401,7 @@ static void map_linear_vram_bank(CirrusVGAState *s, unsigned bank)
 
 static void map_linear_vram(CirrusVGAState *s)
 {
-    if (!s->linear_vram) {
+    if (s->bustype == CIRRUS_BUSTYPE_PCI && !s->linear_vram) {
         s->linear_vram = true;
         memory_region_add_subregion_overlap(&s->pci_bar, 0, &s->vga.vram, 1);
     }
@@ -2411,7 +2411,7 @@ static void map_linear_vram(CirrusVGAState *s)
 
 static void unmap_linear_vram(CirrusVGAState *s)
 {
-    if (s->linear_vram) {
+    if (s->bustype == CIRRUS_BUSTYPE_PCI && s->linear_vram) {
         s->linear_vram = false;
         memory_region_del_subregion(&s->pci_bar, &s->vga.vram);
     }
commit 53d6e682552c981207a38f6c794c47320e95e0d0
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Wed Sep 21 20:49:31 2011 +0200

    vga: Unbreak ISA support
    
    We need to initialize legacy_address_space during ISA VGA setup so that
    the chain-4 alias can be registered properly.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/vga-isa.c b/hw/vga-isa.c
index 0d19901..6b5c8ed 100644
--- a/hw/vga-isa.c
+++ b/hw/vga-isa.c
@@ -49,6 +49,7 @@ static int vga_initfn(ISADevice *dev)
     MemoryRegion *vga_io_memory;
 
     vga_common_init(s, VGA_RAM_SIZE);
+    s->legacy_address_space = isa_address_space(dev);
     vga_io_memory = vga_init_io(s);
     memory_region_add_subregion_overlap(isa_address_space(dev),
                                         isa_mem_base + 0x000a0000,
commit 57285cc3c6275d6fd2397e4a3fa077786f03b6f3
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Wed Sep 21 20:49:30 2011 +0200

    pc: Disable HPET for ISA machine
    
    There was no HPET on ISA boxes.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 52939f5..ec7da6d 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -157,6 +157,7 @@ static void pc_init1(MemoryRegion *system_memory,
         pci_bus = NULL;
         i440fx_state = NULL;
         isa_bus_new(NULL);
+        no_hpet = 1;
     }
     isa_bus_irqs(isa_irq);
 
commit 4463aee630685a6ac595b1acc777536f0a41d02d
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Wed Sep 21 20:49:29 2011 +0200

    pc: Unbreak ROM mapping for ISA machine
    
    This is based on the original fix by Hervé Poussineau: pc_memory_init
    actually takes a memory region for mapping BIOS and extension ROMs. That
    equals the PCI memory region if PCI is available, but must be system
    memory in the ISA case.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/pc.c b/hw/pc.c
index 5bc845a..203627d 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -965,7 +965,7 @@ void pc_memory_init(MemoryRegion *system_memory,
                     const char *initrd_filename,
                     ram_addr_t below_4g_mem_size,
                     ram_addr_t above_4g_mem_size,
-                    MemoryRegion *pci_memory,
+                    MemoryRegion *rom_memory,
                     MemoryRegion **ram_memory)
 {
     char *filename;
@@ -1029,7 +1029,7 @@ void pc_memory_init(MemoryRegion *system_memory,
     isa_bios = g_malloc(sizeof(*isa_bios));
     memory_region_init_alias(isa_bios, "isa-bios", bios,
                              bios_size - isa_bios_size, isa_bios_size);
-    memory_region_add_subregion_overlap(pci_memory,
+    memory_region_add_subregion_overlap(rom_memory,
                                         0x100000 - isa_bios_size,
                                         isa_bios,
                                         1);
@@ -1037,13 +1037,13 @@ void pc_memory_init(MemoryRegion *system_memory,
 
     option_rom_mr = g_malloc(sizeof(*option_rom_mr));
     memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE);
-    memory_region_add_subregion_overlap(pci_memory,
+    memory_region_add_subregion_overlap(rom_memory,
                                         PC_ROM_MIN_VGA,
                                         option_rom_mr,
                                         1);
 
     /* map all the bios at the top of memory */
-    memory_region_add_subregion(pci_memory,
+    memory_region_add_subregion(rom_memory,
                                 (uint32_t)(-bios_size),
                                 bios);
 
diff --git a/hw/pc.h b/hw/pc.h
index dae736e..8e75c71 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -137,7 +137,7 @@ void pc_memory_init(MemoryRegion *system_memory,
                     const char *initrd_filename,
                     ram_addr_t below_4g_mem_size,
                     ram_addr_t above_4g_mem_size,
-                    MemoryRegion *pci_memory,
+                    MemoryRegion *rom_memory,
                     MemoryRegion **ram_memory);
 qemu_irq *pc_allocate_cpu_irq(void);
 void pc_vga_init(PCIBus *pci_bus);
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 75d96d9..52939f5 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -97,6 +97,7 @@ static void pc_init1(MemoryRegion *system_memory,
     ISADevice *rtc_state;
     MemoryRegion *ram_memory;
     MemoryRegion *pci_memory;
+    MemoryRegion *rom_memory;
 
     pc_cpus_init(cpu_model);
 
@@ -112,15 +113,21 @@ static void pc_init1(MemoryRegion *system_memory,
         below_4g_mem_size = ram_size;
     }
 
-    pci_memory = g_new(MemoryRegion, 1);
-    memory_region_init(pci_memory, "pci", INT64_MAX);
+    if (pci_enabled) {
+        pci_memory = g_new(MemoryRegion, 1);
+        memory_region_init(pci_memory, "pci", INT64_MAX);
+        rom_memory = pci_memory;
+    } else {
+        pci_memory = NULL;
+        rom_memory = system_memory;
+    }
 
     /* allocate ram and load rom/bios */
     if (!xen_enabled()) {
         pc_memory_init(system_memory,
                        kernel_filename, kernel_cmdline, initrd_filename,
                        below_4g_mem_size, above_4g_mem_size,
-                       pci_memory, &ram_memory);
+                       rom_memory, &ram_memory);
     }
 
     if (!xen_enabled()) {
commit dd8e93799f13ef82d83c185b8e71e049452f7d40
Author: dann frazier <dann.frazier at canonical.com>
Date:   Wed Sep 21 14:06:25 2011 -0600

    e1000: Don't set the Capabilities List bit
    
    [Originally sent to qemu-kvm list, but I was redirected here]
    
    The Capabilities Pointer is NULL, so this bit shouldn't be set. The state of
    this bit doesn't appear to change any behavior on Linux/Windows versions we've
    tested, but it does cause Windows' PCI/PCI Express Compliance Test to balk.
    
    I happen to have a physical 82540EM controller, and it also sets the
    Capabilities Bit, but it actually has items on the capabilities list to go
    with it :)
    
    Signed-off-by: dann frazier <dann.frazier at canonical.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/e1000.c b/hw/e1000.c
index 6a3a941..ce8fc8b 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -1151,8 +1151,6 @@ static int pci_e1000_init(PCIDevice *pci_dev)
 
     pci_conf = d->dev.config;
 
-    /* TODO: we have no capabilities, so why is this bit set? */
-    pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_CAP_LIST);
     /* TODO: RST# value should be 0, PCI spec 6.2.4 */
     pci_conf[PCI_CACHE_LINE_SIZE] = 0x10;
 
commit 74e26c179efa6eed821c2863b8a50c7b586432c4
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Thu Sep 22 11:26:15 2011 +0200

    core: remove qemu_service_io
    
    qemu_service_io was mainly an alias to qemu_notify_event,
    currently used only by PPC for timer hack, so call
    qemu_notify_event directly.
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/arch_init.c b/arch_init.c
index 9a5a0e3..a6c69c7 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -459,11 +459,6 @@ int ram_load(QEMUFile *f, void *opaque, int version_id)
     return 0;
 }
 
-void qemu_service_io(void)
-{
-    qemu_notify_event();
-}
-
 #ifdef HAS_AUDIO
 struct soundhw {
     const char *name;
diff --git a/qemu-common.h b/qemu-common.h
index 404c421..5e87bdf 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -276,9 +276,6 @@ void cpu_exec_init_all(void);
 void cpu_save(QEMUFile *f, void *opaque);
 int cpu_load(QEMUFile *f, void *opaque, int version_id);
 
-/* Force QEMU to stop what it's doing and service IO */
-void qemu_service_io(void);
-
 /* Force QEMU to process pending events */
 void qemu_notify_event(void);
 
diff --git a/qemu-tool.c b/qemu-tool.c
index eb89fe0..e9f7fe1 100644
--- a/qemu-tool.c
+++ b/qemu-tool.c
@@ -29,10 +29,6 @@ struct QEMUBH
     void *opaque;
 };
 
-void qemu_service_io(void)
-{
-}
-
 Monitor *cur_mon;
 
 int monitor_cur_is_qmp(void)
diff --git a/target-ppc/kvm_ppc.c b/target-ppc/kvm_ppc.c
index 867dc1d..c031fcb 100644
--- a/target-ppc/kvm_ppc.c
+++ b/target-ppc/kvm_ppc.c
@@ -88,7 +88,7 @@ void kvmppc_fdt_update(void *fdt)
 
 static void kvmppc_timer_hack(void *opaque)
 {
-    qemu_service_io();
+    qemu_notify_event();
     qemu_mod_timer(kvmppc_timer, qemu_get_clock_ns(vm_clock) + kvmppc_timer_rate);
 }
 
commit f5f487b2562e289ab896387ca5e067acfd9fb077
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Sat Sep 17 17:26:15 2011 +0100

    MAINTAINERS: claim maintainership for the OMAP devices
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Acked-by: Edgar E. Iglesias <edgar.iglesias at gmail.com>

diff --git a/MAINTAINERS b/MAINTAINERS
index 7c5ea87..5046dc9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -355,6 +355,11 @@ M: Kevin Wolf <kwolf at redhat.com>
 S: Odd Fixes
 F: hw/ide/
 
+OMAP
+M: Peter Maydell <peter.maydell at linaro.org>
+S: Maintained
+F: hw/omap*
+
 PCI
 M: Michael S. Tsirkin <mst at redhat.com>
 S: Supported
commit bdbc1b3cd4fbec9f7219e05e77874b489e61b217
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Wed Sep 21 11:10:43 2011 +0000

    hw/omap1: Wire up GPIO clock
    
    Wire up the OMAP1 GPIO clock -- this fixes a hw_error() on startup
    with OMAP1 based machines (sx1, cheetah).
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/hw/omap1.c b/hw/omap1.c
index 4bf88e8..619812c 100644
--- a/hw/omap1.c
+++ b/hw/omap1.c
@@ -3950,6 +3950,7 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
 
     s->gpio = qdev_create(NULL, "omap-gpio");
     qdev_prop_set_int32(s->gpio, "mpu_model", s->mpu_model);
+    qdev_prop_set_ptr(s->gpio, "clk", omap_findclk(s, "arm_gpio_ck"));
     qdev_init_nofail(s->gpio);
     sysbus_connect_irq(sysbus_from_qdev(s->gpio), 0,
                        qdev_get_gpio_in(s->ih[0], OMAP_INT_GPIO_BANK1));
commit 0919ac787641db11024912651f3bc5764d4f1286
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Fri Sep 23 09:44:38 2011 +0000

    omap_intc: Qdevify
    
    Convert the omap_intc devices to qdev. This includes adding
    a 'revision' property which will be needed for omap3.
    
    The bulk of this patch is the replacement of "s->irq[x][y]"
    with  "qdev_get_gpio_in(s->ih[x], y)" now that the interrupt
    controller exposes its input lines as qdev gpio inputs.
    
    The devices are named "omap-intc" and "omap2-intc", following
    the filename and the OMAP2/3 hardware names, although some
    internal functions are still named "omap_inth_*".
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/hw/nseries.c b/hw/nseries.c
index af287dd..eb99143 100644
--- a/hw/nseries.c
+++ b/hw/nseries.c
@@ -199,7 +199,9 @@ static void n8x0_i2c_setup(struct n800_s *s)
 
     /* Attach a menelaus PM chip */
     dev = i2c_create_slave(s->i2c, "twl92230", N8X0_MENELAUS_ADDR);
-    qdev_connect_gpio_out(dev, 3, s->cpu->irq[0][OMAP_INT_24XX_SYS_NIRQ]);
+    qdev_connect_gpio_out(dev, 3,
+                          qdev_get_gpio_in(s->cpu->ih[0],
+                                           OMAP_INT_24XX_SYS_NIRQ));
 
     /* Attach a TMP105 PM chip (A0 wired to ground) */
     dev = i2c_create_slave(s->i2c, "tmp105", N8X0_TMP105_ADDR);
diff --git a/hw/omap.h b/hw/omap.h
index 0260cc0..cc09a3c 100644
--- a/hw/omap.h
+++ b/hw/omap.h
@@ -99,18 +99,6 @@ target_phys_addr_t omap_l4_region_base(struct omap_target_agent_s *ta,
 int l4_register_io_memory(CPUReadMemoryFunc * const *mem_read,
                 CPUWriteMemoryFunc * const *mem_write, void *opaque);
 
-/* OMAP interrupt controller */
-struct omap_intr_handler_s;
-struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base,
-                unsigned long size, unsigned char nbanks, qemu_irq **pins,
-                qemu_irq parent_irq, qemu_irq parent_fiq, omap_clk clk);
-struct omap_intr_handler_s *omap2_inth_init(target_phys_addr_t base,
-                int size, int nbanks, qemu_irq **pins,
-                qemu_irq parent_irq, qemu_irq parent_fiq,
-                omap_clk fclk, omap_clk iclk);
-void omap_inth_reset(struct omap_intr_handler_s *s);
-qemu_irq omap_inth_get_pin(struct omap_intr_handler_s *s, int n);
-
 /* OMAP2 SDRAM controller */
 struct omap_sdrc_s;
 struct omap_sdrc_s *omap_sdrc_init(target_phys_addr_t base);
@@ -692,9 +680,6 @@ struct uWireSlave {
     void *opaque;
 };
 struct omap_uwire_s;
-struct omap_uwire_s *omap_uwire_init(MemoryRegion *system_memory,
-                target_phys_addr_t base,
-                qemu_irq *irq, qemu_irq dma, omap_clk clk);
 void omap_uwire_attach(struct omap_uwire_s *s,
                 uWireSlave *slave, int chipselect);
 
@@ -732,9 +717,6 @@ struct I2SCodec {
     } in, out;
 };
 struct omap_mcbsp_s;
-struct omap_mcbsp_s *omap_mcbsp_init(MemoryRegion *system_memory,
-                target_phys_addr_t base,
-                qemu_irq *irq, qemu_irq *dma, omap_clk clk);
 void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, I2SCodec *slave);
 
 void omap_tap_init(struct omap_target_agent_s *ta,
@@ -823,7 +805,6 @@ struct omap_mpu_state_s {
 
     CPUState *env;
 
-    qemu_irq *irq[2];
     qemu_irq *drq;
 
     qemu_irq wakeup;
@@ -896,7 +877,7 @@ struct omap_mpu_state_s {
     struct omap_lpg_s *led[2];
 
     /* MPU private TIPB peripherals */
-    struct omap_intr_handler_s *ih[2];
+    DeviceState *ih[2];
 
     struct soc_dma_s *dma;
 
diff --git a/hw/omap1.c b/hw/omap1.c
index f747321..4bf88e8 100644
--- a/hw/omap1.c
+++ b/hw/omap1.c
@@ -524,7 +524,7 @@ static uint64_t omap_ulpd_pm_read(void *opaque, target_phys_addr_t addr,
     case 0x14:	/* IT_STATUS */
         ret = s->ulpd_pm_regs[addr >> 2];
         s->ulpd_pm_regs[addr >> 2] = 0;
-        qemu_irq_lower(s->irq[1][OMAP_INT_GAUGE_32K]);
+        qemu_irq_lower(qdev_get_gpio_in(s->ih[1], OMAP_INT_GAUGE_32K));
         return ret;
 
     case 0x18:	/* Reserved */
@@ -625,7 +625,7 @@ static void omap_ulpd_pm_write(void *opaque, target_phys_addr_t addr,
                     s->ulpd_pm_regs[0x14 >> 2] |= 1 << 1;
 
                 s->ulpd_pm_regs[0x14 >> 2] |= 1 << 0;	/* IT_GAUGING */
-                qemu_irq_raise(s->irq[1][OMAP_INT_GAUGE_32K]);
+                qemu_irq_raise(qdev_get_gpio_in(s->ih[1], OMAP_INT_GAUGE_32K));
             }
         }
         s->ulpd_pm_regs[addr >> 2] = value;
@@ -2257,15 +2257,17 @@ static void omap_uwire_reset(struct omap_uwire_s *s)
     s->setup[4] = 0;
 }
 
-struct omap_uwire_s *omap_uwire_init(MemoryRegion *system_memory,
-                target_phys_addr_t base,
-                qemu_irq *irq, qemu_irq dma, omap_clk clk)
+static struct omap_uwire_s *omap_uwire_init(MemoryRegion *system_memory,
+                                            target_phys_addr_t base,
+                                            qemu_irq txirq, qemu_irq rxirq,
+                                            qemu_irq dma,
+                                            omap_clk clk)
 {
     struct omap_uwire_s *s = (struct omap_uwire_s *)
             g_malloc0(sizeof(struct omap_uwire_s));
 
-    s->txirq = irq[0];
-    s->rxirq = irq[1];
+    s->txirq = txirq;
+    s->rxirq = rxirq;
     s->txdrq = dma;
     omap_uwire_reset(s);
 
@@ -2873,14 +2875,15 @@ static void omap_rtc_reset(struct omap_rtc_s *s)
 }
 
 static struct omap_rtc_s *omap_rtc_init(MemoryRegion *system_memory,
-                target_phys_addr_t base,
-                qemu_irq *irq, omap_clk clk)
+                                        target_phys_addr_t base,
+                                        qemu_irq timerirq, qemu_irq alarmirq,
+                                        omap_clk clk)
 {
     struct omap_rtc_s *s = (struct omap_rtc_s *)
             g_malloc0(sizeof(struct omap_rtc_s));
 
-    s->irq = irq[0];
-    s->alarm = irq[1];
+    s->irq = timerirq;
+    s->alarm = alarmirq;
     s->clk = qemu_new_timer_ms(rt_clock, omap_rtc_tick, s);
 
     omap_rtc_reset(s);
@@ -3402,15 +3405,16 @@ static void omap_mcbsp_reset(struct omap_mcbsp_s *s)
     qemu_del_timer(s->sink_timer);
 }
 
-struct omap_mcbsp_s *omap_mcbsp_init(MemoryRegion *system_memory,
-                target_phys_addr_t base,
-                qemu_irq *irq, qemu_irq *dma, omap_clk clk)
+static struct omap_mcbsp_s *omap_mcbsp_init(MemoryRegion *system_memory,
+                                            target_phys_addr_t base,
+                                            qemu_irq txirq, qemu_irq rxirq,
+                                            qemu_irq *dma, omap_clk clk)
 {
     struct omap_mcbsp_s *s = (struct omap_mcbsp_s *)
             g_malloc0(sizeof(struct omap_mcbsp_s));
 
-    s->txirq = irq[0];
-    s->rxirq = irq[1];
+    s->txirq = txirq;
+    s->rxirq = rxirq;
     s->txdrq = dma[0];
     s->rxdrq = dma[1];
     s->sink_timer = qemu_new_timer_ns(vm_clock, omap_mcbsp_sink_tick, s);
@@ -3642,8 +3646,6 @@ static void omap1_mpu_reset(void *opaque)
 {
     struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque;
 
-    omap_inth_reset(mpu->ih[0]);
-    omap_inth_reset(mpu->ih[1]);
     omap_dma_reset(mpu->dma);
     omap_mpu_timer_reset(mpu->timer[0]);
     omap_mpu_timer_reset(mpu->timer[1]);
@@ -3796,6 +3798,7 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
     qemu_irq *cpu_irq;
     qemu_irq dma_irqs[6];
     DriveInfo *dinfo;
+    SysBusDevice *busdev;
 
     if (!core)
         core = "ti925t";
@@ -3824,17 +3827,30 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
     omap_clkm_init(system_memory, 0xfffece00, 0xe1008000, s);
 
     cpu_irq = arm_pic_init_cpu(s->env);
-    s->ih[0] = omap_inth_init(0xfffecb00, 0x100, 1, &s->irq[0],
-                    cpu_irq[ARM_PIC_CPU_IRQ], cpu_irq[ARM_PIC_CPU_FIQ],
-                    omap_findclk(s, "arminth_ck"));
-    s->ih[1] = omap_inth_init(0xfffe0000, 0x800, 1, &s->irq[1],
-                    omap_inth_get_pin(s->ih[0], OMAP_INT_15XX_IH2_IRQ),
-		    NULL, omap_findclk(s, "arminth_ck"));
-
-    for (i = 0; i < 6; i ++)
-        dma_irqs[i] =
-                s->irq[omap1_dma_irq_map[i].ih][omap1_dma_irq_map[i].intr];
-    s->dma = omap_dma_init(0xfffed800, dma_irqs, s->irq[0][OMAP_INT_DMA_LCD],
+    s->ih[0] = qdev_create(NULL, "omap-intc");
+    qdev_prop_set_uint32(s->ih[0], "size", 0x100);
+    qdev_prop_set_ptr(s->ih[0], "clk", omap_findclk(s, "arminth_ck"));
+    qdev_init_nofail(s->ih[0]);
+    busdev = sysbus_from_qdev(s->ih[0]);
+    sysbus_connect_irq(busdev, 0, cpu_irq[ARM_PIC_CPU_IRQ]);
+    sysbus_connect_irq(busdev, 1, cpu_irq[ARM_PIC_CPU_FIQ]);
+    sysbus_mmio_map(busdev, 0, 0xfffecb00);
+    s->ih[1] = qdev_create(NULL, "omap-intc");
+    qdev_prop_set_uint32(s->ih[1], "size", 0x800);
+    qdev_prop_set_ptr(s->ih[1], "clk", omap_findclk(s, "arminth_ck"));
+    qdev_init_nofail(s->ih[1]);
+    busdev = sysbus_from_qdev(s->ih[1]);
+    sysbus_connect_irq(busdev, 0,
+                       qdev_get_gpio_in(s->ih[0], OMAP_INT_15XX_IH2_IRQ));
+    /* The second interrupt controller's FIQ output is not wired up */
+    sysbus_mmio_map(busdev, 0, 0xfffe0000);
+
+    for (i = 0; i < 6; i++) {
+        dma_irqs[i] = qdev_get_gpio_in(s->ih[omap1_dma_irq_map[i].ih],
+                                       omap1_dma_irq_map[i].intr);
+    }
+    s->dma = omap_dma_init(0xfffed800, dma_irqs,
+                           qdev_get_gpio_in(s->ih[0], OMAP_INT_DMA_LCD),
                            s, omap_findclk(s, "dma_ck"), omap_dma_3_1);
 
     s->port[emiff    ].addr_valid = omap_validate_emiff_addr;
@@ -3851,25 +3867,27 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
                          OMAP_IMIF_BASE, s->sram_size);
 
     s->timer[0] = omap_mpu_timer_init(system_memory, 0xfffec500,
-                    s->irq[0][OMAP_INT_TIMER1],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_TIMER1),
                     omap_findclk(s, "mputim_ck"));
     s->timer[1] = omap_mpu_timer_init(system_memory, 0xfffec600,
-                    s->irq[0][OMAP_INT_TIMER2],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_TIMER2),
                     omap_findclk(s, "mputim_ck"));
     s->timer[2] = omap_mpu_timer_init(system_memory, 0xfffec700,
-                    s->irq[0][OMAP_INT_TIMER3],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_TIMER3),
                     omap_findclk(s, "mputim_ck"));
 
     s->wdt = omap_wd_timer_init(system_memory, 0xfffec800,
-                    s->irq[0][OMAP_INT_WD_TIMER],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_WD_TIMER),
                     omap_findclk(s, "armwdt_ck"));
 
     s->os_timer = omap_os_timer_init(system_memory, 0xfffb9000,
-                    s->irq[1][OMAP_INT_OS_TIMER],
+                    qdev_get_gpio_in(s->ih[1], OMAP_INT_OS_TIMER),
                     omap_findclk(s, "clk32-kHz"));
 
-    s->lcd = omap_lcdc_init(0xfffec000, s->irq[0][OMAP_INT_LCD_CTRL],
-                    omap_dma_get_lcdch(s->dma), omap_findclk(s, "lcd_ck"));
+    s->lcd = omap_lcdc_init(0xfffec000,
+                            qdev_get_gpio_in(s->ih[0], OMAP_INT_LCD_CTRL),
+                            omap_dma_get_lcdch(s->dma),
+                            omap_findclk(s, "lcd_ck"));
 
     omap_ulpd_pm_init(system_memory, 0xfffe0800, s);
     omap_pin_cfg_init(system_memory, 0xfffe1000, s);
@@ -3878,27 +3896,30 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
     omap_mpui_init(system_memory, 0xfffec900, s);
 
     s->private_tipb = omap_tipb_bridge_init(system_memory, 0xfffeca00,
-                    s->irq[0][OMAP_INT_BRIDGE_PRIV],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_BRIDGE_PRIV),
                     omap_findclk(s, "tipb_ck"));
     s->public_tipb = omap_tipb_bridge_init(system_memory, 0xfffed300,
-                    s->irq[0][OMAP_INT_BRIDGE_PUB],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_BRIDGE_PUB),
                     omap_findclk(s, "tipb_ck"));
 
     omap_tcmi_init(system_memory, 0xfffecc00, s);
 
-    s->uart[0] = omap_uart_init(0xfffb0000, s->irq[1][OMAP_INT_UART1],
+    s->uart[0] = omap_uart_init(0xfffb0000,
+                                qdev_get_gpio_in(s->ih[1], OMAP_INT_UART1),
                     omap_findclk(s, "uart1_ck"),
                     omap_findclk(s, "uart1_ck"),
                     s->drq[OMAP_DMA_UART1_TX], s->drq[OMAP_DMA_UART1_RX],
                     "uart1",
                     serial_hds[0]);
-    s->uart[1] = omap_uart_init(0xfffb0800, s->irq[1][OMAP_INT_UART2],
+    s->uart[1] = omap_uart_init(0xfffb0800,
+                                qdev_get_gpio_in(s->ih[1], OMAP_INT_UART2),
                     omap_findclk(s, "uart2_ck"),
                     omap_findclk(s, "uart2_ck"),
                     s->drq[OMAP_DMA_UART2_TX], s->drq[OMAP_DMA_UART2_RX],
                     "uart2",
                     serial_hds[0] ? serial_hds[1] : NULL);
-    s->uart[2] = omap_uart_init(0xfffb9800, s->irq[0][OMAP_INT_UART3],
+    s->uart[2] = omap_uart_init(0xfffb9800,
+                                qdev_get_gpio_in(s->ih[0], OMAP_INT_UART3),
                     omap_findclk(s, "uart3_ck"),
                     omap_findclk(s, "uart3_ck"),
                     s->drq[OMAP_DMA_UART3_TX], s->drq[OMAP_DMA_UART3_RX],
@@ -3918,42 +3939,52 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
         exit(1);
     }
     s->mmc = omap_mmc_init(0xfffb7800, dinfo->bdrv,
-                    s->irq[1][OMAP_INT_OQN], &s->drq[OMAP_DMA_MMC_TX],
+                           qdev_get_gpio_in(s->ih[1], OMAP_INT_OQN),
+                           &s->drq[OMAP_DMA_MMC_TX],
                     omap_findclk(s, "mmc_ck"));
 
     s->mpuio = omap_mpuio_init(system_memory, 0xfffb5000,
-                    s->irq[1][OMAP_INT_KEYBOARD], s->irq[1][OMAP_INT_MPUIO],
-                    s->wakeup, omap_findclk(s, "clk32-kHz"));
+                               qdev_get_gpio_in(s->ih[1], OMAP_INT_KEYBOARD),
+                               qdev_get_gpio_in(s->ih[1], OMAP_INT_MPUIO),
+                               s->wakeup, omap_findclk(s, "clk32-kHz"));
 
     s->gpio = qdev_create(NULL, "omap-gpio");
     qdev_prop_set_int32(s->gpio, "mpu_model", s->mpu_model);
     qdev_init_nofail(s->gpio);
     sysbus_connect_irq(sysbus_from_qdev(s->gpio), 0,
-                    s->irq[0][OMAP_INT_GPIO_BANK1]);
+                       qdev_get_gpio_in(s->ih[0], OMAP_INT_GPIO_BANK1));
     sysbus_mmio_map(sysbus_from_qdev(s->gpio), 0, 0xfffce000);
 
-    s->microwire = omap_uwire_init(system_memory,
-                    0xfffb3000, &s->irq[1][OMAP_INT_uWireTX],
+    s->microwire = omap_uwire_init(system_memory, 0xfffb3000,
+                                   qdev_get_gpio_in(s->ih[1], OMAP_INT_uWireTX),
+                                   qdev_get_gpio_in(s->ih[1], OMAP_INT_uWireRX),
                     s->drq[OMAP_DMA_UWIRE_TX], omap_findclk(s, "mpuper_ck"));
 
     omap_pwl_init(system_memory, 0xfffb5800, s, omap_findclk(s, "armxor_ck"));
     omap_pwt_init(system_memory, 0xfffb6000, s, omap_findclk(s, "armxor_ck"));
 
-    s->i2c[0] = omap_i2c_init(0xfffb3800, s->irq[1][OMAP_INT_I2C],
+    s->i2c[0] = omap_i2c_init(0xfffb3800,
+                              qdev_get_gpio_in(s->ih[1], OMAP_INT_I2C),
                     &s->drq[OMAP_DMA_I2C_RX], omap_findclk(s, "mpuper_ck"));
 
     s->rtc = omap_rtc_init(system_memory, 0xfffb4800,
-                    &s->irq[1][OMAP_INT_RTC_TIMER],
+                           qdev_get_gpio_in(s->ih[1], OMAP_INT_RTC_TIMER),
+                           qdev_get_gpio_in(s->ih[1], OMAP_INT_RTC_ALARM),
                     omap_findclk(s, "clk32-kHz"));
 
-    s->mcbsp1 = omap_mcbsp_init(system_memory,
-                    0xfffb1800, &s->irq[1][OMAP_INT_McBSP1TX],
+    s->mcbsp1 = omap_mcbsp_init(system_memory, 0xfffb1800,
+                                qdev_get_gpio_in(s->ih[1], OMAP_INT_McBSP1TX),
+                                qdev_get_gpio_in(s->ih[1], OMAP_INT_McBSP1RX),
                     &s->drq[OMAP_DMA_MCBSP1_TX], omap_findclk(s, "dspxor_ck"));
-    s->mcbsp2 = omap_mcbsp_init(system_memory,
-                    0xfffb1000, &s->irq[0][OMAP_INT_310_McBSP2_TX],
+    s->mcbsp2 = omap_mcbsp_init(system_memory, 0xfffb1000,
+                                qdev_get_gpio_in(s->ih[0],
+                                                 OMAP_INT_310_McBSP2_TX),
+                                qdev_get_gpio_in(s->ih[0],
+                                                 OMAP_INT_310_McBSP2_RX),
                     &s->drq[OMAP_DMA_MCBSP2_TX], omap_findclk(s, "mpuper_ck"));
-    s->mcbsp3 = omap_mcbsp_init(system_memory,
-                    0xfffb7000, &s->irq[1][OMAP_INT_McBSP3TX],
+    s->mcbsp3 = omap_mcbsp_init(system_memory, 0xfffb7000,
+                                qdev_get_gpio_in(s->ih[1], OMAP_INT_McBSP3TX),
+                                qdev_get_gpio_in(s->ih[1], OMAP_INT_McBSP3RX),
                     &s->drq[OMAP_DMA_MCBSP3_TX], omap_findclk(s, "dspxor_ck"));
 
     s->led[0] = omap_lpg_init(system_memory,
diff --git a/hw/omap2.c b/hw/omap2.c
index 3d529ce..838c32f 100644
--- a/hw/omap2.c
+++ b/hw/omap2.c
@@ -2180,7 +2180,6 @@ static void omap2_mpu_reset(void *opaque)
 {
     struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque;
 
-    omap_inth_reset(mpu->ih[0]);
     omap_dma_reset(mpu->dma);
     omap_prcm_reset(mpu->prcm);
     omap_sysctl_reset(mpu->sysc);
@@ -2264,20 +2263,27 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
 
     /* Actually mapped at any 2K boundary in the ARM11 private-peripheral if */
     cpu_irq = arm_pic_init_cpu(s->env);
-    s->ih[0] = omap2_inth_init(0x480fe000, 0x1000, 3, &s->irq[0],
-                    cpu_irq[ARM_PIC_CPU_IRQ], cpu_irq[ARM_PIC_CPU_FIQ],
-                    omap_findclk(s, "mpu_intc_fclk"),
-                    omap_findclk(s, "mpu_intc_iclk"));
-
+    s->ih[0] = qdev_create(NULL, "omap2-intc");
+    qdev_prop_set_uint8(s->ih[0], "revision", 0x21);
+    qdev_prop_set_ptr(s->ih[0], "fclk", omap_findclk(s, "mpu_intc_fclk"));
+    qdev_prop_set_ptr(s->ih[0], "iclk", omap_findclk(s, "mpu_intc_iclk"));
+    qdev_init_nofail(s->ih[0]);
+    busdev = sysbus_from_qdev(s->ih[0]);
+    sysbus_connect_irq(busdev, 0, cpu_irq[ARM_PIC_CPU_IRQ]);
+    sysbus_connect_irq(busdev, 1, cpu_irq[ARM_PIC_CPU_FIQ]);
+    sysbus_mmio_map(busdev, 0, 0x480fe000);
     s->prcm = omap_prcm_init(omap_l4tao(s->l4, 3),
-                    s->irq[0][OMAP_INT_24XX_PRCM_MPU_IRQ], NULL, NULL, s);
+                             qdev_get_gpio_in(s->ih[0],
+                                              OMAP_INT_24XX_PRCM_MPU_IRQ),
+                             NULL, NULL, s);
 
     s->sysc = omap_sysctl_init(omap_l4tao(s->l4, 1),
                     omap_findclk(s, "omapctrl_iclk"), s);
 
-    for (i = 0; i < 4; i ++)
-        dma_irqs[i] =
-                s->irq[omap2_dma_irq_map[i].ih][omap2_dma_irq_map[i].intr];
+    for (i = 0; i < 4; i++) {
+        dma_irqs[i] = qdev_get_gpio_in(s->ih[omap2_dma_irq_map[i].ih],
+                                       omap2_dma_irq_map[i].intr);
+    }
     s->dma = omap_dma4_init(0x48056000, dma_irqs, s, 256, 32,
                     omap_findclk(s, "sdma_iclk"),
                     omap_findclk(s, "sdma_fclk"));
@@ -2290,7 +2296,8 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
                          OMAP2_SRAM_BASE, s->sram_size);
 
     s->uart[0] = omap2_uart_init(omap_l4ta(s->l4, 19),
-                    s->irq[0][OMAP_INT_24XX_UART1_IRQ],
+                                 qdev_get_gpio_in(s->ih[0],
+                                                  OMAP_INT_24XX_UART1_IRQ),
                     omap_findclk(s, "uart1_fclk"),
                     omap_findclk(s, "uart1_iclk"),
                     s->drq[OMAP24XX_DMA_UART1_TX],
@@ -2298,7 +2305,8 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
                     "uart1",
                     serial_hds[0]);
     s->uart[1] = omap2_uart_init(omap_l4ta(s->l4, 20),
-                    s->irq[0][OMAP_INT_24XX_UART2_IRQ],
+                                 qdev_get_gpio_in(s->ih[0],
+                                                  OMAP_INT_24XX_UART2_IRQ),
                     omap_findclk(s, "uart2_fclk"),
                     omap_findclk(s, "uart2_iclk"),
                     s->drq[OMAP24XX_DMA_UART2_TX],
@@ -2306,7 +2314,8 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
                     "uart2",
                     serial_hds[0] ? serial_hds[1] : NULL);
     s->uart[2] = omap2_uart_init(omap_l4ta(s->l4, 21),
-                    s->irq[0][OMAP_INT_24XX_UART3_IRQ],
+                                 qdev_get_gpio_in(s->ih[0],
+                                                  OMAP_INT_24XX_UART3_IRQ),
                     omap_findclk(s, "uart3_fclk"),
                     omap_findclk(s, "uart3_iclk"),
                     s->drq[OMAP24XX_DMA_UART3_TX],
@@ -2315,51 +2324,51 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
                     serial_hds[0] && serial_hds[1] ? serial_hds[2] : NULL);
 
     s->gptimer[0] = omap_gp_timer_init(omap_l4ta(s->l4, 7),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER1],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER1),
                     omap_findclk(s, "wu_gpt1_clk"),
                     omap_findclk(s, "wu_l4_iclk"));
     s->gptimer[1] = omap_gp_timer_init(omap_l4ta(s->l4, 8),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER2],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER2),
                     omap_findclk(s, "core_gpt2_clk"),
                     omap_findclk(s, "core_l4_iclk"));
     s->gptimer[2] = omap_gp_timer_init(omap_l4ta(s->l4, 22),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER3],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER3),
                     omap_findclk(s, "core_gpt3_clk"),
                     omap_findclk(s, "core_l4_iclk"));
     s->gptimer[3] = omap_gp_timer_init(omap_l4ta(s->l4, 23),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER4],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER4),
                     omap_findclk(s, "core_gpt4_clk"),
                     omap_findclk(s, "core_l4_iclk"));
     s->gptimer[4] = omap_gp_timer_init(omap_l4ta(s->l4, 24),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER5],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER5),
                     omap_findclk(s, "core_gpt5_clk"),
                     omap_findclk(s, "core_l4_iclk"));
     s->gptimer[5] = omap_gp_timer_init(omap_l4ta(s->l4, 25),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER6],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER6),
                     omap_findclk(s, "core_gpt6_clk"),
                     omap_findclk(s, "core_l4_iclk"));
     s->gptimer[6] = omap_gp_timer_init(omap_l4ta(s->l4, 26),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER7],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER7),
                     omap_findclk(s, "core_gpt7_clk"),
                     omap_findclk(s, "core_l4_iclk"));
     s->gptimer[7] = omap_gp_timer_init(omap_l4ta(s->l4, 27),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER8],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER8),
                     omap_findclk(s, "core_gpt8_clk"),
                     omap_findclk(s, "core_l4_iclk"));
     s->gptimer[8] = omap_gp_timer_init(omap_l4ta(s->l4, 28),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER9],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER9),
                     omap_findclk(s, "core_gpt9_clk"),
                     omap_findclk(s, "core_l4_iclk"));
     s->gptimer[9] = omap_gp_timer_init(omap_l4ta(s->l4, 29),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER10],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER10),
                     omap_findclk(s, "core_gpt10_clk"),
                     omap_findclk(s, "core_l4_iclk"));
     s->gptimer[10] = omap_gp_timer_init(omap_l4ta(s->l4, 30),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER11],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER11),
                     omap_findclk(s, "core_gpt11_clk"),
                     omap_findclk(s, "core_l4_iclk"));
     s->gptimer[11] = omap_gp_timer_init(omap_l4ta(s->l4, 31),
-                    s->irq[0][OMAP_INT_24XX_GPTIMER12],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER12),
                     omap_findclk(s, "core_gpt12_clk"),
                     omap_findclk(s, "core_l4_iclk"));
 
@@ -2370,12 +2379,12 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
                     omap_findclk(s, "core_l4_iclk"));
 
     s->i2c[0] = omap2_i2c_init(omap_l4tao(s->l4, 5),
-                    s->irq[0][OMAP_INT_24XX_I2C1_IRQ],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_I2C1_IRQ),
                     &s->drq[OMAP24XX_DMA_I2C1_TX],
                     omap_findclk(s, "i2c1.fclk"),
                     omap_findclk(s, "i2c1.iclk"));
     s->i2c[1] = omap2_i2c_init(omap_l4tao(s->l4, 6),
-                    s->irq[0][OMAP_INT_24XX_I2C2_IRQ],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_I2C2_IRQ),
                     &s->drq[OMAP24XX_DMA_I2C2_TX],
                     omap_findclk(s, "i2c2.fclk"),
                     omap_findclk(s, "i2c2.iclk"));
@@ -2392,10 +2401,14 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
     }
     qdev_init_nofail(s->gpio);
     busdev = sysbus_from_qdev(s->gpio);
-    sysbus_connect_irq(busdev, 0, s->irq[0][OMAP_INT_24XX_GPIO_BANK1]);
-    sysbus_connect_irq(busdev, 3, s->irq[0][OMAP_INT_24XX_GPIO_BANK2]);
-    sysbus_connect_irq(busdev, 6, s->irq[0][OMAP_INT_24XX_GPIO_BANK3]);
-    sysbus_connect_irq(busdev, 9, s->irq[0][OMAP_INT_24XX_GPIO_BANK4]);
+    sysbus_connect_irq(busdev, 0,
+                       qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK1));
+    sysbus_connect_irq(busdev, 3,
+                       qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK2));
+    sysbus_connect_irq(busdev, 6,
+                       qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK3));
+    sysbus_connect_irq(busdev, 9,
+                       qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK4));
     ta = omap_l4ta(s->l4, 3);
     sysbus_mmio_map(busdev, 0, omap_l4_region_base(ta, 1));
     sysbus_mmio_map(busdev, 1, omap_l4_region_base(ta, 0));
@@ -2404,7 +2417,8 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
     sysbus_mmio_map(busdev, 4, omap_l4_region_base(ta, 5));
 
     s->sdrc = omap_sdrc_init(0x68009000);
-    s->gpmc = omap_gpmc_init(s, 0x6800a000, s->irq[0][OMAP_INT_24XX_GPMC_IRQ],
+    s->gpmc = omap_gpmc_init(s, 0x6800a000,
+                             qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPMC_IRQ),
                              s->drq[OMAP24XX_DMA_GPMC]);
 
     dinfo = drive_get(IF_SD, 0, 0);
@@ -2413,36 +2427,38 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
         exit(1);
     }
     s->mmc = omap2_mmc_init(omap_l4tao(s->l4, 9), dinfo->bdrv,
-                    s->irq[0][OMAP_INT_24XX_MMC_IRQ],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_MMC_IRQ),
                     &s->drq[OMAP24XX_DMA_MMC1_TX],
                     omap_findclk(s, "mmc_fclk"), omap_findclk(s, "mmc_iclk"));
 
     s->mcspi[0] = omap_mcspi_init(omap_l4ta(s->l4, 35), 4,
-                    s->irq[0][OMAP_INT_24XX_MCSPI1_IRQ],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_MCSPI1_IRQ),
                     &s->drq[OMAP24XX_DMA_SPI1_TX0],
                     omap_findclk(s, "spi1_fclk"),
                     omap_findclk(s, "spi1_iclk"));
     s->mcspi[1] = omap_mcspi_init(omap_l4ta(s->l4, 36), 2,
-                    s->irq[0][OMAP_INT_24XX_MCSPI2_IRQ],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_MCSPI2_IRQ),
                     &s->drq[OMAP24XX_DMA_SPI2_TX0],
                     omap_findclk(s, "spi2_fclk"),
                     omap_findclk(s, "spi2_iclk"));
 
     s->dss = omap_dss_init(omap_l4ta(s->l4, 10), 0x68000800,
                     /* XXX wire M_IRQ_25, D_L2_IRQ_30 and I_IRQ_13 together */
-                    s->irq[0][OMAP_INT_24XX_DSS_IRQ], s->drq[OMAP24XX_DMA_DSS],
+                    qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_DSS_IRQ),
+                           s->drq[OMAP24XX_DMA_DSS],
                     omap_findclk(s, "dss_clk1"), omap_findclk(s, "dss_clk2"),
                     omap_findclk(s, "dss_54m_clk"),
                     omap_findclk(s, "dss_l3_iclk"),
                     omap_findclk(s, "dss_l4_iclk"));
 
     omap_sti_init(omap_l4ta(s->l4, 18), 0x54000000,
-                    s->irq[0][OMAP_INT_24XX_STI], omap_findclk(s, "emul_ck"),
+                  qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_STI),
+                  omap_findclk(s, "emul_ck"),
                     serial_hds[0] && serial_hds[1] && serial_hds[2] ?
                     serial_hds[3] : NULL);
 
     s->eac = omap_eac_init(omap_l4ta(s->l4, 32),
-                    s->irq[0][OMAP_INT_24XX_EAC_IRQ],
+                           qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_EAC_IRQ),
                     /* Ten consecutive lines */
                     &s->drq[OMAP24XX_DMA_EAC_AC_RD],
                     omap_findclk(s, "func_96m_clk"),
diff --git a/hw/omap_intc.c b/hw/omap_intc.c
index 38637c6..0f7fd9d 100644
--- a/hw/omap_intc.c
+++ b/hw/omap_intc.c
@@ -19,7 +19,7 @@
  */
 #include "hw.h"
 #include "omap.h"
-#include "exec-memory.h"
+#include "sysbus.h"
 
 /* Interrupt Handlers */
 struct omap_intr_handler_bank_s {
@@ -33,25 +33,26 @@ struct omap_intr_handler_bank_s {
 };
 
 struct omap_intr_handler_s {
+    SysBusDevice busdev;
     qemu_irq *pins;
     qemu_irq parent_intr[2];
     MemoryRegion mmio;
+    void *iclk;
+    void *fclk;
     unsigned char nbanks;
     int level_only;
+    uint32_t size;
+
+    uint8_t revision;
 
     /* state */
     uint32_t new_agr[2];
     int sir_intr[2];
     int autoidle;
     uint32_t mask;
-    struct omap_intr_handler_bank_s bank[];
+    struct omap_intr_handler_bank_s bank[3];
 };
 
-inline qemu_irq omap_inth_get_pin(struct omap_intr_handler_s *s, int n)
-{
-    return s->pins[n];
-}
-
 static void omap_inth_sir_update(struct omap_intr_handler_s *s, int is_fiq)
 {
     int i, j, sir_intr, p_intr, p, f;
@@ -325,8 +326,10 @@ static const MemoryRegionOps omap_inth_mem_ops = {
     },
 };
 
-void omap_inth_reset(struct omap_intr_handler_s *s)
+static void omap_inth_reset(DeviceState *dev)
 {
+    struct omap_intr_handler_s *s = FROM_SYSBUS(struct omap_intr_handler_s,
+                                                sysbus_from_qdev(dev));
     int i;
 
     for (i = 0; i < s->nbanks; ++i){
@@ -353,29 +356,35 @@ void omap_inth_reset(struct omap_intr_handler_s *s)
     qemu_set_irq(s->parent_intr[1], 0);
 }
 
-struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base,
-                unsigned long size, unsigned char nbanks, qemu_irq **pins,
-                qemu_irq parent_irq, qemu_irq parent_fiq, omap_clk clk)
+static int omap_intc_init(SysBusDevice *dev)
 {
-    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *)
-            g_malloc0(sizeof(struct omap_intr_handler_s) +
-                            sizeof(struct omap_intr_handler_bank_s) * nbanks);
-
-    s->parent_intr[0] = parent_irq;
-    s->parent_intr[1] = parent_fiq;
-    s->nbanks = nbanks;
-    s->pins = qemu_allocate_irqs(omap_set_intr, s, nbanks * 32);
-    if (pins)
-        *pins = s->pins;
-
-    memory_region_init_io(&s->mmio, &omap_inth_mem_ops, s, "omap-intc", size);
-    memory_region_add_subregion(get_system_memory(), base, &s->mmio);
-
-    omap_inth_reset(s);
-
-    return s;
+    struct omap_intr_handler_s *s;
+    s = FROM_SYSBUS(struct omap_intr_handler_s, dev);
+    if (!s->iclk) {
+        hw_error("omap-intc: clk not connected\n");
+    }
+    s->nbanks = 1;
+    sysbus_init_irq(dev, &s->parent_intr[0]);
+    sysbus_init_irq(dev, &s->parent_intr[1]);
+    qdev_init_gpio_in(&dev->qdev, omap_set_intr, s->nbanks * 32);
+    memory_region_init_io(&s->mmio, &omap_inth_mem_ops, s,
+                          "omap-intc", s->size);
+    sysbus_init_mmio_region(dev, &s->mmio);
+    return 0;
 }
 
+static SysBusDeviceInfo omap_intc_info = {
+    .init = omap_intc_init,
+    .qdev.name = "omap-intc",
+    .qdev.size = sizeof(struct omap_intr_handler_s),
+    .qdev.reset = omap_inth_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("size", struct omap_intr_handler_s, size, 0x100),
+        DEFINE_PROP_PTR("clk", struct omap_intr_handler_s, iclk),
+        DEFINE_PROP_END_OF_LIST()
+    }
+};
+
 static uint64_t omap2_inth_read(void *opaque, target_phys_addr_t addr,
                                 unsigned size)
 {
@@ -394,7 +403,7 @@ static uint64_t omap2_inth_read(void *opaque, target_phys_addr_t addr,
 
     switch (offset) {
     case 0x00:	/* INTC_REVISION */
-        return 0x21;
+        return s->revision;
 
     case 0x10:	/* INTC_SYSCONFIG */
         return (s->autoidle >> 2) & 1;
@@ -475,7 +484,7 @@ static void omap2_inth_write(void *opaque, target_phys_addr_t addr,
         s->autoidle &= 4;
         s->autoidle |= (value & 1) << 2;
         if (value & 2)						/* SOFTRESET */
-            omap_inth_reset(s);
+            omap_inth_reset(&s->busdev.qdev);
         return;
 
     case 0x48:	/* INTC_CONTROL */
@@ -568,27 +577,45 @@ static const MemoryRegionOps omap2_inth_mem_ops = {
     },
 };
 
-struct omap_intr_handler_s *omap2_inth_init(target_phys_addr_t base,
-                int size, int nbanks, qemu_irq **pins,
-                qemu_irq parent_irq, qemu_irq parent_fiq,
-                omap_clk fclk, omap_clk iclk)
+static int omap2_intc_init(SysBusDevice *dev)
 {
-    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *)
-            g_malloc0(sizeof(struct omap_intr_handler_s) +
-                            sizeof(struct omap_intr_handler_bank_s) * nbanks);
-
-    s->parent_intr[0] = parent_irq;
-    s->parent_intr[1] = parent_fiq;
-    s->nbanks = nbanks;
+    struct omap_intr_handler_s *s;
+    s = FROM_SYSBUS(struct omap_intr_handler_s, dev);
+    if (!s->iclk) {
+        hw_error("omap2-intc: iclk not connected\n");
+    }
+    if (!s->fclk) {
+        hw_error("omap2-intc: fclk not connected\n");
+    }
     s->level_only = 1;
-    s->pins = qemu_allocate_irqs(omap_set_intr_noedge, s, nbanks * 32);
-    if (pins)
-        *pins = s->pins;
-
-    memory_region_init_io(&s->mmio, &omap2_inth_mem_ops, s, "omap2-intc", size);
-    memory_region_add_subregion(get_system_memory(), base, &s->mmio);
+    s->nbanks = 3;
+    sysbus_init_irq(dev, &s->parent_intr[0]);
+    sysbus_init_irq(dev, &s->parent_intr[1]);
+    qdev_init_gpio_in(&dev->qdev, omap_set_intr_noedge, s->nbanks * 32);
+    memory_region_init_io(&s->mmio, &omap2_inth_mem_ops, s,
+                          "omap2-intc", 0x1000);
+    sysbus_init_mmio_region(dev, &s->mmio);
+    return 0;
+}
 
-    omap_inth_reset(s);
+static SysBusDeviceInfo omap2_intc_info = {
+    .init = omap2_intc_init,
+    .qdev.name = "omap2-intc",
+    .qdev.size = sizeof(struct omap_intr_handler_s),
+    .qdev.reset = omap_inth_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT8("revision", struct omap_intr_handler_s,
+                          revision, 0x21),
+        DEFINE_PROP_PTR("iclk", struct omap_intr_handler_s, iclk),
+        DEFINE_PROP_PTR("fclk", struct omap_intr_handler_s, fclk),
+        DEFINE_PROP_END_OF_LIST()
+    }
+};
 
-    return s;
+static void omap_intc_register_device(void)
+{
+    sysbus_register_withprop(&omap_intc_info);
+    sysbus_register_withprop(&omap2_intc_info);
 }
+
+device_init(omap_intc_register_device)
commit 53bb614ee344c2eb37cf5a79d56c945d7661fcf5
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Fri Sep 23 09:44:38 2011 +0000

    omap_intc: Use MemoryRegion API
    
    Convert omap_intc to use the MemoryRegion API
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/hw/omap_intc.c b/hw/omap_intc.c
index f1f570e..38637c6 100644
--- a/hw/omap_intc.c
+++ b/hw/omap_intc.c
@@ -19,6 +19,7 @@
  */
 #include "hw.h"
 #include "omap.h"
+#include "exec-memory.h"
 
 /* Interrupt Handlers */
 struct omap_intr_handler_bank_s {
@@ -34,6 +35,7 @@ struct omap_intr_handler_bank_s {
 struct omap_intr_handler_s {
     qemu_irq *pins;
     qemu_irq parent_intr[2];
+    MemoryRegion mmio;
     unsigned char nbanks;
     int level_only;
 
@@ -142,7 +144,8 @@ static void omap_set_intr_noedge(void *opaque, int irq, int req)
         bank->irqs = (bank->inputs &= ~(1 << n)) | bank->swi;
 }
 
-static uint32_t omap_inth_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_inth_read(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
 {
     struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
     int i, offset = addr;
@@ -220,7 +223,7 @@ static uint32_t omap_inth_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void omap_inth_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                            uint64_t value, unsigned size)
 {
     struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
     int i, offset = addr;
@@ -312,16 +315,14 @@ static void omap_inth_write(void *opaque, target_phys_addr_t addr,
     OMAP_BAD_REG(addr);
 }
 
-static CPUReadMemoryFunc * const omap_inth_readfn[] = {
-    omap_badwidth_read32,
-    omap_badwidth_read32,
-    omap_inth_read,
-};
-
-static CPUWriteMemoryFunc * const omap_inth_writefn[] = {
-    omap_inth_write,
-    omap_inth_write,
-    omap_inth_write,
+static const MemoryRegionOps omap_inth_mem_ops = {
+    .read = omap_inth_read,
+    .write = omap_inth_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
 };
 
 void omap_inth_reset(struct omap_intr_handler_s *s)
@@ -356,7 +357,6 @@ struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base,
                 unsigned long size, unsigned char nbanks, qemu_irq **pins,
                 qemu_irq parent_irq, qemu_irq parent_fiq, omap_clk clk)
 {
-    int iomemtype;
     struct omap_intr_handler_s *s = (struct omap_intr_handler_s *)
             g_malloc0(sizeof(struct omap_intr_handler_s) +
                             sizeof(struct omap_intr_handler_bank_s) * nbanks);
@@ -368,16 +368,16 @@ struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base,
     if (pins)
         *pins = s->pins;
 
-    omap_inth_reset(s);
+    memory_region_init_io(&s->mmio, &omap_inth_mem_ops, s, "omap-intc", size);
+    memory_region_add_subregion(get_system_memory(), base, &s->mmio);
 
-    iomemtype = cpu_register_io_memory(omap_inth_readfn,
-                    omap_inth_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, size, iomemtype);
+    omap_inth_reset(s);
 
     return s;
 }
 
-static uint32_t omap2_inth_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap2_inth_read(void *opaque, target_phys_addr_t addr,
+                                unsigned size)
 {
     struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
     int offset = addr;
@@ -455,7 +455,7 @@ static uint32_t omap2_inth_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void omap2_inth_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                             uint64_t value, unsigned size)
 {
     struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
     int offset = addr;
@@ -558,16 +558,14 @@ static void omap2_inth_write(void *opaque, target_phys_addr_t addr,
     OMAP_BAD_REG(addr);
 }
 
-static CPUReadMemoryFunc * const omap2_inth_readfn[] = {
-    omap_badwidth_read32,
-    omap_badwidth_read32,
-    omap2_inth_read,
-};
-
-static CPUWriteMemoryFunc * const omap2_inth_writefn[] = {
-    omap2_inth_write,
-    omap2_inth_write,
-    omap2_inth_write,
+static const MemoryRegionOps omap2_inth_mem_ops = {
+    .read = omap2_inth_read,
+    .write = omap2_inth_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
 };
 
 struct omap_intr_handler_s *omap2_inth_init(target_phys_addr_t base,
@@ -575,7 +573,6 @@ struct omap_intr_handler_s *omap2_inth_init(target_phys_addr_t base,
                 qemu_irq parent_irq, qemu_irq parent_fiq,
                 omap_clk fclk, omap_clk iclk)
 {
-    int iomemtype;
     struct omap_intr_handler_s *s = (struct omap_intr_handler_s *)
             g_malloc0(sizeof(struct omap_intr_handler_s) +
                             sizeof(struct omap_intr_handler_bank_s) * nbanks);
@@ -588,11 +585,10 @@ struct omap_intr_handler_s *omap2_inth_init(target_phys_addr_t base,
     if (pins)
         *pins = s->pins;
 
-    omap_inth_reset(s);
+    memory_region_init_io(&s->mmio, &omap2_inth_mem_ops, s, "omap2-intc", size);
+    memory_region_add_subregion(get_system_memory(), base, &s->mmio);
 
-    iomemtype = cpu_register_io_memory(omap2_inth_readfn,
-                    omap2_inth_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, size, iomemtype);
+    omap_inth_reset(s);
 
     return s;
 }
commit 7e36b264ce524bc60b7b71dd45c05af767ceff2b
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Sat Sep 17 19:51:49 2011 +0100

    hw/omap_gpmc: Modify correct field when writing IRQSTATUS register
    
    Writing to IRQSTATUS should affect irqst, not irqen -- error
    spotted by Andrzej Zaborowski.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Andrzej Zaborowski <andrew.zaborowski at intel.com>

diff --git a/hw/omap_gpmc.c b/hw/omap_gpmc.c
index e27b93c..7fc82a2 100644
--- a/hw/omap_gpmc.c
+++ b/hw/omap_gpmc.c
@@ -639,7 +639,7 @@ static void omap_gpmc_write(void *opaque, target_phys_addr_t addr,
         break;
 
     case 0x018:	/* GPMC_IRQSTATUS */
-        s->irqen &= ~value;
+        s->irqst &= ~value;
         omap_gpmc_int_update(s);
         break;
 
commit 7196345549474719eb85c675174ce3717adf771b
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Sat Sep 17 19:51:48 2011 +0100

    hw/omap_gpmc: Add comment about FIFOTHRESHOLDSTATUS bit
    
    Promote the remark about why we handle FIFOTHRESHOLDSTATUS the
    way we do from the commit message of de8af7fe0 to a comment in
    the code.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Andrzej Zaborowski <andrew.zaborowski at intel.com>

diff --git a/hw/omap_gpmc.c b/hw/omap_gpmc.c
index 02f0c52..e27b93c 100644
--- a/hw/omap_gpmc.c
+++ b/hw/omap_gpmc.c
@@ -569,6 +569,13 @@ static uint64_t omap_gpmc_read(void *opaque, target_phys_addr_t addr,
     case 0x1ec:	/* GPMC_PREFETCH_CONTROL */
         return s->prefetch.startengine;
     case 0x1f0:	/* GPMC_PREFETCH_STATUS */
+        /* NB: The OMAP3 TRM is inconsistent about whether the GPMC
+         * FIFOTHRESHOLDSTATUS bit should be set when
+         * FIFOPOINTER > FIFOTHRESHOLD or when it is >= FIFOTHRESHOLD.
+         * Apparently the underlying functional spec from which the TRM was
+         * created states that the behaviour is ">=", and this also
+         * makes more conceptual sense.
+         */
         return (s->prefetch.fifopointer << 24) |
                 ((s->prefetch.fifopointer >=
                   ((s->prefetch.config1 >> 8) & 0x7f) ? 1 : 0) << 16) |
commit 5f5422258e1f50f871bafcc5bfb2b498f414a310
Author: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Date:   Tue Aug 2 11:35:54 2011 +0530

    hw/9pfs: Add handle based fs driver
    
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>

diff --git a/Makefile.objs b/Makefile.objs
index 1c65087..8d23fbb 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -304,11 +304,11 @@ sound-obj-$(CONFIG_HDA) += intel-hda.o hda-audio.o
 adlib.o fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0
 hw-obj-$(CONFIG_SOUND) += $(sound-obj-y)
 
-9pfs-nested-$(CONFIG_VIRTFS) = virtio-9p.o virtio-9p-debug.o
-9pfs-nested-$(CONFIG_VIRTFS) +=  virtio-9p-local.o virtio-9p-xattr.o
-9pfs-nested-$(CONFIG_VIRTFS) +=   virtio-9p-xattr-user.o virtio-9p-posix-acl.o
+9pfs-nested-$(CONFIG_VIRTFS)  = virtio-9p.o virtio-9p-debug.o
+9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-local.o virtio-9p-xattr.o
+9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-xattr-user.o virtio-9p-posix-acl.o
 9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-coth.o cofs.o codir.o cofile.o
-9pfs-nested-$(CONFIG_VIRTFS) += coxattr.o
+9pfs-nested-$(CONFIG_VIRTFS) += coxattr.o virtio-9p-handle.o
 
 hw-obj-$(CONFIG_REALLY_VIRTFS) += $(addprefix 9pfs/, $(9pfs-nested-y))
 $(addprefix 9pfs/, $(9pfs-nested-y)): QEMU_CFLAGS+=$(GLIB_CFLAGS)
diff --git a/fsdev/qemu-fsdev.c b/fsdev/qemu-fsdev.c
index 336d7e4..768819f 100644
--- a/fsdev/qemu-fsdev.c
+++ b/fsdev/qemu-fsdev.c
@@ -23,6 +23,7 @@ static QTAILQ_HEAD(FsTypeEntry_head, FsTypeListEntry) fstype_entries =
 
 static FsTypeTable FsTypes[] = {
     { .name = "local", .ops = &local_ops},
+    { .name = "handle", .ops = &handle_ops},
 };
 
 int qemu_fsdev_add(QemuOpts *opts)
diff --git a/fsdev/qemu-fsdev.h b/fsdev/qemu-fsdev.h
index f9f08d3..e04931a 100644
--- a/fsdev/qemu-fsdev.h
+++ b/fsdev/qemu-fsdev.h
@@ -52,4 +52,5 @@ typedef struct FsTypeListEntry {
 int qemu_fsdev_add(QemuOpts *opts);
 FsTypeEntry *get_fsdev_fsentry(char *id);
 extern FileOperations local_ops;
+extern FileOperations handle_ops;
 #endif
diff --git a/hw/9pfs/virtio-9p-handle.c b/hw/9pfs/virtio-9p-handle.c
new file mode 100644
index 0000000..5c8b5ed
--- /dev/null
+++ b/hw/9pfs/virtio-9p-handle.c
@@ -0,0 +1,611 @@
+/*
+ * Virtio 9p handle callback
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *    Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "hw/virtio.h"
+#include "virtio-9p.h"
+#include "virtio-9p-xattr.h"
+#include <arpa/inet.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <attr/xattr.h>
+#include <unistd.h>
+
+struct handle_data {
+    int mountfd;
+    int handle_bytes;
+};
+
+#if __GLIBC__ <= 2 && __GLIBC_MINOR__ < 14
+struct file_handle {
+        unsigned int handle_bytes;
+        int handle_type;
+        unsigned char handle[0];
+};
+#endif
+
+#ifndef AT_EMPTY_PATH
+#define AT_EMPTY_PATH   0x1000  /* Allow empty relative pathname */
+#endif
+#ifndef O_PATH
+#define O_PATH    010000000
+#endif
+
+#ifndef __NR_name_to_handle_at
+#if defined(__i386__)
+#define __NR_name_to_handle_at  341
+#define __NR_open_by_handle_at  342
+#elif defined(__x86_64__)
+#define __NR_name_to_handle_at  303
+#define __NR_open_by_handle_at  304
+#endif
+#endif
+
+#ifdef __NR_name_to_handle_at
+static inline int name_to_handle(int dirfd, const char *name,
+                                 struct file_handle *fh, int *mnt_id, int flags)
+{
+    return syscall(__NR_name_to_handle_at, dirfd, name, fh, mnt_id, flags);
+}
+
+static inline int open_by_handle(int mountfd, const char *fh, int flags)
+{
+    return syscall(__NR_open_by_handle_at, mountfd, fh, flags);
+}
+#else
+static inline int name_to_handle(int dirfd, const char *name,
+                                 struct file_handle *fh, int *mnt_id, int flags)
+{
+    errno = ENOSYS;
+    return -1;
+}
+
+static inline int open_by_handle(int mountfd, const char *fh, int flags)
+{
+    errno = ENOSYS;
+    return -1;
+}
+#endif
+
+static int handle_update_file_cred(int dirfd, const char *name, FsCred *credp)
+{
+    int fd, ret;
+    fd = openat(dirfd, name, O_NONBLOCK | O_NOFOLLOW);;
+    if (fd < 0) {
+        return fd;
+    }
+    ret = fchmod(fd, credp->fc_mode & 07777);
+    if (ret < 0) {
+        goto err_out;
+    }
+    ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH);
+err_out:
+    close(fd);
+    return ret;
+}
+
+
+static int handle_lstat(FsContext *fs_ctx, V9fsPath *fs_path,
+                        struct stat *stbuf)
+{
+    int fd, ret;
+    struct handle_data *data = (struct handle_data *)fs_ctx->private;
+
+    fd = open_by_handle(data->mountfd, fs_path->data, O_PATH);
+    if (fd < 0) {
+        return fd;
+    }
+    ret = fstatat(fd, "", stbuf, AT_EMPTY_PATH);
+    close(fd);
+    return ret;
+}
+
+static ssize_t handle_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
+                               char *buf, size_t bufsz)
+{
+    int fd, ret;
+    struct handle_data *data = (struct handle_data *)fs_ctx->private;
+
+    fd = open_by_handle(data->mountfd, fs_path->data, O_PATH);
+    if (fd < 0) {
+        return fd;
+    }
+    ret = readlinkat(fd, "", buf, bufsz);
+    close(fd);
+    return ret;
+}
+
+static int handle_close(FsContext *ctx, int fd)
+{
+    return close(fd);
+}
+
+static int handle_closedir(FsContext *ctx, DIR *dir)
+{
+    return closedir(dir);
+}
+
+static int handle_open(FsContext *ctx, V9fsPath *fs_path, int flags)
+{
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    return open_by_handle(data->mountfd, fs_path->data, flags);
+}
+
+static DIR *handle_opendir(FsContext *ctx, V9fsPath *fs_path)
+{
+    int fd;
+    fd = handle_open(ctx, fs_path, O_DIRECTORY);
+    if (fd < 0) {
+        return NULL;
+    }
+    return fdopendir(fd);
+}
+
+static void handle_rewinddir(FsContext *ctx, DIR *dir)
+{
+    return rewinddir(dir);
+}
+
+static off_t handle_telldir(FsContext *ctx, DIR *dir)
+{
+    return telldir(dir);
+}
+
+static int handle_readdir_r(FsContext *ctx, DIR *dir, struct dirent *entry,
+                            struct dirent **result)
+{
+    return readdir_r(dir, entry, result);
+}
+
+static void handle_seekdir(FsContext *ctx, DIR *dir, off_t off)
+{
+    return seekdir(dir, off);
+}
+
+static ssize_t handle_preadv(FsContext *ctx, int fd, const struct iovec *iov,
+                             int iovcnt, off_t offset)
+{
+#ifdef CONFIG_PREADV
+    return preadv(fd, iov, iovcnt, offset);
+#else
+    int err = lseek(fd, offset, SEEK_SET);
+    if (err == -1) {
+        return err;
+    } else {
+        return readv(fd, iov, iovcnt);
+    }
+#endif
+}
+
+static ssize_t handle_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
+                              int iovcnt, off_t offset)
+{
+#ifdef CONFIG_PREADV
+    return pwritev(fd, iov, iovcnt, offset);
+#else
+    int err = lseek(fd, offset, SEEK_SET);
+    if (err == -1) {
+        return err;
+    } else {
+        return writev(fd, iov, iovcnt);
+    }
+#endif
+}
+
+static int handle_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
+{
+    int fd, ret;
+    struct handle_data *data = (struct handle_data *)fs_ctx->private;
+
+    fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
+    if (fd < 0) {
+        return fd;
+    }
+    ret = fchmod(fd, credp->fc_mode);
+    close(fd);
+    return ret;
+}
+
+static int handle_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
+                       const char *name, FsCred *credp)
+{
+    int dirfd, ret;
+    struct handle_data *data = (struct handle_data *)fs_ctx->private;
+
+    dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
+    if (dirfd < 0) {
+        return dirfd;
+    }
+    ret = mknodat(dirfd, name, credp->fc_mode, credp->fc_rdev);
+    if (!ret) {
+        ret = handle_update_file_cred(dirfd, name, credp);
+    }
+    close(dirfd);
+    return ret;
+}
+
+static int handle_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
+                       const char *name, FsCred *credp)
+{
+    int dirfd, ret;
+    struct handle_data *data = (struct handle_data *)fs_ctx->private;
+
+    dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
+    if (dirfd < 0) {
+        return dirfd;
+    }
+    ret = mkdirat(dirfd, name, credp->fc_mode);
+    if (!ret) {
+        ret = handle_update_file_cred(dirfd, name, credp);
+    }
+    close(dirfd);
+    return ret;
+}
+
+static int handle_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf)
+{
+    return fstat(fd, stbuf);
+}
+
+static int handle_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
+                       int flags, FsCred *credp)
+{
+    int ret;
+    int dirfd, fd;
+    struct handle_data *data = (struct handle_data *)fs_ctx->private;
+
+    dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
+    if (dirfd < 0) {
+        return dirfd;
+    }
+    fd = openat(dirfd, name, flags | O_NOFOLLOW, credp->fc_mode);
+    if (fd >= 0) {
+        ret = handle_update_file_cred(dirfd, name, credp);
+        if (ret < 0) {
+            close(fd);
+            fd = ret;
+        }
+    }
+    close(dirfd);
+    return fd;
+}
+
+
+static int handle_symlink(FsContext *fs_ctx, const char *oldpath,
+                          V9fsPath *dir_path, const char *name, FsCred *credp)
+{
+    int fd, dirfd, ret;
+    struct handle_data *data = (struct handle_data *)fs_ctx->private;
+
+    dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
+    if (dirfd < 0) {
+        return dirfd;
+    }
+    ret = symlinkat(oldpath, dirfd, name);
+    if (!ret) {
+        fd = openat(dirfd, name, O_PATH | O_NOFOLLOW);
+        if (fd < 0) {
+            ret = fd;
+            goto err_out;
+        }
+        ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH);
+        close(fd);
+    }
+err_out:
+    close(dirfd);
+    return ret;
+}
+
+static int handle_link(FsContext *ctx, V9fsPath *oldpath,
+                       V9fsPath *dirpath, const char *name)
+{
+    int oldfd, newdirfd, ret;
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    oldfd = open_by_handle(data->mountfd, oldpath->data, O_PATH);
+    if (oldfd < 0) {
+        return oldfd;
+    }
+    newdirfd = open_by_handle(data->mountfd, dirpath->data, O_PATH);
+    if (newdirfd < 0) {
+        close(oldfd);
+        return newdirfd;
+    }
+    ret = linkat(oldfd, "", newdirfd, name, AT_EMPTY_PATH);
+    close(newdirfd);
+    close(oldfd);
+    return ret;
+}
+
+static int handle_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
+{
+    int fd, ret;
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK | O_WRONLY);
+    if (fd < 0) {
+        return fd;
+    }
+    ret = ftruncate(fd, size);
+    close(fd);
+    return ret;
+}
+
+static int handle_rename(FsContext *ctx, const char *oldpath,
+                         const char *newpath)
+{
+    errno = EOPNOTSUPP;
+    return -1;
+}
+
+static int handle_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
+{
+    int fd, ret;
+    struct handle_data *data = (struct handle_data *)fs_ctx->private;
+
+    fd = open_by_handle(data->mountfd, fs_path->data, O_PATH);
+    if (fd < 0) {
+        return fd;
+    }
+    ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH);
+    close(fd);
+    return ret;
+}
+
+static int handle_utimensat(FsContext *ctx, V9fsPath *fs_path,
+                            const struct timespec *buf)
+{
+    int fd, ret;
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
+    if (fd < 0) {
+        return fd;
+    }
+    ret = futimens(fd, buf);
+    close(fd);
+    return ret;
+}
+
+static int handle_remove(FsContext *ctx, const char *path)
+{
+    errno = EOPNOTSUPP;
+    return -1;
+}
+
+static int handle_fsync(FsContext *ctx, int fd, int datasync)
+{
+    if (datasync) {
+        return qemu_fdatasync(fd);
+    } else {
+        return fsync(fd);
+    }
+}
+
+static int handle_statfs(FsContext *ctx, V9fsPath *fs_path,
+                         struct statfs *stbuf)
+{
+    int fd, ret;
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
+    if (fd < 0) {
+        return fd;
+    }
+    ret = fstatfs(fd, stbuf);
+    close(fd);
+    return ret;
+}
+
+static ssize_t handle_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
+                                const char *name, void *value, size_t size)
+{
+    int fd, ret;
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
+    if (fd < 0) {
+        return fd;
+    }
+    ret = fgetxattr(fd, name, value, size);
+    close(fd);
+    return ret;
+}
+
+static ssize_t handle_llistxattr(FsContext *ctx, V9fsPath *fs_path,
+                                 void *value, size_t size)
+{
+    int fd, ret;
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
+    if (fd < 0) {
+        return fd;
+    }
+    ret = flistxattr(fd, value, size);
+    close(fd);
+    return ret;
+}
+
+static int handle_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
+                            void *value, size_t size, int flags)
+{
+    int fd, ret;
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
+    if (fd < 0) {
+        return fd;
+    }
+    ret = fsetxattr(fd, name, value, size, flags);
+    close(fd);
+    return ret;
+}
+
+static int handle_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
+                               const char *name)
+{
+    int fd, ret;
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
+    if (fd < 0) {
+        return fd;
+    }
+    ret = fremovexattr(fd, name);
+    close(fd);
+    return ret;
+}
+
+static int handle_name_to_path(FsContext *ctx, V9fsPath *dir_path,
+                              const char *name, V9fsPath *target)
+{
+    char buffer[PATH_MAX];
+    struct file_handle *fh;
+    int dirfd, ret, mnt_id;
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    /* "." and ".." are not allowed */
+    if (!strcmp(name, ".") || !strcmp(name, "..")) {
+        errno = EINVAL;
+        return -1;
+
+    }
+    if (dir_path) {
+        dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
+    } else {
+        /* relative to export root */
+        dirfd = open(rpath(ctx, ".", buffer), O_DIRECTORY);
+    }
+    if (dirfd < 0) {
+        return dirfd;
+    }
+    fh = g_malloc(sizeof(struct file_handle) + data->handle_bytes);
+    fh->handle_bytes = data->handle_bytes;
+    /* add a "./" at the begining of the path */
+    snprintf(buffer, PATH_MAX, "./%s", name);
+    /* flag = 0 imply don't follow symlink */
+    ret = name_to_handle(dirfd, buffer, fh, &mnt_id, 0);
+    if (!ret) {
+        target->data = (char *)fh;
+        target->size = sizeof(struct file_handle) + data->handle_bytes;
+    } else {
+        g_free(fh);
+    }
+    close(dirfd);
+    return ret;
+}
+
+static int handle_renameat(FsContext *ctx, V9fsPath *olddir,
+                           const char *old_name, V9fsPath *newdir,
+                           const char *new_name)
+{
+    int olddirfd, newdirfd, ret;
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    olddirfd = open_by_handle(data->mountfd, olddir->data, O_PATH);
+    if (olddirfd < 0) {
+        return olddirfd;
+    }
+    newdirfd = open_by_handle(data->mountfd, newdir->data, O_PATH);
+    if (newdirfd < 0) {
+        close(olddirfd);
+        return newdirfd;
+    }
+    ret = renameat(olddirfd, old_name, newdirfd, new_name);
+    close(newdirfd);
+    close(olddirfd);
+    return ret;
+}
+
+static int handle_unlinkat(FsContext *ctx, V9fsPath *dir,
+                           const char *name, int flags)
+{
+    int dirfd, ret;
+    struct handle_data *data = (struct handle_data *)ctx->private;
+
+    dirfd = open_by_handle(data->mountfd, dir->data, O_PATH);
+    if (dirfd < 0) {
+        return dirfd;
+    }
+
+    ret = unlinkat(dirfd, name, flags);
+    close(dirfd);
+    return ret;
+}
+
+static int handle_init(FsContext *ctx)
+{
+    int ret, mnt_id;
+    struct file_handle fh;
+    struct handle_data *data = g_malloc(sizeof(struct handle_data));
+    data->mountfd = open(ctx->fs_root, O_DIRECTORY);
+    if (data->mountfd < 0) {
+        ret = data->mountfd;
+        goto err_out;
+    }
+    memset(&fh, 0, sizeof(struct file_handle));
+    ret = name_to_handle(data->mountfd, ".", &fh, &mnt_id, 0);
+    if (ret && errno == EOVERFLOW) {
+        data->handle_bytes = fh.handle_bytes;
+        ctx->private = data;
+        ret = 0;
+        goto out;
+    }
+    /* we got 0 byte handle ? */
+    ret = -1;
+    close(data->mountfd);
+err_out:
+    g_free(data);
+out:
+    return ret;
+}
+
+FileOperations handle_ops = {
+    .init         = handle_init,
+    .lstat        = handle_lstat,
+    .readlink     = handle_readlink,
+    .close        = handle_close,
+    .closedir     = handle_closedir,
+    .open         = handle_open,
+    .opendir      = handle_opendir,
+    .rewinddir    = handle_rewinddir,
+    .telldir      = handle_telldir,
+    .readdir_r    = handle_readdir_r,
+    .seekdir      = handle_seekdir,
+    .preadv       = handle_preadv,
+    .pwritev      = handle_pwritev,
+    .chmod        = handle_chmod,
+    .mknod        = handle_mknod,
+    .mkdir        = handle_mkdir,
+    .fstat        = handle_fstat,
+    .open2        = handle_open2,
+    .symlink      = handle_symlink,
+    .link         = handle_link,
+    .truncate     = handle_truncate,
+    .rename       = handle_rename,
+    .chown        = handle_chown,
+    .utimensat    = handle_utimensat,
+    .remove       = handle_remove,
+    .fsync        = handle_fsync,
+    .statfs       = handle_statfs,
+    .lgetxattr    = handle_lgetxattr,
+    .llistxattr   = handle_llistxattr,
+    .lsetxattr    = handle_lsetxattr,
+    .lremovexattr = handle_lremovexattr,
+    .name_to_path = handle_name_to_path,
+    .renameat     = handle_renameat,
+    .unlinkat     = handle_unlinkat,
+};
commit bccacf6c7920ee46ec4063c4bd9469eb3ec4e253
Author: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Date:   Tue Aug 2 11:36:17 2011 +0530

    hw/9pfs: Implement TFLUSH operation
    
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>

diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c
index b379f93..72732e7 100644
--- a/hw/9pfs/codir.c
+++ b/hw/9pfs/codir.c
@@ -17,11 +17,15 @@
 #include "qemu-coroutine.h"
 #include "virtio-9p-coth.h"
 
-int v9fs_co_readdir_r(V9fsState *s, V9fsFidState *fidp, struct dirent *dent,
+int v9fs_co_readdir_r(V9fsPDU *pdu, V9fsFidState *fidp, struct dirent *dent,
                       struct dirent **result)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_co_run_in_worker(
         {
             errno = 0;
@@ -35,10 +39,14 @@ int v9fs_co_readdir_r(V9fsState *s, V9fsFidState *fidp, struct dirent *dent,
     return err;
 }
 
-off_t v9fs_co_telldir(V9fsState *s, V9fsFidState *fidp)
+off_t v9fs_co_telldir(V9fsPDU *pdu, V9fsFidState *fidp)
 {
     off_t err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_co_run_in_worker(
         {
             err = s->ops->telldir(&s->ctx, fidp->fs.dir);
@@ -49,29 +57,41 @@ off_t v9fs_co_telldir(V9fsState *s, V9fsFidState *fidp)
     return err;
 }
 
-void v9fs_co_seekdir(V9fsState *s, V9fsFidState *fidp, off_t offset)
+void v9fs_co_seekdir(V9fsPDU *pdu, V9fsFidState *fidp, off_t offset)
 {
+    V9fsState *s = pdu->s;
+    if (v9fs_request_cancelled(pdu)) {
+        return;
+    }
     v9fs_co_run_in_worker(
         {
             s->ops->seekdir(&s->ctx, fidp->fs.dir, offset);
         });
 }
 
-void v9fs_co_rewinddir(V9fsState *s, V9fsFidState *fidp)
+void v9fs_co_rewinddir(V9fsPDU *pdu, V9fsFidState *fidp)
 {
+    V9fsState *s = pdu->s;
+    if (v9fs_request_cancelled(pdu)) {
+        return;
+    }
     v9fs_co_run_in_worker(
         {
             s->ops->rewinddir(&s->ctx, fidp->fs.dir);
         });
 }
 
-int v9fs_co_mkdir(V9fsState *s, V9fsFidState *fidp, V9fsString *name,
+int v9fs_co_mkdir(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name,
                   mode_t mode, uid_t uid, gid_t gid, struct stat *stbuf)
 {
     int err;
     FsCred cred;
     V9fsPath path;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;;
+    }
     cred_init(&cred);
     cred.fc_mode = mode;
     cred.fc_uid = uid;
@@ -98,10 +118,14 @@ int v9fs_co_mkdir(V9fsState *s, V9fsFidState *fidp, V9fsString *name,
     return err;
 }
 
-int v9fs_co_opendir(V9fsState *s, V9fsFidState *fidp)
+int v9fs_co_opendir(V9fsPDU *pdu, V9fsFidState *fidp)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;;
+    }
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
@@ -116,16 +140,20 @@ int v9fs_co_opendir(V9fsState *s, V9fsFidState *fidp)
     if (!err) {
         total_open_fd++;
         if (total_open_fd > open_fd_hw) {
-            v9fs_reclaim_fd(s);
+            v9fs_reclaim_fd(pdu);
         }
     }
     return err;
 }
 
-int v9fs_co_closedir(V9fsState *s, DIR *dir)
+int v9fs_co_closedir(V9fsPDU *pdu, DIR *dir)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;;
+    }
     v9fs_co_run_in_worker(
         {
             err = s->ops->closedir(&s->ctx, dir);
diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c
index 1a99adc..7ad4bec 100644
--- a/hw/9pfs/cofile.c
+++ b/hw/9pfs/cofile.c
@@ -17,10 +17,14 @@
 #include "qemu-coroutine.h"
 #include "virtio-9p-coth.h"
 
-int v9fs_co_lstat(V9fsState *s, V9fsPath *path, struct stat *stbuf)
+int v9fs_co_lstat(V9fsPDU *pdu, V9fsPath *path, struct stat *stbuf)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
@@ -33,10 +37,14 @@ int v9fs_co_lstat(V9fsState *s, V9fsPath *path, struct stat *stbuf)
     return err;
 }
 
-int v9fs_co_fstat(V9fsState *s, int fd, struct stat *stbuf)
+int v9fs_co_fstat(V9fsPDU *pdu, int fd, struct stat *stbuf)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_co_run_in_worker(
         {
             err = s->ops->fstat(&s->ctx, fd, stbuf);
@@ -47,10 +55,14 @@ int v9fs_co_fstat(V9fsState *s, int fd, struct stat *stbuf)
     return err;
 }
 
-int v9fs_co_open(V9fsState *s, V9fsFidState *fidp, int flags)
+int v9fs_co_open(V9fsPDU *pdu, V9fsFidState *fidp, int flags)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
@@ -65,20 +77,23 @@ int v9fs_co_open(V9fsState *s, V9fsFidState *fidp, int flags)
     if (!err) {
         total_open_fd++;
         if (total_open_fd > open_fd_hw) {
-            v9fs_reclaim_fd(s);
+            v9fs_reclaim_fd(pdu);
         }
     }
     return err;
 }
 
-int v9fs_co_open2(V9fsState *s, V9fsFidState *fidp, V9fsString *name, gid_t gid,
+int v9fs_co_open2(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, gid_t gid,
                   int flags, int mode, struct stat *stbuf)
 {
     int err;
     FsCred cred;
     V9fsPath path;
+    V9fsState *s = pdu->s;
 
-
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     cred_init(&cred);
     cred.fc_mode = mode & 07777;
     cred.fc_uid = fidp->uid;
@@ -116,16 +131,20 @@ int v9fs_co_open2(V9fsState *s, V9fsFidState *fidp, V9fsString *name, gid_t gid,
     if (!err) {
         total_open_fd++;
         if (total_open_fd > open_fd_hw) {
-            v9fs_reclaim_fd(s);
+            v9fs_reclaim_fd(pdu);
         }
     }
     return err;
 }
 
-int v9fs_co_close(V9fsState *s, int fd)
+int v9fs_co_close(V9fsPDU *pdu, int fd)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_co_run_in_worker(
         {
             err = s->ops->close(&s->ctx, fd);
@@ -139,11 +158,14 @@ int v9fs_co_close(V9fsState *s, int fd)
     return err;
 }
 
-int v9fs_co_fsync(V9fsState *s, V9fsFidState *fidp, int datasync)
+int v9fs_co_fsync(V9fsPDU *pdu, V9fsFidState *fidp, int datasync)
 {
-    int fd;
-    int err;
+    int fd, err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     fd = fidp->fs.fd;
     v9fs_co_run_in_worker(
         {
@@ -155,11 +177,15 @@ int v9fs_co_fsync(V9fsState *s, V9fsFidState *fidp, int datasync)
     return err;
 }
 
-int v9fs_co_link(V9fsState *s, V9fsFidState *oldfid,
+int v9fs_co_link(V9fsPDU *pdu, V9fsFidState *oldfid,
                  V9fsFidState *newdirfid, V9fsString *name)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
@@ -173,12 +199,15 @@ int v9fs_co_link(V9fsState *s, V9fsFidState *oldfid,
     return err;
 }
 
-int v9fs_co_pwritev(V9fsState *s, V9fsFidState *fidp,
+int v9fs_co_pwritev(V9fsPDU *pdu, V9fsFidState *fidp,
                     struct iovec *iov, int iovcnt, int64_t offset)
 {
-    int fd;
-    int err;
+    int fd, err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     fd = fidp->fs.fd;
     v9fs_co_run_in_worker(
         {
@@ -190,12 +219,15 @@ int v9fs_co_pwritev(V9fsState *s, V9fsFidState *fidp,
     return err;
 }
 
-int v9fs_co_preadv(V9fsState *s, V9fsFidState *fidp,
+int v9fs_co_preadv(V9fsPDU *pdu, V9fsFidState *fidp,
                    struct iovec *iov, int iovcnt, int64_t offset)
 {
-    int fd;
-    int err;
+    int fd, err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     fd = fidp->fs.fd;
     v9fs_co_run_in_worker(
         {
diff --git a/hw/9pfs/cofs.c b/hw/9pfs/cofs.c
index 9c3c9e9..68745ad 100644
--- a/hw/9pfs/cofs.c
+++ b/hw/9pfs/cofs.c
@@ -17,11 +17,15 @@
 #include "qemu-coroutine.h"
 #include "virtio-9p-coth.h"
 
-int v9fs_co_readlink(V9fsState *s, V9fsPath *path, V9fsString *buf)
+int v9fs_co_readlink(V9fsPDU *pdu, V9fsPath *path, V9fsString *buf)
 {
     int err;
     ssize_t len;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     buf->data = g_malloc(PATH_MAX);
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
@@ -45,10 +49,14 @@ int v9fs_co_readlink(V9fsState *s, V9fsPath *path, V9fsString *buf)
     return err;
 }
 
-int v9fs_co_statfs(V9fsState *s, V9fsPath *path, struct statfs *stbuf)
+int v9fs_co_statfs(V9fsPDU *pdu, V9fsPath *path, struct statfs *stbuf)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
@@ -61,11 +69,15 @@ int v9fs_co_statfs(V9fsState *s, V9fsPath *path, struct statfs *stbuf)
     return err;
 }
 
-int v9fs_co_chmod(V9fsState *s, V9fsPath *path, mode_t mode)
+int v9fs_co_chmod(V9fsPDU *pdu, V9fsPath *path, mode_t mode)
 {
     int err;
     FsCred cred;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     cred_init(&cred);
     cred.fc_mode = mode;
     v9fs_path_read_lock(s);
@@ -80,11 +92,15 @@ int v9fs_co_chmod(V9fsState *s, V9fsPath *path, mode_t mode)
     return err;
 }
 
-int v9fs_co_utimensat(V9fsState *s, V9fsPath *path,
+int v9fs_co_utimensat(V9fsPDU *pdu, V9fsPath *path,
                       struct timespec times[2])
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
@@ -97,11 +113,15 @@ int v9fs_co_utimensat(V9fsState *s, V9fsPath *path,
     return err;
 }
 
-int v9fs_co_chown(V9fsState *s, V9fsPath *path, uid_t uid, gid_t gid)
+int v9fs_co_chown(V9fsPDU *pdu, V9fsPath *path, uid_t uid, gid_t gid)
 {
     int err;
     FsCred cred;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     cred_init(&cred);
     cred.fc_uid = uid;
     cred.fc_gid = gid;
@@ -117,10 +137,14 @@ int v9fs_co_chown(V9fsState *s, V9fsPath *path, uid_t uid, gid_t gid)
     return err;
 }
 
-int v9fs_co_truncate(V9fsState *s, V9fsPath *path, off_t size)
+int v9fs_co_truncate(V9fsPDU *pdu, V9fsPath *path, off_t size)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
@@ -133,13 +157,17 @@ int v9fs_co_truncate(V9fsState *s, V9fsPath *path, off_t size)
     return err;
 }
 
-int v9fs_co_mknod(V9fsState *s, V9fsFidState *fidp, V9fsString *name, uid_t uid,
+int v9fs_co_mknod(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, uid_t uid,
                   gid_t gid, dev_t dev, mode_t mode, struct stat *stbuf)
 {
     int err;
     V9fsPath path;
     FsCred cred;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     cred_init(&cred);
     cred.fc_uid  = uid;
     cred.fc_gid  = gid;
@@ -168,10 +196,14 @@ int v9fs_co_mknod(V9fsState *s, V9fsFidState *fidp, V9fsString *name, uid_t uid,
 }
 
 /* Only works with path name based fid */
-int v9fs_co_remove(V9fsState *s, V9fsPath *path)
+int v9fs_co_remove(V9fsPDU *pdu, V9fsPath *path)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
@@ -184,10 +216,14 @@ int v9fs_co_remove(V9fsState *s, V9fsPath *path)
     return err;
 }
 
-int v9fs_co_unlinkat(V9fsState *s, V9fsPath *path, V9fsString *name, int flags)
+int v9fs_co_unlinkat(V9fsPDU *pdu, V9fsPath *path, V9fsString *name, int flags)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
@@ -201,10 +237,14 @@ int v9fs_co_unlinkat(V9fsState *s, V9fsPath *path, V9fsString *name, int flags)
 }
 
 /* Only work with path name based fid */
-int v9fs_co_rename(V9fsState *s, V9fsPath *oldpath, V9fsPath *newpath)
+int v9fs_co_rename(V9fsPDU *pdu, V9fsPath *oldpath, V9fsPath *newpath)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_co_run_in_worker(
         {
             err = s->ops->rename(&s->ctx, oldpath->data, newpath->data);
@@ -215,11 +255,15 @@ int v9fs_co_rename(V9fsState *s, V9fsPath *oldpath, V9fsPath *newpath)
     return err;
 }
 
-int v9fs_co_renameat(V9fsState *s, V9fsPath *olddirpath, V9fsString *oldname,
+int v9fs_co_renameat(V9fsPDU *pdu, V9fsPath *olddirpath, V9fsString *oldname,
                      V9fsPath *newdirpath, V9fsString *newname)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_co_run_in_worker(
         {
             err = s->ops->renameat(&s->ctx, olddirpath, oldname->data,
@@ -231,14 +275,17 @@ int v9fs_co_renameat(V9fsState *s, V9fsPath *olddirpath, V9fsString *oldname,
     return err;
 }
 
-int v9fs_co_symlink(V9fsState *s, V9fsFidState *dfidp, V9fsString *name,
+int v9fs_co_symlink(V9fsPDU *pdu, V9fsFidState *dfidp, V9fsString *name,
                     const char *oldpath, gid_t gid, struct stat *stbuf)
 {
     int err;
     FsCred cred;
     V9fsPath path;
+    V9fsState *s = pdu->s;
 
-
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     cred_init(&cred);
     cred.fc_uid = dfidp->uid;
     cred.fc_gid = gid;
@@ -270,10 +317,11 @@ int v9fs_co_symlink(V9fsState *s, V9fsFidState *dfidp, V9fsString *name,
  * For path name based fid we don't block. So we can
  * directly call the fs driver ops.
  */
-int v9fs_co_name_to_path(V9fsState *s, V9fsPath *dirpath,
+int v9fs_co_name_to_path(V9fsPDU *pdu, V9fsPath *dirpath,
                          const char *name, V9fsPath *path)
 {
     int err;
+    V9fsState *s = pdu->s;
 
     if (s->ctx.flags & PATHNAME_FSCONTEXT) {
         err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
@@ -281,6 +329,9 @@ int v9fs_co_name_to_path(V9fsState *s, V9fsPath *dirpath,
             err = -errno;
         }
     } else {
+        if (v9fs_request_cancelled(pdu)) {
+            return -EINTR;
+        }
         v9fs_co_run_in_worker(
             {
                 err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
diff --git a/hw/9pfs/coxattr.c b/hw/9pfs/coxattr.c
index dd2e4a5..8a48228 100644
--- a/hw/9pfs/coxattr.c
+++ b/hw/9pfs/coxattr.c
@@ -17,10 +17,14 @@
 #include "qemu-coroutine.h"
 #include "virtio-9p-coth.h"
 
-int v9fs_co_llistxattr(V9fsState *s, V9fsPath *path, void *value, size_t size)
+int v9fs_co_llistxattr(V9fsPDU *pdu, V9fsPath *path, void *value, size_t size)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
@@ -33,12 +37,16 @@ int v9fs_co_llistxattr(V9fsState *s, V9fsPath *path, void *value, size_t size)
     return err;
 }
 
-int v9fs_co_lgetxattr(V9fsState *s, V9fsPath *path,
+int v9fs_co_lgetxattr(V9fsPDU *pdu, V9fsPath *path,
                       V9fsString *xattr_name,
                       void *value, size_t size)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
@@ -53,12 +61,16 @@ int v9fs_co_lgetxattr(V9fsState *s, V9fsPath *path,
     return err;
 }
 
-int v9fs_co_lsetxattr(V9fsState *s, V9fsPath *path,
+int v9fs_co_lsetxattr(V9fsPDU *pdu, V9fsPath *path,
                       V9fsString *xattr_name, void *value,
                       size_t size, int flags)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
@@ -73,11 +85,15 @@ int v9fs_co_lsetxattr(V9fsState *s, V9fsPath *path,
     return err;
 }
 
-int v9fs_co_lremovexattr(V9fsState *s, V9fsPath *path,
+int v9fs_co_lremovexattr(V9fsPDU *pdu, V9fsPath *path,
                          V9fsString *xattr_name)
 {
     int err;
+    V9fsState *s = pdu->s;
 
+    if (v9fs_request_cancelled(pdu)) {
+        return -EINTR;
+    }
     v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
diff --git a/hw/9pfs/virtio-9p-coth.h b/hw/9pfs/virtio-9p-coth.h
index cd94571..4630080 100644
--- a/hw/9pfs/virtio-9p-coth.h
+++ b/hw/9pfs/virtio-9p-coth.h
@@ -56,49 +56,49 @@ typedef struct V9fsThPool {
 
 extern void co_run_in_worker_bh(void *);
 extern int v9fs_init_worker_threads(void);
-extern int v9fs_co_readlink(V9fsState *, V9fsPath *, V9fsString *);
-extern int v9fs_co_readdir_r(V9fsState *, V9fsFidState *,
+extern int v9fs_co_readlink(V9fsPDU *, V9fsPath *, V9fsString *);
+extern int v9fs_co_readdir_r(V9fsPDU *, V9fsFidState *,
                            struct dirent *, struct dirent **result);
-extern off_t v9fs_co_telldir(V9fsState *, V9fsFidState *);
-extern void v9fs_co_seekdir(V9fsState *, V9fsFidState *, off_t);
-extern void v9fs_co_rewinddir(V9fsState *, V9fsFidState *);
-extern int v9fs_co_statfs(V9fsState *, V9fsPath *, struct statfs *);
-extern int v9fs_co_lstat(V9fsState *, V9fsPath *, struct stat *);
-extern int v9fs_co_chmod(V9fsState *, V9fsPath *, mode_t);
-extern int v9fs_co_utimensat(V9fsState *, V9fsPath *, struct timespec [2]);
-extern int v9fs_co_chown(V9fsState *, V9fsPath *, uid_t, gid_t);
-extern int v9fs_co_truncate(V9fsState *, V9fsPath *, off_t);
-extern int v9fs_co_llistxattr(V9fsState *, V9fsPath *, void *, size_t);
-extern int v9fs_co_lgetxattr(V9fsState *, V9fsPath *,
+extern off_t v9fs_co_telldir(V9fsPDU *, V9fsFidState *);
+extern void v9fs_co_seekdir(V9fsPDU *, V9fsFidState *, off_t);
+extern void v9fs_co_rewinddir(V9fsPDU *, V9fsFidState *);
+extern int v9fs_co_statfs(V9fsPDU *, V9fsPath *, struct statfs *);
+extern int v9fs_co_lstat(V9fsPDU *, V9fsPath *, struct stat *);
+extern int v9fs_co_chmod(V9fsPDU *, V9fsPath *, mode_t);
+extern int v9fs_co_utimensat(V9fsPDU *, V9fsPath *, struct timespec [2]);
+extern int v9fs_co_chown(V9fsPDU *, V9fsPath *, uid_t, gid_t);
+extern int v9fs_co_truncate(V9fsPDU *, V9fsPath *, off_t);
+extern int v9fs_co_llistxattr(V9fsPDU *, V9fsPath *, void *, size_t);
+extern int v9fs_co_lgetxattr(V9fsPDU *, V9fsPath *,
                              V9fsString *, void *, size_t);
-extern int v9fs_co_mknod(V9fsState *, V9fsFidState *, V9fsString *, uid_t,
+extern int v9fs_co_mknod(V9fsPDU *, V9fsFidState *, V9fsString *, uid_t,
                          gid_t, dev_t, mode_t, struct stat *);
-extern int v9fs_co_mkdir(V9fsState *, V9fsFidState *, V9fsString *,
+extern int v9fs_co_mkdir(V9fsPDU *, V9fsFidState *, V9fsString *,
                          mode_t, uid_t, gid_t, struct stat *);
-extern int v9fs_co_remove(V9fsState *, V9fsPath *);
-extern int v9fs_co_rename(V9fsState *, V9fsPath *, V9fsPath *);
-extern int v9fs_co_unlinkat(V9fsState *, V9fsPath *, V9fsString *, int flags);
-extern int v9fs_co_renameat(V9fsState *, V9fsPath *, V9fsString *,
+extern int v9fs_co_remove(V9fsPDU *, V9fsPath *);
+extern int v9fs_co_rename(V9fsPDU *, V9fsPath *, V9fsPath *);
+extern int v9fs_co_unlinkat(V9fsPDU *, V9fsPath *, V9fsString *, int flags);
+extern int v9fs_co_renameat(V9fsPDU *, V9fsPath *, V9fsString *,
                             V9fsPath *, V9fsString *);
-extern int v9fs_co_fstat(V9fsState *, int, struct stat *);
-extern int v9fs_co_opendir(V9fsState *, V9fsFidState *);
-extern int v9fs_co_open(V9fsState *, V9fsFidState *, int);
-extern int v9fs_co_open2(V9fsState *, V9fsFidState *, V9fsString *,
+extern int v9fs_co_fstat(V9fsPDU *, int, struct stat *);
+extern int v9fs_co_opendir(V9fsPDU *, V9fsFidState *);
+extern int v9fs_co_open(V9fsPDU *, V9fsFidState *, int);
+extern int v9fs_co_open2(V9fsPDU *, V9fsFidState *, V9fsString *,
                          gid_t, int, int, struct stat *);
-extern int v9fs_co_lsetxattr(V9fsState *, V9fsPath *, V9fsString *,
+extern int v9fs_co_lsetxattr(V9fsPDU *, V9fsPath *, V9fsString *,
                              void *, size_t, int);
-extern int v9fs_co_lremovexattr(V9fsState *, V9fsPath *, V9fsString *);
-extern int v9fs_co_closedir(V9fsState *, DIR *);
-extern int v9fs_co_close(V9fsState *, int);
-extern int v9fs_co_fsync(V9fsState *, V9fsFidState *, int);
-extern int v9fs_co_symlink(V9fsState *, V9fsFidState *, V9fsString *,
+extern int v9fs_co_lremovexattr(V9fsPDU *, V9fsPath *, V9fsString *);
+extern int v9fs_co_closedir(V9fsPDU *, DIR *);
+extern int v9fs_co_close(V9fsPDU *, int);
+extern int v9fs_co_fsync(V9fsPDU *, V9fsFidState *, int);
+extern int v9fs_co_symlink(V9fsPDU *, V9fsFidState *, V9fsString *,
                            const char *, gid_t, struct stat *);
-extern int v9fs_co_link(V9fsState *, V9fsFidState *,
+extern int v9fs_co_link(V9fsPDU *, V9fsFidState *,
                         V9fsFidState *, V9fsString *);
-extern int v9fs_co_pwritev(V9fsState *, V9fsFidState *,
+extern int v9fs_co_pwritev(V9fsPDU *, V9fsFidState *,
                            struct iovec *, int, int64_t);
-extern int v9fs_co_preadv(V9fsState *, V9fsFidState *,
+extern int v9fs_co_preadv(V9fsPDU *, V9fsFidState *,
                           struct iovec *, int, int64_t);
-extern int v9fs_co_name_to_path(V9fsState *, V9fsPath *,
+extern int v9fs_co_name_to_path(V9fsPDU *, V9fsPath *,
                                 const char *, V9fsPath *);
 #endif
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index 320ed95..513e181 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -58,6 +58,7 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
                                     sizeof(V9fsState));
     /* initialize pdu allocator */
     QLIST_INIT(&s->free_list);
+    QLIST_INIT(&s->active_list);
     for (i = 0; i < (MAX_REQ - 1); i++) {
         QLIST_INSERT_HEAD(&s->free_list, &s->pdus[i], next);
     }
diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index e51df2a..c01c31a 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -269,29 +269,30 @@ static size_t v9fs_string_size(V9fsString *str)
 
 /*
  * returns 0 if fid got re-opened, 1 if not, < 0 on error */
-static int v9fs_reopen_fid(V9fsState *s, V9fsFidState *f)
+static int v9fs_reopen_fid(V9fsPDU *pdu, V9fsFidState *f)
 {
     int err = 1;
     if (f->fid_type == P9_FID_FILE) {
         if (f->fs.fd == -1) {
             do {
-                err = v9fs_co_open(s, f, f->open_flags);
-            } while (err == -EINTR);
+                err = v9fs_co_open(pdu, f, f->open_flags);
+            } while (err == -EINTR && !pdu->cancelled);
         }
     } else if (f->fid_type == P9_FID_DIR) {
         if (f->fs.dir == NULL) {
             do {
-                err = v9fs_co_opendir(s, f);
-            } while (err == -EINTR);
+                err = v9fs_co_opendir(pdu, f);
+            } while (err == -EINTR && !pdu->cancelled);
         }
     }
     return err;
 }
 
-static V9fsFidState *get_fid(V9fsState *s, int32_t fid)
+static V9fsFidState *get_fid(V9fsPDU *pdu, int32_t fid)
 {
     int err;
     V9fsFidState *f;
+    V9fsState *s = pdu->s;
 
     for (f = s->fid_list; f; f = f->next) {
         BUG_ON(f->clunked);
@@ -308,7 +309,7 @@ static V9fsFidState *get_fid(V9fsState *s, int32_t fid)
              * while trying to free up some file
              * descriptors.
              */
-            err = v9fs_reopen_fid(s, f);
+            err = v9fs_reopen_fid(pdu, f);
             if (err < 0) {
                 f->ref--;
                 return NULL;
@@ -350,7 +351,7 @@ static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
     return f;
 }
 
-static int v9fs_xattr_fid_clunk(V9fsState *s, V9fsFidState *fidp)
+static int v9fs_xattr_fid_clunk(V9fsPDU *pdu, V9fsFidState *fidp)
 {
     int retval = 0;
 
@@ -368,12 +369,12 @@ static int v9fs_xattr_fid_clunk(V9fsState *s, V9fsFidState *fidp)
         goto free_out;
     }
     if (fidp->fs.xattr.len) {
-        retval = v9fs_co_lsetxattr(s, &fidp->path, &fidp->fs.xattr.name,
+        retval = v9fs_co_lsetxattr(pdu, &fidp->path, &fidp->fs.xattr.name,
                                    fidp->fs.xattr.value,
                                    fidp->fs.xattr.len,
                                    fidp->fs.xattr.flags);
     } else {
-        retval = v9fs_co_lremovexattr(s, &fidp->path, &fidp->fs.xattr.name);
+        retval = v9fs_co_lremovexattr(pdu, &fidp->path, &fidp->fs.xattr.name);
     }
 free_out:
     v9fs_string_free(&fidp->fs.xattr.name);
@@ -384,28 +385,28 @@ free_value:
     return retval;
 }
 
-static int free_fid(V9fsState *s, V9fsFidState *fidp)
+static int free_fid(V9fsPDU *pdu, V9fsFidState *fidp)
 {
     int retval = 0;
 
     if (fidp->fid_type == P9_FID_FILE) {
         /* If we reclaimed the fd no need to close */
         if (fidp->fs.fd != -1) {
-            retval = v9fs_co_close(s, fidp->fs.fd);
+            retval = v9fs_co_close(pdu, fidp->fs.fd);
         }
     } else if (fidp->fid_type == P9_FID_DIR) {
         if (fidp->fs.dir != NULL) {
-            retval = v9fs_co_closedir(s, fidp->fs.dir);
+            retval = v9fs_co_closedir(pdu, fidp->fs.dir);
         }
     } else if (fidp->fid_type == P9_FID_XATTR) {
-        retval = v9fs_xattr_fid_clunk(s, fidp);
+        retval = v9fs_xattr_fid_clunk(pdu, fidp);
     }
     v9fs_path_free(&fidp->path);
     g_free(fidp);
     return retval;
 }
 
-static void put_fid(V9fsState *s, V9fsFidState *fidp)
+static void put_fid(V9fsPDU *pdu, V9fsFidState *fidp)
 {
     BUG_ON(!fidp->ref);
     fidp->ref--;
@@ -413,7 +414,7 @@ static void put_fid(V9fsState *s, V9fsFidState *fidp)
      * Don't free the fid if it is in reclaim list
      */
     if (!fidp->ref && fidp->clunked) {
-        free_fid(s, fidp);
+        free_fid(pdu, fidp);
     }
 }
 
@@ -435,9 +436,10 @@ static V9fsFidState *clunk_fid(V9fsState *s, int32_t fid)
     return fidp;
 }
 
-void v9fs_reclaim_fd(V9fsState *s)
+void v9fs_reclaim_fd(V9fsPDU *pdu)
 {
     int reclaim_count = 0;
+    V9fsState *s = pdu->s;
     V9fsFidState *f, *reclaim_list = NULL;
 
     for (f = s->fid_list; f; f = f->next) {
@@ -502,22 +504,23 @@ void v9fs_reclaim_fd(V9fsState *s)
         f = reclaim_list;
         reclaim_list = f->rclm_lst;
         if (f->fid_type == P9_FID_FILE) {
-            v9fs_co_close(s, f->fs_reclaim.fd);
+            v9fs_co_close(pdu, f->fs_reclaim.fd);
         } else if (f->fid_type == P9_FID_DIR) {
-            v9fs_co_closedir(s, f->fs_reclaim.dir);
+            v9fs_co_closedir(pdu, f->fs_reclaim.dir);
         }
         f->rclm_lst = NULL;
         /*
          * Now drop the fid reference, free it
          * if clunked.
          */
-        put_fid(s, f);
+        put_fid(pdu, f);
     }
 }
 
-static int v9fs_mark_fids_unreclaim(V9fsState *s, V9fsPath *path)
+static int v9fs_mark_fids_unreclaim(V9fsPDU *pdu, V9fsPath *path)
 {
     int err;
+    V9fsState *s = pdu->s;
     V9fsFidState *fidp, head_fid;
 
     head_fid.next = s->fid_list;
@@ -530,7 +533,7 @@ static int v9fs_mark_fids_unreclaim(V9fsState *s, V9fsPath *path)
             fidp->flags |= FID_NON_RECLAIMABLE;
 
             /* reopen the file/dir if already closed */
-            err = v9fs_reopen_fid(s, fidp);
+            err = v9fs_reopen_fid(pdu, fidp);
             if (err < 0) {
                 return -1;
             }
@@ -590,12 +593,12 @@ static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp)
     }
 }
 
-static int fid_to_qid(V9fsState *s, V9fsFidState *fidp, V9fsQID *qidp)
+static int fid_to_qid(V9fsPDU *pdu, V9fsFidState *fidp, V9fsQID *qidp)
 {
     struct stat stbuf;
     int err;
 
-    err = v9fs_co_lstat(s, &fidp->path, &stbuf);
+    err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
     if (err < 0) {
         return err;
     }
@@ -608,8 +611,9 @@ static V9fsPDU *alloc_pdu(V9fsState *s)
     V9fsPDU *pdu = NULL;
 
     if (!QLIST_EMPTY(&s->free_list)) {
-	pdu = QLIST_FIRST(&s->free_list);
-	QLIST_REMOVE(pdu, next);
+        pdu = QLIST_FIRST(&s->free_list);
+        QLIST_REMOVE(pdu, next);
+        QLIST_INSERT_HEAD(&s->active_list, pdu, next);
     }
     return pdu;
 }
@@ -620,7 +624,14 @@ static void free_pdu(V9fsState *s, V9fsPDU *pdu)
         if (debug_9p_pdu) {
             pprint_pdu(pdu);
         }
-        QLIST_INSERT_HEAD(&s->free_list, pdu, next);
+        /*
+         * Cancelled pdu are added back to the freelist
+         * by flush request .
+         */
+        if (!pdu->cancelled) {
+            QLIST_REMOVE(pdu, next);
+            QLIST_INSERT_HEAD(&s->free_list, pdu, next);
+        }
     }
 }
 
@@ -913,6 +924,9 @@ static void complete_pdu(V9fsState *s, V9fsPDU *pdu, ssize_t len)
     /* FIXME: we should batch these completions */
     virtio_notify(&s->vdev, s->vq);
 
+    /* Now wakeup anybody waiting in flush for this request */
+    qemu_co_queue_next(&pdu->complete);
+
     free_pdu(s, pdu);
 }
 
@@ -1032,7 +1046,7 @@ static uint32_t stat_to_v9mode(const struct stat *stbuf)
     return mode;
 }
 
-static int stat_to_v9stat(V9fsState *s, V9fsPath *name,
+static int stat_to_v9stat(V9fsPDU *pdu, V9fsPath *name,
                             const struct stat *stbuf,
                             V9fsStat *v9stat)
 {
@@ -1058,7 +1072,7 @@ static int stat_to_v9stat(V9fsState *s, V9fsPath *name,
     v9fs_string_null(&v9stat->extension);
 
     if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
-        err = v9fs_co_readlink(s, name, &v9stat->extension);
+        err = v9fs_co_readlink(pdu, name, &v9stat->extension);
         if (err < 0) {
             return err;
         }
@@ -1239,13 +1253,13 @@ static void v9fs_attach(void *opaque)
         goto out_nofid;
     }
     fidp->uid = n_uname;
-    err = v9fs_co_name_to_path(s, NULL, "/", &fidp->path);
+    err = v9fs_co_name_to_path(pdu, NULL, "/", &fidp->path);
     if (err < 0) {
         err = -EINVAL;
         clunk_fid(s, fid);
         goto out;
     }
-    err = fid_to_qid(s, fidp, &qid);
+    err = fid_to_qid(pdu, fidp, &qid);
     if (err < 0) {
         err = -EINVAL;
         clunk_fid(s, fid);
@@ -1254,7 +1268,7 @@ static void v9fs_attach(void *opaque)
     offset += pdu_marshal(pdu, offset, "Q", &qid);
     err = offset;
 out:
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(s, pdu, err);
     v9fs_string_free(&uname);
@@ -1274,16 +1288,16 @@ static void v9fs_stat(void *opaque)
 
     pdu_unmarshal(pdu, offset, "d", &fid);
 
-    fidp = get_fid(s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -ENOENT;
         goto out_nofid;
     }
-    err = v9fs_co_lstat(s, &fidp->path, &stbuf);
+    err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
     if (err < 0) {
         goto out;
     }
-    err = stat_to_v9stat(s, &fidp->path, &stbuf, &v9stat);
+    err = stat_to_v9stat(pdu, &fidp->path, &stbuf, &v9stat);
     if (err < 0) {
         goto out;
     }
@@ -1291,7 +1305,7 @@ static void v9fs_stat(void *opaque)
     err = offset;
     v9fs_stat_free(&v9stat);
 out:
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(s, pdu, err);
 }
@@ -1310,7 +1324,7 @@ static void v9fs_getattr(void *opaque)
 
     pdu_unmarshal(pdu, offset, "dq", &fid, &request_mask);
 
-    fidp = get_fid(s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         retval = -ENOENT;
         goto out_nofid;
@@ -1319,7 +1333,7 @@ static void v9fs_getattr(void *opaque)
      * Currently we only support BASIC fields in stat, so there is no
      * need to look at request_mask.
      */
-    retval = v9fs_co_lstat(s, &fidp->path, &stbuf);
+    retval = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
     if (retval < 0) {
         goto out;
     }
@@ -1327,7 +1341,7 @@ static void v9fs_getattr(void *opaque)
     retval = offset;
     retval += pdu_marshal(pdu, offset, "A", &v9stat_dotl);
 out:
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(s, pdu, retval);
 }
@@ -1356,13 +1370,13 @@ static void v9fs_setattr(void *opaque)
 
     pdu_unmarshal(pdu, offset, "dI", &fid, &v9iattr);
 
-    fidp = get_fid(s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -EINVAL;
         goto out_nofid;
     }
     if (v9iattr.valid & ATTR_MODE) {
-        err = v9fs_co_chmod(s, &fidp->path, v9iattr.mode);
+        err = v9fs_co_chmod(pdu, &fidp->path, v9iattr.mode);
         if (err < 0) {
             goto out;
         }
@@ -1389,7 +1403,7 @@ static void v9fs_setattr(void *opaque)
         } else {
             times[1].tv_nsec = UTIME_OMIT;
         }
-        err = v9fs_co_utimensat(s, &fidp->path, times);
+        err = v9fs_co_utimensat(pdu, &fidp->path, times);
         if (err < 0) {
             goto out;
         }
@@ -1407,21 +1421,21 @@ static void v9fs_setattr(void *opaque)
         if (!(v9iattr.valid & ATTR_GID)) {
             v9iattr.gid = -1;
         }
-        err = v9fs_co_chown(s, &fidp->path, v9iattr.uid,
+        err = v9fs_co_chown(pdu, &fidp->path, v9iattr.uid,
                             v9iattr.gid);
         if (err < 0) {
             goto out;
         }
     }
     if (v9iattr.valid & (ATTR_SIZE)) {
-        err = v9fs_co_truncate(s, &fidp->path, v9iattr.size);
+        err = v9fs_co_truncate(pdu, &fidp->path, v9iattr.size);
         if (err < 0) {
             goto out;
         }
     }
     err = offset;
 out:
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(s, pdu, err);
 }
@@ -1466,7 +1480,7 @@ static void v9fs_walk(void *opaque)
         err = -EINVAL;
         goto out_nofid;
     }
-    fidp = get_fid(s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -ENOENT;
         goto out_nofid;
@@ -1480,11 +1494,11 @@ static void v9fs_walk(void *opaque)
     v9fs_path_copy(&dpath, &fidp->path);
     v9fs_path_copy(&path, &fidp->path);
     for (name_idx = 0; name_idx < nwnames; name_idx++) {
-        err = v9fs_co_name_to_path(s, &dpath, wnames[name_idx].data, &path);
+        err = v9fs_co_name_to_path(pdu, &dpath, wnames[name_idx].data, &path);
         if (err < 0) {
             goto out;
         }
-        err = v9fs_co_lstat(s, &path, &stbuf);
+        err = v9fs_co_lstat(pdu, &path, &stbuf);
         if (err < 0) {
             goto out;
         }
@@ -1505,9 +1519,9 @@ static void v9fs_walk(void *opaque)
     }
     err = v9fs_walk_marshal(pdu, nwnames, qids);
 out:
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
     if (newfidp) {
-        put_fid(s, newfidp);
+        put_fid(pdu, newfidp);
     }
     v9fs_path_free(&dpath);
     v9fs_path_free(&path);
@@ -1523,16 +1537,17 @@ out_nofid:
     return;
 }
 
-static int32_t get_iounit(V9fsState *s, V9fsPath *path)
+static int32_t get_iounit(V9fsPDU *pdu, V9fsPath *path)
 {
     struct statfs stbuf;
     int32_t iounit = 0;
+    V9fsState *s = pdu->s;
 
     /*
      * iounit should be multiples of f_bsize (host filesystem block size
      * and as well as less than (client msize - P9_IOHDRSZ))
      */
-    if (!v9fs_co_statfs(s, path, &stbuf)) {
+    if (!v9fs_co_statfs(pdu, path, &stbuf)) {
         iounit = stbuf.f_bsize;
         iounit *= (s->msize - P9_IOHDRSZ)/stbuf.f_bsize;
     }
@@ -1561,20 +1576,20 @@ static void v9fs_open(void *opaque)
     } else {
         pdu_unmarshal(pdu, offset, "db", &fid, &mode);
     }
-    fidp = get_fid(s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -ENOENT;
         goto out_nofid;
     }
     BUG_ON(fidp->fid_type != P9_FID_NONE);
 
-    err = v9fs_co_lstat(s, &fidp->path, &stbuf);
+    err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
     if (err < 0) {
         goto out;
     }
     stat_to_qid(&stbuf, &qid);
     if (S_ISDIR(stbuf.st_mode)) {
-        err = v9fs_co_opendir(s, fidp);
+        err = v9fs_co_opendir(pdu, fidp);
         if (err < 0) {
             goto out;
         }
@@ -1590,7 +1605,7 @@ static void v9fs_open(void *opaque)
         } else {
             flags = omode_to_uflags(mode);
         }
-        err = v9fs_co_open(s, fidp, flags);
+        err = v9fs_co_open(pdu, fidp, flags);
         if (err < 0) {
             goto out;
         }
@@ -1603,12 +1618,12 @@ static void v9fs_open(void *opaque)
              */
             fidp->flags |= FID_NON_RECLAIMABLE;
         }
-        iounit = get_iounit(s, &fidp->path);
+        iounit = get_iounit(pdu, &fidp->path);
         offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
         err = offset;
     }
 out:
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(s, pdu, err);
 }
@@ -1629,7 +1644,7 @@ static void v9fs_lcreate(void *opaque)
     pdu_unmarshal(pdu, offset, "dsddd", &dfid, &name, &flags,
                   &mode, &gid);
 
-    fidp = get_fid(pdu->s, dfid);
+    fidp = get_fid(pdu, dfid);
     if (fidp == NULL) {
         err = -ENOENT;
         goto out_nofid;
@@ -1637,8 +1652,7 @@ static void v9fs_lcreate(void *opaque)
 
     /* Ignore direct disk access hint until the server supports it. */
     flags &= ~O_DIRECT;
-
-    err = v9fs_co_open2(pdu->s, fidp, &name, gid,
+    err = v9fs_co_open2(pdu, fidp, &name, gid,
                         flags | O_CREAT, mode, &stbuf);
     if (err < 0) {
         goto out;
@@ -1652,12 +1666,12 @@ static void v9fs_lcreate(void *opaque)
          */
         fidp->flags |= FID_NON_RECLAIMABLE;
     }
-    iounit =  get_iounit(pdu->s, &fidp->path);
+    iounit =  get_iounit(pdu, &fidp->path);
     stat_to_qid(&stbuf, &qid);
     offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
     err = offset;
 out:
-    put_fid(pdu->s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(pdu->s, pdu, err);
     v9fs_string_free(&name);
@@ -1674,16 +1688,16 @@ static void v9fs_fsync(void *opaque)
     V9fsState *s = pdu->s;
 
     pdu_unmarshal(pdu, offset, "dd", &fid, &datasync);
-    fidp = get_fid(s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -ENOENT;
         goto out_nofid;
     }
-    err = v9fs_co_fsync(s, fidp, datasync);
+    err = v9fs_co_fsync(pdu, fidp, datasync);
     if (!err) {
         err = offset;
     }
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(s, pdu, err);
 }
@@ -1711,7 +1725,7 @@ static void v9fs_clunk(void *opaque)
     fidp->ref++;
     err = offset;
 
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(s, pdu, err);
 }
@@ -1740,7 +1754,7 @@ static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu,
     return offset;
 }
 
-static int v9fs_do_readdir_with_stat(V9fsState *s, V9fsPDU *pdu,
+static int v9fs_do_readdir_with_stat(V9fsPDU *pdu,
                                      V9fsFidState *fidp, int32_t max_count)
 {
     V9fsPath path;
@@ -1752,7 +1766,7 @@ static int v9fs_do_readdir_with_stat(V9fsState *s, V9fsPDU *pdu,
     struct dirent *dent, *result;
 
     /* save the directory position */
-    saved_dir_pos = v9fs_co_telldir(s, fidp);
+    saved_dir_pos = v9fs_co_telldir(pdu, fidp);
     if (saved_dir_pos < 0) {
         return saved_dir_pos;
     }
@@ -1761,19 +1775,19 @@ static int v9fs_do_readdir_with_stat(V9fsState *s, V9fsPDU *pdu,
 
     while (1) {
         v9fs_path_init(&path);
-        err = v9fs_co_readdir_r(s, fidp, dent, &result);
+        err = v9fs_co_readdir_r(pdu, fidp, dent, &result);
         if (err || !result) {
             break;
         }
-        err = v9fs_co_name_to_path(s, &fidp->path, dent->d_name, &path);
+        err = v9fs_co_name_to_path(pdu, &fidp->path, dent->d_name, &path);
         if (err < 0) {
             goto out;
         }
-        err = v9fs_co_lstat(s, &path, &stbuf);
+        err = v9fs_co_lstat(pdu, &path, &stbuf);
         if (err < 0) {
             goto out;
         }
-        err = stat_to_v9stat(s, &path, &stbuf, &v9stat);
+        err = stat_to_v9stat(pdu, &path, &stbuf, &v9stat);
         if (err < 0) {
             goto out;
         }
@@ -1781,7 +1795,7 @@ static int v9fs_do_readdir_with_stat(V9fsState *s, V9fsPDU *pdu,
         len = pdu_marshal(pdu, 11 + count, "S", &v9stat);
         if ((len != (v9stat.size + 2)) || ((count + len) > max_count)) {
             /* Ran out of buffer. Set dir back to old position and return */
-            v9fs_co_seekdir(s, fidp, saved_dir_pos);
+            v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
             v9fs_stat_free(&v9stat);
             v9fs_path_free(&path);
             g_free(dent);
@@ -1815,7 +1829,7 @@ static void v9fs_read(void *opaque)
 
     pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &max_count);
 
-    fidp = get_fid(s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -EINVAL;
         goto out_nofid;
@@ -1823,9 +1837,9 @@ static void v9fs_read(void *opaque)
     if (fidp->fid_type == P9_FID_DIR) {
 
         if (off == 0) {
-            v9fs_co_rewinddir(s, fidp);
+            v9fs_co_rewinddir(pdu, fidp);
         }
-        count = v9fs_do_readdir_with_stat(s, pdu, fidp, max_count);
+        count = v9fs_do_readdir_with_stat(pdu, fidp, max_count);
         if (count < 0) {
             err = count;
             goto out;
@@ -1848,12 +1862,12 @@ static void v9fs_read(void *opaque)
             }
             /* Loop in case of EINTR */
             do {
-                len = v9fs_co_preadv(s, fidp, sg, cnt, off);
+                len = v9fs_co_preadv(pdu, fidp, sg, cnt, off);
                 if (len >= 0) {
                     off   += len;
                     count += len;
                 }
-            } while (len == -EINTR);
+            } while (len == -EINTR && !pdu->cancelled);
             if (len < 0) {
                 /* IO error return the error */
                 err = len;
@@ -1870,7 +1884,7 @@ static void v9fs_read(void *opaque)
         err = -EINVAL;
     }
 out:
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(s, pdu, err);
 }
@@ -1884,7 +1898,7 @@ static size_t v9fs_readdir_data_size(V9fsString *name)
     return 24 + v9fs_string_size(name);
 }
 
-static int v9fs_do_readdir(V9fsState *s, V9fsPDU *pdu,
+static int v9fs_do_readdir(V9fsPDU *pdu,
                            V9fsFidState *fidp, int32_t max_count)
 {
     size_t size;
@@ -1896,7 +1910,7 @@ static int v9fs_do_readdir(V9fsState *s, V9fsPDU *pdu,
     struct dirent *dent, *result;
 
     /* save the directory position */
-    saved_dir_pos = v9fs_co_telldir(s, fidp);
+    saved_dir_pos = v9fs_co_telldir(pdu, fidp);
     if (saved_dir_pos < 0) {
         return saved_dir_pos;
     }
@@ -1904,7 +1918,7 @@ static int v9fs_do_readdir(V9fsState *s, V9fsPDU *pdu,
     dent = g_malloc(sizeof(struct dirent));
 
     while (1) {
-        err = v9fs_co_readdir_r(s, fidp, dent, &result);
+        err = v9fs_co_readdir_r(pdu, fidp, dent, &result);
         if (err || !result) {
             break;
         }
@@ -1912,7 +1926,7 @@ static int v9fs_do_readdir(V9fsState *s, V9fsPDU *pdu,
         v9fs_string_sprintf(&name, "%s", dent->d_name);
         if ((count + v9fs_readdir_data_size(&name)) > max_count) {
             /* Ran out of buffer. Set dir back to old position and return */
-            v9fs_co_seekdir(s, fidp, saved_dir_pos);
+            v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
             v9fs_string_free(&name);
             g_free(dent);
             return count;
@@ -1956,7 +1970,7 @@ static void v9fs_readdir(void *opaque)
 
     pdu_unmarshal(pdu, offset, "dqd", &fid, &initial_offset, &max_count);
 
-    fidp = get_fid(s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         retval = -EINVAL;
         goto out_nofid;
@@ -1966,11 +1980,11 @@ static void v9fs_readdir(void *opaque)
         goto out;
     }
     if (initial_offset == 0) {
-        v9fs_co_rewinddir(s, fidp);
+        v9fs_co_rewinddir(pdu, fidp);
     } else {
-        v9fs_co_seekdir(s, fidp, initial_offset);
+        v9fs_co_seekdir(pdu, fidp, initial_offset);
     }
-    count = v9fs_do_readdir(s, pdu, fidp, max_count);
+    count = v9fs_do_readdir(pdu, fidp, max_count);
     if (count < 0) {
         retval = count;
         goto out;
@@ -1979,7 +1993,7 @@ static void v9fs_readdir(void *opaque)
     retval += pdu_marshal(pdu, offset, "d", count);
     retval += count;
 out:
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(s, pdu, retval);
 }
@@ -2046,7 +2060,7 @@ static void v9fs_write(void *opaque)
 
     pdu_unmarshal(pdu, offset, "dqdv", &fid, &off, &count, sg, &cnt);
 
-    fidp = get_fid(s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -EINVAL;
         goto out_nofid;
@@ -2073,12 +2087,12 @@ static void v9fs_write(void *opaque)
         }
         /* Loop in case of EINTR */
         do {
-            len = v9fs_co_pwritev(s, fidp, sg, cnt, off);
+            len = v9fs_co_pwritev(pdu, fidp, sg, cnt, off);
             if (len >= 0) {
                 off   += len;
                 total += len;
             }
-        } while (len == -EINTR);
+        } while (len == -EINTR && !pdu->cancelled);
         if (len < 0) {
             /* IO error return the error */
             err = len;
@@ -2089,7 +2103,7 @@ static void v9fs_write(void *opaque)
     offset += pdu_marshal(pdu, offset, "d", total);
     err = offset;
 out:
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(s, pdu, err);
 }
@@ -2115,57 +2129,57 @@ static void v9fs_create(void *opaque)
     pdu_unmarshal(pdu, offset, "dsdbs", &fid, &name,
                   &perm, &mode, &extension);
 
-    fidp = get_fid(pdu->s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -EINVAL;
         goto out_nofid;
     }
     if (perm & P9_STAT_MODE_DIR) {
-        err = v9fs_co_mkdir(pdu->s, fidp, &name, perm & 0777,
+        err = v9fs_co_mkdir(pdu, fidp, &name, perm & 0777,
                             fidp->uid, -1, &stbuf);
         if (err < 0) {
             goto out;
         }
-        err = v9fs_co_name_to_path(pdu->s, &fidp->path, name.data, &path);
+        err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
         if (err < 0) {
             goto out;
         }
         v9fs_path_copy(&fidp->path, &path);
-        err = v9fs_co_opendir(pdu->s, fidp);
+        err = v9fs_co_opendir(pdu, fidp);
         if (err < 0) {
             goto out;
         }
         fidp->fid_type = P9_FID_DIR;
     } else if (perm & P9_STAT_MODE_SYMLINK) {
-        err = v9fs_co_symlink(pdu->s, fidp, &name,
+        err = v9fs_co_symlink(pdu, fidp, &name,
                               extension.data, -1 , &stbuf);
         if (err < 0) {
             goto out;
         }
-        err = v9fs_co_name_to_path(pdu->s, &fidp->path, name.data, &path);
+        err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
         if (err < 0) {
             goto out;
         }
         v9fs_path_copy(&fidp->path, &path);
     } else if (perm & P9_STAT_MODE_LINK) {
         int32_t ofid = atoi(extension.data);
-        V9fsFidState *ofidp = get_fid(pdu->s, ofid);
+        V9fsFidState *ofidp = get_fid(pdu, ofid);
         if (ofidp == NULL) {
             err = -EINVAL;
             goto out;
         }
-        err = v9fs_co_link(pdu->s, ofidp, fidp, &name);
-        put_fid(pdu->s, ofidp);
+        err = v9fs_co_link(pdu, ofidp, fidp, &name);
+        put_fid(pdu, ofidp);
         if (err < 0) {
             goto out;
         }
-        err = v9fs_co_name_to_path(pdu->s, &fidp->path, name.data, &path);
+        err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
         if (err < 0) {
             fidp->fid_type = P9_FID_NONE;
             goto out;
         }
         v9fs_path_copy(&fidp->path, &path);
-        err = v9fs_co_lstat(pdu->s, &fidp->path, &stbuf);
+        err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
         if (err < 0) {
             fidp->fid_type = P9_FID_NONE;
             goto out;
@@ -2193,40 +2207,40 @@ static void v9fs_create(void *opaque)
         }
 
         nmode |= perm & 0777;
-        err = v9fs_co_mknod(pdu->s, fidp, &name, fidp->uid, -1,
+        err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
                             makedev(major, minor), nmode, &stbuf);
         if (err < 0) {
             goto out;
         }
-        err = v9fs_co_name_to_path(pdu->s, &fidp->path, name.data, &path);
+        err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
         if (err < 0) {
             goto out;
         }
         v9fs_path_copy(&fidp->path, &path);
     } else if (perm & P9_STAT_MODE_NAMED_PIPE) {
-        err = v9fs_co_mknod(pdu->s, fidp, &name, fidp->uid, -1,
+        err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
                             0, S_IFIFO | (perm & 0777), &stbuf);
         if (err < 0) {
             goto out;
         }
-        err = v9fs_co_name_to_path(pdu->s, &fidp->path, name.data, &path);
+        err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
         if (err < 0) {
             goto out;
         }
         v9fs_path_copy(&fidp->path, &path);
     } else if (perm & P9_STAT_MODE_SOCKET) {
-        err = v9fs_co_mknod(pdu->s, fidp, &name, fidp->uid, -1,
+        err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
                             0, S_IFSOCK | (perm & 0777), &stbuf);
         if (err < 0) {
             goto out;
         }
-        err = v9fs_co_name_to_path(pdu->s, &fidp->path, name.data, &path);
+        err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
         if (err < 0) {
             goto out;
         }
         v9fs_path_copy(&fidp->path, &path);
     } else {
-        err = v9fs_co_open2(pdu->s, fidp, &name, -1,
+        err = v9fs_co_open2(pdu, fidp, &name, -1,
                             omode_to_uflags(mode)|O_CREAT, perm, &stbuf);
         if (err < 0) {
             goto out;
@@ -2241,12 +2255,12 @@ static void v9fs_create(void *opaque)
             fidp->flags |= FID_NON_RECLAIMABLE;
         }
     }
-    iounit = get_iounit(pdu->s, &fidp->path);
+    iounit = get_iounit(pdu, &fidp->path);
     stat_to_qid(&stbuf, &qid);
     offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
     err = offset;
 out:
-    put_fid(pdu->s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
    complete_pdu(pdu->s, pdu, err);
    v9fs_string_free(&name);
@@ -2269,12 +2283,12 @@ static void v9fs_symlink(void *opaque)
 
     pdu_unmarshal(pdu, offset, "dssd", &dfid, &name, &symname, &gid);
 
-    dfidp = get_fid(pdu->s, dfid);
+    dfidp = get_fid(pdu, dfid);
     if (dfidp == NULL) {
         err = -EINVAL;
         goto out_nofid;
     }
-    err = v9fs_co_symlink(pdu->s, dfidp, &name, symname.data, gid, &stbuf);
+    err = v9fs_co_symlink(pdu, dfidp, &name, symname.data, gid, &stbuf);
     if (err < 0) {
         goto out;
     }
@@ -2282,7 +2296,7 @@ static void v9fs_symlink(void *opaque)
     offset += pdu_marshal(pdu, offset, "Q", &qid);
     err = offset;
 out:
-    put_fid(pdu->s, dfidp);
+    put_fid(pdu, dfidp);
 out_nofid:
     complete_pdu(pdu->s, pdu, err);
     v9fs_string_free(&name);
@@ -2291,9 +2305,28 @@ out_nofid:
 
 static void v9fs_flush(void *opaque)
 {
+    int16_t tag;
+    size_t offset = 7;
+    V9fsPDU *cancel_pdu;
     V9fsPDU *pdu = opaque;
     V9fsState *s = pdu->s;
-    /* A nop call with no return */
+
+    pdu_unmarshal(pdu, offset, "w", &tag);
+
+    QLIST_FOREACH(cancel_pdu, &s->active_list, next) {
+        if (cancel_pdu->tag == tag) {
+            break;
+        }
+    }
+    if (cancel_pdu) {
+        cancel_pdu->cancelled = 1;
+        /*
+         * Wait for pdu to complete.
+         */
+        qemu_co_queue_wait(&cancel_pdu->complete);
+        cancel_pdu->cancelled = 0;
+        free_pdu(pdu->s, cancel_pdu);
+    }
     complete_pdu(s, pdu, 7);
     return;
 }
@@ -2310,23 +2343,23 @@ static void v9fs_link(void *opaque)
 
     pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
 
-    dfidp = get_fid(s, dfid);
+    dfidp = get_fid(pdu, dfid);
     if (dfidp == NULL) {
         err = -ENOENT;
         goto out_nofid;
     }
 
-    oldfidp = get_fid(s, oldfid);
+    oldfidp = get_fid(pdu, oldfid);
     if (oldfidp == NULL) {
         err = -ENOENT;
         goto out;
     }
-    err = v9fs_co_link(s, oldfidp, dfidp, &name);
+    err = v9fs_co_link(pdu, oldfidp, dfidp, &name);
     if (!err) {
         err = offset;
     }
 out:
-    put_fid(s, dfidp);
+    put_fid(pdu, dfidp);
 out_nofid:
     v9fs_string_free(&name);
     complete_pdu(s, pdu, err);
@@ -2343,7 +2376,7 @@ static void v9fs_remove(void *opaque)
 
     pdu_unmarshal(pdu, offset, "d", &fid);
 
-    fidp = get_fid(pdu->s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -EINVAL;
         goto out_nofid;
@@ -2357,18 +2390,18 @@ static void v9fs_remove(void *opaque)
      * IF the file is unlinked, we cannot reopen
      * the file later. So don't reclaim fd
      */
-    err = v9fs_mark_fids_unreclaim(pdu->s, &fidp->path);
+    err = v9fs_mark_fids_unreclaim(pdu, &fidp->path);
     if (err < 0) {
         goto out_err;
     }
-    err = v9fs_co_remove(pdu->s, &fidp->path);
+    err = v9fs_co_remove(pdu, &fidp->path);
     if (!err) {
         err = offset;
     }
 out_err:
     /* For TREMOVE we need to clunk the fid even on failed remove */
     clunk_fid(pdu->s, fidp->fid);
-    put_fid(pdu->s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(pdu->s, pdu, err);
 }
@@ -2385,7 +2418,7 @@ static void v9fs_unlinkat(void *opaque)
 
     pdu_unmarshal(pdu, offset, "dsd", &dfid, &name, &flags);
 
-    dfidp = get_fid(pdu->s, dfid);
+    dfidp = get_fid(pdu, dfid);
     if (dfidp == NULL) {
         err = -EINVAL;
         goto out_nofid;
@@ -2395,20 +2428,20 @@ static void v9fs_unlinkat(void *opaque)
      * the file later. So don't reclaim fd
      */
     v9fs_path_init(&path);
-    err = v9fs_co_name_to_path(pdu->s, &dfidp->path, name.data, &path);
+    err = v9fs_co_name_to_path(pdu, &dfidp->path, name.data, &path);
     if (err < 0) {
         goto out_err;
     }
-    err = v9fs_mark_fids_unreclaim(pdu->s, &path);
+    err = v9fs_mark_fids_unreclaim(pdu, &path);
     if (err < 0) {
         goto out_err;
     }
-    err = v9fs_co_unlinkat(pdu->s, &dfidp->path, &name, flags);
+    err = v9fs_co_unlinkat(pdu, &dfidp->path, &name, flags);
     if (!err) {
         err = offset;
     }
 out_err:
-    put_fid(pdu->s, dfidp);
+    put_fid(pdu, dfidp);
     v9fs_path_free(&path);
 out_nofid:
     complete_pdu(pdu->s, pdu, err);
@@ -2417,25 +2450,26 @@ out_nofid:
 
 
 /* Only works with path name based fid */
-static int v9fs_complete_rename(V9fsState *s, V9fsFidState *fidp,
+static int v9fs_complete_rename(V9fsPDU *pdu, V9fsFidState *fidp,
                                 int32_t newdirfid, V9fsString *name)
 {
     char *end;
     int err = 0;
     V9fsPath new_path;
     V9fsFidState *tfidp;
+    V9fsState *s = pdu->s;
     V9fsFidState *dirfidp = NULL;
     char *old_name, *new_name;
 
     v9fs_path_init(&new_path);
     if (newdirfid != -1) {
-        dirfidp = get_fid(s, newdirfid);
+        dirfidp = get_fid(pdu, newdirfid);
         if (dirfidp == NULL) {
             err = -ENOENT;
             goto out_nofid;
         }
         BUG_ON(dirfidp->fid_type != P9_FID_NONE);
-        v9fs_co_name_to_path(s, &dirfidp->path, name->data, &new_path);
+        v9fs_co_name_to_path(pdu, &dirfidp->path, name->data, &new_path);
     } else {
         old_name = fidp->path.data;
         end = strrchr(old_name, '/');
@@ -2447,10 +2481,10 @@ static int v9fs_complete_rename(V9fsState *s, V9fsFidState *fidp,
         new_name = g_malloc0(end - old_name + name->size + 1);
         strncat(new_name, old_name, end - old_name);
         strncat(new_name + (end - old_name), name->data, name->size);
-        v9fs_co_name_to_path(s, NULL, new_name, &new_path);
+        v9fs_co_name_to_path(pdu, NULL, new_name, &new_path);
         g_free(new_name);
     }
-    err = v9fs_co_rename(s, &fidp->path, &new_path);
+    err = v9fs_co_rename(pdu, &fidp->path, &new_path);
     if (err < 0) {
         goto out;
     }
@@ -2466,7 +2500,7 @@ static int v9fs_complete_rename(V9fsState *s, V9fsFidState *fidp,
     }
 out:
     if (dirfidp) {
-        put_fid(s, dirfidp);
+        put_fid(pdu, dirfidp);
     }
     v9fs_path_free(&new_path);
 out_nofid:
@@ -2487,7 +2521,7 @@ static void v9fs_rename(void *opaque)
 
     pdu_unmarshal(pdu, offset, "dds", &fid, &newdirfid, &name);
 
-    fidp = get_fid(s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -ENOENT;
         goto out_nofid;
@@ -2499,30 +2533,31 @@ static void v9fs_rename(void *opaque)
         goto out;
     }
     v9fs_path_write_lock(s);
-    err = v9fs_complete_rename(s, fidp, newdirfid, &name);
+    err = v9fs_complete_rename(pdu, fidp, newdirfid, &name);
     v9fs_path_unlock(s);
     if (!err) {
         err = offset;
     }
 out:
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(s, pdu, err);
     v9fs_string_free(&name);
 }
 
-static void v9fs_fix_fid_paths(V9fsState *s, V9fsPath *olddir,
+static void v9fs_fix_fid_paths(V9fsPDU *pdu, V9fsPath *olddir,
                                V9fsString *old_name, V9fsPath *newdir,
                                V9fsString *new_name)
 {
     V9fsFidState *tfidp;
     V9fsPath oldpath, newpath;
+    V9fsState *s = pdu->s;
 
 
     v9fs_path_init(&oldpath);
     v9fs_path_init(&newpath);
-    v9fs_co_name_to_path(s, olddir, old_name->data, &oldpath);
-    v9fs_co_name_to_path(s, newdir, new_name->data, &newpath);
+    v9fs_co_name_to_path(pdu, olddir, old_name->data, &oldpath);
+    v9fs_co_name_to_path(pdu, newdir, new_name->data, &newpath);
 
     /*
      * Fixup fid's pointing to the old name to
@@ -2538,44 +2573,45 @@ static void v9fs_fix_fid_paths(V9fsState *s, V9fsPath *olddir,
     v9fs_path_free(&newpath);
 }
 
-static int v9fs_complete_renameat(V9fsState *s, int32_t olddirfid,
+static int v9fs_complete_renameat(V9fsPDU *pdu, int32_t olddirfid,
                                   V9fsString *old_name, int32_t newdirfid,
                                   V9fsString *new_name)
 {
     int err = 0;
+    V9fsState *s = pdu->s;
     V9fsFidState *newdirfidp = NULL, *olddirfidp = NULL;
 
-    olddirfidp = get_fid(s, olddirfid);
+    olddirfidp = get_fid(pdu, olddirfid);
     if (olddirfidp == NULL) {
         err = -ENOENT;
         goto out;
     }
     if (newdirfid != -1) {
-        newdirfidp = get_fid(s, newdirfid);
+        newdirfidp = get_fid(pdu, newdirfid);
         if (newdirfidp == NULL) {
             err = -ENOENT;
             goto out;
         }
     } else {
-        newdirfidp = get_fid(s, olddirfid);
+        newdirfidp = get_fid(pdu, olddirfid);
     }
 
-    err = v9fs_co_renameat(s, &olddirfidp->path, old_name,
+    err = v9fs_co_renameat(pdu, &olddirfidp->path, old_name,
                            &newdirfidp->path, new_name);
     if (err < 0) {
         goto out;
     }
     if (s->ctx.flags & PATHNAME_FSCONTEXT) {
         /* Only for path based fid  we need to do the below fixup */
-        v9fs_fix_fid_paths(s, &olddirfidp->path, old_name,
+        v9fs_fix_fid_paths(pdu, &olddirfidp->path, old_name,
                            &newdirfidp->path, new_name);
     }
 out:
     if (olddirfidp) {
-        put_fid(s, olddirfidp);
+        put_fid(pdu, olddirfidp);
     }
     if (newdirfidp) {
-        put_fid(s, newdirfidp);
+        put_fid(pdu, newdirfidp);
     }
     return err;
 }
@@ -2593,7 +2629,8 @@ static void v9fs_renameat(void *opaque)
                   &old_name, &newdirfid, &new_name);
 
     v9fs_path_write_lock(s);
-    err = v9fs_complete_renameat(s, olddirfid, &old_name, newdirfid, &new_name);
+    err = v9fs_complete_renameat(pdu, olddirfid,
+                                 &old_name, newdirfid, &new_name);
     v9fs_path_unlock(s);
     if (!err) {
         err = offset;
@@ -2617,19 +2654,19 @@ static void v9fs_wstat(void *opaque)
 
     pdu_unmarshal(pdu, offset, "dwS", &fid, &unused, &v9stat);
 
-    fidp = get_fid(s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -EINVAL;
         goto out_nofid;
     }
     /* do we need to sync the file? */
     if (donttouch_stat(&v9stat)) {
-        err = v9fs_co_fsync(s, fidp, 0);
+        err = v9fs_co_fsync(pdu, fidp, 0);
         goto out;
     }
     if (v9stat.mode != -1) {
         uint32_t v9_mode;
-        err = v9fs_co_lstat(s, &fidp->path, &stbuf);
+        err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
         if (err < 0) {
             goto out;
         }
@@ -2640,7 +2677,7 @@ static void v9fs_wstat(void *opaque)
             err = -EIO;
             goto out;
         }
-        err = v9fs_co_chmod(s, &fidp->path,
+        err = v9fs_co_chmod(pdu, &fidp->path,
                             v9mode_to_mode(v9stat.mode,
                                            &v9stat.extension));
         if (err < 0) {
@@ -2661,32 +2698,32 @@ static void v9fs_wstat(void *opaque)
         } else {
             times[1].tv_nsec = UTIME_OMIT;
         }
-        err = v9fs_co_utimensat(s, &fidp->path, times);
+        err = v9fs_co_utimensat(pdu, &fidp->path, times);
         if (err < 0) {
             goto out;
         }
     }
     if (v9stat.n_gid != -1 || v9stat.n_uid != -1) {
-        err = v9fs_co_chown(s, &fidp->path, v9stat.n_uid, v9stat.n_gid);
+        err = v9fs_co_chown(pdu, &fidp->path, v9stat.n_uid, v9stat.n_gid);
         if (err < 0) {
             goto out;
         }
     }
     if (v9stat.name.size != 0) {
-        err = v9fs_complete_rename(s, fidp, -1, &v9stat.name);
+        err = v9fs_complete_rename(pdu, fidp, -1, &v9stat.name);
         if (err < 0) {
             goto out;
         }
     }
     if (v9stat.length != -1) {
-        err = v9fs_co_truncate(s, &fidp->path, v9stat.length);
+        err = v9fs_co_truncate(pdu, &fidp->path, v9stat.length);
         if (err < 0) {
             goto out;
         }
     }
     err = offset;
 out:
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     v9fs_stat_free(&v9stat);
     complete_pdu(s, pdu, err);
@@ -2748,19 +2785,19 @@ static void v9fs_statfs(void *opaque)
     V9fsState *s = pdu->s;
 
     pdu_unmarshal(pdu, offset, "d", &fid);
-    fidp = get_fid(s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         retval = -ENOENT;
         goto out_nofid;
     }
-    retval = v9fs_co_statfs(s, &fidp->path, &stbuf);
+    retval = v9fs_co_statfs(pdu, &fidp->path, &stbuf);
     if (retval < 0) {
         goto out;
     }
     retval = offset;
     retval += v9fs_fill_statfs(s, pdu, &stbuf);
 out:
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(s, pdu, retval);
     return;
@@ -2785,12 +2822,12 @@ static void v9fs_mknod(void *opaque)
     pdu_unmarshal(pdu, offset, "dsdddd", &fid, &name, &mode,
                   &major, &minor, &gid);
 
-    fidp = get_fid(s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -ENOENT;
         goto out_nofid;
     }
-    err = v9fs_co_mknod(s, fidp, &name, fidp->uid, gid,
+    err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, gid,
                         makedev(major, minor), mode, &stbuf);
     if (err < 0) {
         goto out;
@@ -2799,7 +2836,7 @@ static void v9fs_mknod(void *opaque)
     err = offset;
     err += pdu_marshal(pdu, offset, "Q", &qid);
 out:
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(s, pdu, err);
     v9fs_string_free(&name);
@@ -2835,18 +2872,18 @@ static void v9fs_lock(void *opaque)
         err = -EINVAL;
         goto out_nofid;
     }
-    fidp = get_fid(s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -ENOENT;
         goto out_nofid;
     }
-    err = v9fs_co_fstat(s, fidp->fs.fd, &stbuf);
+    err = v9fs_co_fstat(pdu, fidp->fs.fd, &stbuf);
     if (err < 0) {
         goto out;
     }
     status = P9_LOCK_SUCCESS;
 out:
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     err = offset;
     err += pdu_marshal(pdu, offset, "b", status);
@@ -2874,12 +2911,12 @@ static void v9fs_getlock(void *opaque)
                   &glock->start, &glock->length, &glock->proc_id,
                   &glock->client_id);
 
-    fidp = get_fid(s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -ENOENT;
         goto out_nofid;
     }
-    err = v9fs_co_fstat(s, fidp->fs.fd, &stbuf);
+    err = v9fs_co_fstat(pdu, fidp->fs.fd, &stbuf);
     if (err < 0) {
         goto out;
     }
@@ -2889,7 +2926,7 @@ static void v9fs_getlock(void *opaque)
                           &glock->client_id);
     err = offset;
 out:
-    put_fid(s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(s, pdu, err);
     v9fs_string_free(&glock->client_id);
@@ -2911,12 +2948,12 @@ static void v9fs_mkdir(void *opaque)
 
     pdu_unmarshal(pdu, offset, "dsdd", &fid, &name, &mode, &gid);
 
-    fidp = get_fid(pdu->s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -ENOENT;
         goto out_nofid;
     }
-    err = v9fs_co_mkdir(pdu->s, fidp, &name, mode, fidp->uid, gid, &stbuf);
+    err = v9fs_co_mkdir(pdu, fidp, &name, mode, fidp->uid, gid, &stbuf);
     if (err < 0) {
         goto out;
     }
@@ -2924,7 +2961,7 @@ static void v9fs_mkdir(void *opaque)
     offset += pdu_marshal(pdu, offset, "Q", &qid);
     err = offset;
 out:
-    put_fid(pdu->s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(pdu->s, pdu, err);
     v9fs_string_free(&name);
@@ -2943,7 +2980,7 @@ static void v9fs_xattrwalk(void *opaque)
     V9fsState *s = pdu->s;
 
     pdu_unmarshal(pdu, offset, "dds", &fid, &newfid, &name);
-    file_fidp = get_fid(s, fid);
+    file_fidp = get_fid(pdu, fid);
     if (file_fidp == NULL) {
         err = -ENOENT;
         goto out_nofid;
@@ -2958,7 +2995,7 @@ static void v9fs_xattrwalk(void *opaque)
         /*
          * listxattr request. Get the size first
          */
-        size = v9fs_co_llistxattr(s, &xattr_fidp->path, NULL, 0);
+        size = v9fs_co_llistxattr(pdu, &xattr_fidp->path, NULL, 0);
         if (size < 0) {
             err = size;
             clunk_fid(s, xattr_fidp->fid);
@@ -2972,7 +3009,7 @@ static void v9fs_xattrwalk(void *opaque)
         xattr_fidp->fs.xattr.copied_len = -1;
         if (size) {
             xattr_fidp->fs.xattr.value = g_malloc(size);
-            err = v9fs_co_llistxattr(s, &xattr_fidp->path,
+            err = v9fs_co_llistxattr(pdu, &xattr_fidp->path,
                                      xattr_fidp->fs.xattr.value,
                                      xattr_fidp->fs.xattr.len);
             if (err < 0) {
@@ -2987,7 +3024,7 @@ static void v9fs_xattrwalk(void *opaque)
          * specific xattr fid. We check for xattr
          * presence also collect the xattr size
          */
-        size = v9fs_co_lgetxattr(s, &xattr_fidp->path,
+        size = v9fs_co_lgetxattr(pdu, &xattr_fidp->path,
                                  &name, NULL, 0);
         if (size < 0) {
             err = size;
@@ -3002,7 +3039,7 @@ static void v9fs_xattrwalk(void *opaque)
         xattr_fidp->fs.xattr.copied_len = -1;
         if (size) {
             xattr_fidp->fs.xattr.value = g_malloc(size);
-            err = v9fs_co_lgetxattr(s, &xattr_fidp->path,
+            err = v9fs_co_lgetxattr(pdu, &xattr_fidp->path,
                                     &name, xattr_fidp->fs.xattr.value,
                                     xattr_fidp->fs.xattr.len);
             if (err < 0) {
@@ -3014,9 +3051,9 @@ static void v9fs_xattrwalk(void *opaque)
         err = offset;
     }
 out:
-    put_fid(s, file_fidp);
+    put_fid(pdu, file_fidp);
     if (xattr_fidp) {
-        put_fid(s, xattr_fidp);
+        put_fid(pdu, xattr_fidp);
     }
 out_nofid:
     complete_pdu(s, pdu, err);
@@ -3039,7 +3076,7 @@ static void v9fs_xattrcreate(void *opaque)
     pdu_unmarshal(pdu, offset, "dsqd",
                   &fid, &name, &size, &flags);
 
-    file_fidp = get_fid(s, fid);
+    file_fidp = get_fid(pdu, fid);
     if (file_fidp == NULL) {
         err = -EINVAL;
         goto out_nofid;
@@ -3058,7 +3095,7 @@ static void v9fs_xattrcreate(void *opaque)
         xattr_fidp->fs.xattr.value = NULL;
     }
     err = offset;
-    put_fid(s, file_fidp);
+    put_fid(pdu, file_fidp);
 out_nofid:
     complete_pdu(s, pdu, err);
     v9fs_string_free(&name);
@@ -3074,14 +3111,14 @@ static void v9fs_readlink(void *opaque)
     V9fsFidState *fidp;
 
     pdu_unmarshal(pdu, offset, "d", &fid);
-    fidp = get_fid(pdu->s, fid);
+    fidp = get_fid(pdu, fid);
     if (fidp == NULL) {
         err = -ENOENT;
         goto out_nofid;
     }
 
     v9fs_string_init(&target);
-    err = v9fs_co_readlink(pdu->s, &fidp->path, &target);
+    err = v9fs_co_readlink(pdu, &fidp->path, &target);
     if (err < 0) {
         goto out;
     }
@@ -3089,7 +3126,7 @@ static void v9fs_readlink(void *opaque)
     err = offset;
     v9fs_string_free(&target);
 out:
-    put_fid(pdu->s, fidp);
+    put_fid(pdu, fidp);
 out_nofid:
     complete_pdu(pdu->s, pdu, err);
 }
@@ -3173,6 +3210,7 @@ void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
         memcpy(&pdu->size, ptr, 4);
         pdu->id = ptr[4];
         memcpy(&pdu->tag, ptr + 5, 2);
+        qemu_co_queue_init(&pdu->complete);
         submit_pdu(s, pdu);
     }
     free_pdu(s, pdu);
diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
index 80147d4..60b8a56 100644
--- a/hw/9pfs/virtio-9p.h
+++ b/hw/9pfs/virtio-9p.h
@@ -131,6 +131,8 @@ struct V9fsPDU
     uint32_t size;
     uint16_t tag;
     uint8_t id;
+    uint8_t cancelled;
+    CoQueue complete;
     VirtQueueElement elem;
     struct V9fsState *s;
     QLIST_ENTRY(V9fsPDU) next;
@@ -231,6 +233,7 @@ typedef struct V9fsState
     VirtQueue *vq;
     V9fsPDU pdus[MAX_REQ];
     QLIST_HEAD(, V9fsPDU) free_list;
+    QLIST_HEAD(, V9fsPDU) active_list;
     V9fsFidState *fid_list;
     FileOperations *ops;
     FsContext ctx;
@@ -409,9 +412,14 @@ static inline void v9fs_path_unlock(V9fsState *s)
     }
 }
 
+static inline uint8_t v9fs_request_cancelled(V9fsPDU *pdu)
+{
+    return pdu->cancelled;
+}
+
 extern void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq);
 extern void virtio_9p_set_fd_limit(void);
-extern void v9fs_reclaim_fd(V9fsState *s);
+extern void v9fs_reclaim_fd(V9fsPDU *pdu);
 extern void v9fs_string_init(V9fsString *str);
 extern void v9fs_string_free(V9fsString *str);
 extern void v9fs_string_null(V9fsString *str);
commit ce421a19612aaf0d25dede4bad3ea205587c9dae
Author: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Date:   Tue Aug 2 11:36:24 2011 +0530

    hw/9pfs: Avoid unnecessary get_fid in v9fs_clunk
    
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>

diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index 2a68953..e51df2a 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -417,7 +417,7 @@ static void put_fid(V9fsState *s, V9fsFidState *fidp)
     }
 }
 
-static int clunk_fid(V9fsState *s, int32_t fid)
+static V9fsFidState *clunk_fid(V9fsState *s, int32_t fid)
 {
     V9fsFidState **fidpp, *fidp;
 
@@ -426,14 +426,13 @@ static int clunk_fid(V9fsState *s, int32_t fid)
             break;
         }
     }
-
     if (*fidpp == NULL) {
-        return -ENOENT;
+        return NULL;
     }
     fidp = *fidpp;
     *fidpp = fidp->next;
     fidp->clunked = 1;
-    return 0;
+    return fidp;
 }
 
 void v9fs_reclaim_fd(V9fsState *s)
@@ -1700,17 +1699,18 @@ static void v9fs_clunk(void *opaque)
 
     pdu_unmarshal(pdu, offset, "d", &fid);
 
-    fidp = get_fid(s, fid);
+    fidp = clunk_fid(s, fid);
     if (fidp == NULL) {
         err = -ENOENT;
         goto out_nofid;
     }
-    err = clunk_fid(s, fidp->fid);
-    if (err < 0) {
-        goto out;
-    }
+    /*
+     * Bump the ref so that put_fid will
+     * free the fid.
+     */
+    fidp->ref++;
     err = offset;
-out:
+
     put_fid(s, fidp);
 out_nofid:
     complete_pdu(s, pdu, err);
commit 532decb715acb2e03bbe373c9bd914a8499896ee
Author: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Date:   Tue Aug 2 11:35:54 2011 +0530

    hw/9pfs: Add fs driver specific details to fscontext
    
    Add a new context flag PATHNAME_FSCONTEXT and indicate whether
    the fs driver track fid using path names. Also add a private
    pointer that help us to track fs driver specific values in there
    
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>

diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h
index 5221d6d..8de8abf 100644
--- a/fsdev/file-op-9p.h
+++ b/fsdev/file-op-9p.h
@@ -50,12 +50,18 @@ typedef struct FsCred
 
 struct xattr_operations;
 
+/* FsContext flag values */
+#define PATHNAME_FSCONTEXT 0x1
+
 typedef struct FsContext
 {
+    int flags;
     char *fs_root;
     SecModel fs_sm;
     uid_t uid;
     struct xattr_operations **xops;
+    /* fs driver specific data */
+    void *private;
 } FsContext;
 
 typedef struct V9fsPath {
diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c
index 2c50df8..b379f93 100644
--- a/hw/9pfs/codir.c
+++ b/hw/9pfs/codir.c
@@ -76,7 +76,7 @@ int v9fs_co_mkdir(V9fsState *s, V9fsFidState *fidp, V9fsString *name,
     cred.fc_mode = mode;
     cred.fc_uid = uid;
     cred.fc_gid = gid;
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             err = s->ops->mkdir(&s->ctx, &fidp->path, name->data,  &cred);
@@ -94,7 +94,7 @@ int v9fs_co_mkdir(V9fsState *s, V9fsFidState *fidp, V9fsString *name,
                 v9fs_path_free(&path);
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     return err;
 }
 
@@ -102,7 +102,7 @@ int v9fs_co_opendir(V9fsState *s, V9fsFidState *fidp)
 {
     int err;
 
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             fidp->fs.dir = s->ops->opendir(&s->ctx, &fidp->path);
@@ -112,7 +112,7 @@ int v9fs_co_opendir(V9fsState *s, V9fsFidState *fidp)
                 err = 0;
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     if (!err) {
         total_open_fd++;
         if (total_open_fd > open_fd_hw) {
diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c
index 69fad36..1a99adc 100644
--- a/hw/9pfs/cofile.c
+++ b/hw/9pfs/cofile.c
@@ -21,7 +21,7 @@ int v9fs_co_lstat(V9fsState *s, V9fsPath *path, struct stat *stbuf)
 {
     int err;
 
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             err = s->ops->lstat(&s->ctx, path, stbuf);
@@ -29,7 +29,7 @@ int v9fs_co_lstat(V9fsState *s, V9fsPath *path, struct stat *stbuf)
                 err = -errno;
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     return err;
 }
 
@@ -51,7 +51,7 @@ int v9fs_co_open(V9fsState *s, V9fsFidState *fidp, int flags)
 {
     int err;
 
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             fidp->fs.fd = s->ops->open(&s->ctx, &fidp->path, flags);
@@ -61,7 +61,7 @@ int v9fs_co_open(V9fsState *s, V9fsFidState *fidp, int flags)
                 err = 0;
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     if (!err) {
         total_open_fd++;
         if (total_open_fd > open_fd_hw) {
@@ -88,7 +88,7 @@ int v9fs_co_open2(V9fsState *s, V9fsFidState *fidp, V9fsString *name, gid_t gid,
      * don't change. Read lock is fine because this fid cannot
      * be used by any other operation.
      */
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             fidp->fs.fd = s->ops->open2(&s->ctx, &fidp->path,
@@ -112,7 +112,7 @@ int v9fs_co_open2(V9fsState *s, V9fsFidState *fidp, V9fsString *name, gid_t gid,
                 v9fs_path_free(&path);
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     if (!err) {
         total_open_fd++;
         if (total_open_fd > open_fd_hw) {
@@ -160,7 +160,7 @@ int v9fs_co_link(V9fsState *s, V9fsFidState *oldfid,
 {
     int err;
 
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             err = s->ops->link(&s->ctx, &oldfid->path,
@@ -169,7 +169,7 @@ int v9fs_co_link(V9fsState *s, V9fsFidState *oldfid,
                 err = -errno;
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     return err;
 }
 
diff --git a/hw/9pfs/cofs.c b/hw/9pfs/cofs.c
index 7f5220e..9c3c9e9 100644
--- a/hw/9pfs/cofs.c
+++ b/hw/9pfs/cofs.c
@@ -23,8 +23,7 @@ int v9fs_co_readlink(V9fsState *s, V9fsPath *path, V9fsString *buf)
     ssize_t len;
 
     buf->data = g_malloc(PATH_MAX);
-    qemu_co_rwlock_rdlock(&s->rename_lock);
-
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             len = s->ops->readlink(&s->ctx, path,
@@ -37,7 +36,7 @@ int v9fs_co_readlink(V9fsState *s, V9fsPath *path, V9fsString *buf)
                 err = -errno;
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     if (err) {
         g_free(buf->data);
         buf->data = NULL;
@@ -50,7 +49,7 @@ int v9fs_co_statfs(V9fsState *s, V9fsPath *path, struct statfs *stbuf)
 {
     int err;
 
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             err = s->ops->statfs(&s->ctx, path, stbuf);
@@ -58,7 +57,7 @@ int v9fs_co_statfs(V9fsState *s, V9fsPath *path, struct statfs *stbuf)
                 err = -errno;
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     return err;
 }
 
@@ -69,7 +68,7 @@ int v9fs_co_chmod(V9fsState *s, V9fsPath *path, mode_t mode)
 
     cred_init(&cred);
     cred.fc_mode = mode;
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             err = s->ops->chmod(&s->ctx, path, &cred);
@@ -77,7 +76,7 @@ int v9fs_co_chmod(V9fsState *s, V9fsPath *path, mode_t mode)
                 err = -errno;
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     return err;
 }
 
@@ -86,7 +85,7 @@ int v9fs_co_utimensat(V9fsState *s, V9fsPath *path,
 {
     int err;
 
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             err = s->ops->utimensat(&s->ctx, path, times);
@@ -94,7 +93,7 @@ int v9fs_co_utimensat(V9fsState *s, V9fsPath *path,
                 err = -errno;
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     return err;
 }
 
@@ -106,7 +105,7 @@ int v9fs_co_chown(V9fsState *s, V9fsPath *path, uid_t uid, gid_t gid)
     cred_init(&cred);
     cred.fc_uid = uid;
     cred.fc_gid = gid;
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             err = s->ops->chown(&s->ctx, path, &cred);
@@ -114,7 +113,7 @@ int v9fs_co_chown(V9fsState *s, V9fsPath *path, uid_t uid, gid_t gid)
                 err = -errno;
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     return err;
 }
 
@@ -122,7 +121,7 @@ int v9fs_co_truncate(V9fsState *s, V9fsPath *path, off_t size)
 {
     int err;
 
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             err = s->ops->truncate(&s->ctx, path, size);
@@ -130,7 +129,7 @@ int v9fs_co_truncate(V9fsState *s, V9fsPath *path, off_t size)
                 err = -errno;
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     return err;
 }
 
@@ -146,7 +145,7 @@ int v9fs_co_mknod(V9fsState *s, V9fsFidState *fidp, V9fsString *name, uid_t uid,
     cred.fc_gid  = gid;
     cred.fc_mode = mode;
     cred.fc_rdev = dev;
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             err = s->ops->mknod(&s->ctx, &fidp->path, name->data, &cred);
@@ -164,7 +163,7 @@ int v9fs_co_mknod(V9fsState *s, V9fsFidState *fidp, V9fsString *name, uid_t uid,
                 v9fs_path_free(&path);
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     return err;
 }
 
@@ -173,7 +172,7 @@ int v9fs_co_remove(V9fsState *s, V9fsPath *path)
 {
     int err;
 
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             err = s->ops->remove(&s->ctx, path->data);
@@ -181,7 +180,7 @@ int v9fs_co_remove(V9fsState *s, V9fsPath *path)
                 err = -errno;
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     return err;
 }
 
@@ -189,7 +188,7 @@ int v9fs_co_unlinkat(V9fsState *s, V9fsPath *path, V9fsString *name, int flags)
 {
     int err;
 
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             err = s->ops->unlinkat(&s->ctx, path, name->data, flags);
@@ -197,7 +196,7 @@ int v9fs_co_unlinkat(V9fsState *s, V9fsPath *path, V9fsString *name, int flags)
                 err = -errno;
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     return err;
 }
 
@@ -244,7 +243,7 @@ int v9fs_co_symlink(V9fsState *s, V9fsFidState *dfidp, V9fsString *name,
     cred.fc_uid = dfidp->uid;
     cred.fc_gid = gid;
     cred.fc_mode = 0777;
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             err = s->ops->symlink(&s->ctx, oldpath, &dfidp->path,
@@ -263,7 +262,7 @@ int v9fs_co_symlink(V9fsState *s, V9fsFidState *dfidp, V9fsString *name,
                 v9fs_path_free(&path);
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     return err;
 }
 
@@ -275,9 +274,20 @@ int v9fs_co_name_to_path(V9fsState *s, V9fsPath *dirpath,
                          const char *name, V9fsPath *path)
 {
     int err;
-    err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
-    if (err < 0) {
-        err = -errno;
+
+    if (s->ctx.flags & PATHNAME_FSCONTEXT) {
+        err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
+        if (err < 0) {
+            err = -errno;
+        }
+    } else {
+        v9fs_co_run_in_worker(
+            {
+                err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
+                if (err < 0) {
+                    err = -errno;
+                }
+            });
     }
     return err;
 }
diff --git a/hw/9pfs/coxattr.c b/hw/9pfs/coxattr.c
index b723240..dd2e4a5 100644
--- a/hw/9pfs/coxattr.c
+++ b/hw/9pfs/coxattr.c
@@ -21,7 +21,7 @@ int v9fs_co_llistxattr(V9fsState *s, V9fsPath *path, void *value, size_t size)
 {
     int err;
 
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             err = s->ops->llistxattr(&s->ctx, path, value, size);
@@ -29,7 +29,7 @@ int v9fs_co_llistxattr(V9fsState *s, V9fsPath *path, void *value, size_t size)
                 err = -errno;
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     return err;
 }
 
@@ -39,7 +39,7 @@ int v9fs_co_lgetxattr(V9fsState *s, V9fsPath *path,
 {
     int err;
 
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             err = s->ops->lgetxattr(&s->ctx, path,
@@ -49,7 +49,7 @@ int v9fs_co_lgetxattr(V9fsState *s, V9fsPath *path,
                 err = -errno;
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     return err;
 }
 
@@ -59,7 +59,7 @@ int v9fs_co_lsetxattr(V9fsState *s, V9fsPath *path,
 {
     int err;
 
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             err = s->ops->lsetxattr(&s->ctx, path,
@@ -69,7 +69,7 @@ int v9fs_co_lsetxattr(V9fsState *s, V9fsPath *path,
                 err = -errno;
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     return err;
 }
 
@@ -78,7 +78,7 @@ int v9fs_co_lremovexattr(V9fsState *s, V9fsPath *path,
 {
     int err;
 
-    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_path_read_lock(s);
     v9fs_co_run_in_worker(
         {
             err = s->ops->lremovexattr(&s->ctx, path, xattr_name->data);
@@ -86,6 +86,6 @@ int v9fs_co_lremovexattr(V9fsState *s, V9fsPath *path,
                 err = -errno;
             }
         });
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     return err;
 }
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index 1ffe95b..320ed95 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -124,6 +124,7 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
     memcpy(s->tag, conf->tag, len);
     s->tag_len = len;
     s->ctx.uid = -1;
+    s->ctx.flags = 0;
 
     s->ops = fse->ops;
     s->vdev.get_features = virtio_9p_get_features;
diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c
index 61954fe..9559ff6 100644
--- a/hw/9pfs/virtio-9p-local.c
+++ b/hw/9pfs/virtio-9p-local.c
@@ -647,6 +647,7 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
 
 static int local_init(FsContext *ctx)
 {
+    ctx->flags |= PATHNAME_FSCONTEXT;
     return 0;
 }
 
diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index 82f1db5..2a68953 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -2332,6 +2332,7 @@ out_nofid:
     complete_pdu(s, pdu, err);
 }
 
+/* Only works with path name based fid */
 static void v9fs_remove(void *opaque)
 {
     int32_t fid;
@@ -2347,6 +2348,11 @@ static void v9fs_remove(void *opaque)
         err = -EINVAL;
         goto out_nofid;
     }
+    /* if fs driver is not path based, return EOPNOTSUPP */
+    if (!pdu->s->ctx.flags & PATHNAME_FSCONTEXT) {
+        err = -EOPNOTSUPP;
+        goto out_err;
+    }
     /*
      * IF the file is unlinked, we cannot reopen
      * the file later. So don't reclaim fd
@@ -2467,6 +2473,7 @@ out_nofid:
     return err;
 }
 
+/* Only works with path name based fid */
 static void v9fs_rename(void *opaque)
 {
     int32_t fid;
@@ -2486,13 +2493,18 @@ static void v9fs_rename(void *opaque)
         goto out_nofid;
     }
     BUG_ON(fidp->fid_type != P9_FID_NONE);
-
-    qemu_co_rwlock_wrlock(&s->rename_lock);
+    /* if fs driver is not path based, return EOPNOTSUPP */
+    if (!pdu->s->ctx.flags & PATHNAME_FSCONTEXT) {
+        err = -EOPNOTSUPP;
+        goto out;
+    }
+    v9fs_path_write_lock(s);
     err = v9fs_complete_rename(s, fidp, newdirfid, &name);
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     if (!err) {
         err = offset;
     }
+out:
     put_fid(s, fidp);
 out_nofid:
     complete_pdu(s, pdu, err);
@@ -2553,9 +2565,11 @@ static int v9fs_complete_renameat(V9fsState *s, int32_t olddirfid,
     if (err < 0) {
         goto out;
     }
-    /* Only for path based fid  we need to do the below fixup */
-    v9fs_fix_fid_paths(s, &olddirfidp->path, old_name,
-                       &newdirfidp->path, new_name);
+    if (s->ctx.flags & PATHNAME_FSCONTEXT) {
+        /* Only for path based fid  we need to do the below fixup */
+        v9fs_fix_fid_paths(s, &olddirfidp->path, old_name,
+                           &newdirfidp->path, new_name);
+    }
 out:
     if (olddirfidp) {
         put_fid(s, olddirfidp);
@@ -2578,9 +2592,9 @@ static void v9fs_renameat(void *opaque)
     pdu_unmarshal(pdu, offset, "dsds", &olddirfid,
                   &old_name, &newdirfid, &new_name);
 
-    qemu_co_rwlock_wrlock(&s->rename_lock);
+    v9fs_path_write_lock(s);
     err = v9fs_complete_renameat(s, olddirfid, &old_name, newdirfid, &new_name);
-    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_path_unlock(s);
     if (!err) {
         err = offset;
     }
diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
index 8c7c3f0..80147d4 100644
--- a/hw/9pfs/virtio-9p.h
+++ b/hw/9pfs/virtio-9p.h
@@ -388,6 +388,27 @@ static inline size_t do_pdu_unpack(void *dst, struct iovec *sg, int sg_count,
     return pdu_packunpack(dst, sg, sg_count, offset, size, 0);
 }
 
+static inline void v9fs_path_write_lock(V9fsState *s)
+{
+    if (s->ctx.flags & PATHNAME_FSCONTEXT) {
+        qemu_co_rwlock_wrlock(&s->rename_lock);
+    }
+}
+
+static inline void v9fs_path_read_lock(V9fsState *s)
+{
+    if (s->ctx.flags & PATHNAME_FSCONTEXT) {
+        qemu_co_rwlock_rdlock(&s->rename_lock);
+    }
+}
+
+static inline void v9fs_path_unlock(V9fsState *s)
+{
+    if (s->ctx.flags & PATHNAME_FSCONTEXT) {
+        qemu_co_rwlock_unlock(&s->rename_lock);
+    }
+}
+
 extern void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq);
 extern void virtio_9p_set_fd_limit(void);
 extern void v9fs_reclaim_fd(V9fsState *s);
commit 0174fe73e605311598d9e7f03e95be9705a3e0e7
Author: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Date:   Tue Aug 2 11:35:54 2011 +0530

    hw/9pfs: Add init callback to fs driver
    
    This call back can be used to do fs driver specific initialization.
    
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>

diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h
index 8a7dbdb..5221d6d 100644
--- a/fsdev/file-op-9p.h
+++ b/fsdev/file-op-9p.h
@@ -19,6 +19,7 @@
 #include <sys/stat.h>
 #include <sys/uio.h>
 #include <sys/vfs.h>
+
 #define SM_LOCAL_MODE_BITS    0600
 #define SM_LOCAL_DIR_MODE_BITS    0700
 
@@ -66,6 +67,7 @@ void cred_init(FsCred *);
 
 typedef struct FileOperations
 {
+    int (*init)(struct FsContext *);
     int (*lstat)(FsContext *, V9fsPath *, struct stat *);
     ssize_t (*readlink)(FsContext *, V9fsPath *, char *, size_t);
     int (*chmod)(FsContext *, V9fsPath *, FsCred *);
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index eea70cb..1ffe95b 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -45,7 +45,7 @@ static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config)
 }
 
 VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
- {
+{
     V9fsState *s;
     int i, len;
     struct stat stat;
@@ -133,6 +133,11 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
     s->fid_list = NULL;
     qemu_co_rwlock_init(&s->rename_lock);
 
+    if (s->ops->init(&s->ctx) < 0) {
+        fprintf(stderr, "Virtio-9p Failed to initialize fs-driver with id:%s"
+                " and export path:%s\n", conf->fsdev_id, s->ctx.fs_root);
+        exit(1);
+    }
     if (v9fs_init_worker_threads() < 0) {
         fprintf(stderr, "worker thread initialization failed\n");
         exit(1);
diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c
index 55f62f9..61954fe 100644
--- a/hw/9pfs/virtio-9p-local.c
+++ b/hw/9pfs/virtio-9p-local.c
@@ -21,7 +21,6 @@
 #include <sys/un.h>
 #include <attr/xattr.h>
 
-
 static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
 {
     int err;
@@ -646,7 +645,13 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
     return ret;
 }
 
+static int local_init(FsContext *ctx)
+{
+    return 0;
+}
+
 FileOperations local_ops = {
+    .init  = local_init,
     .lstat = local_lstat,
     .readlink = local_readlink,
     .close = local_close,
commit 2289be19aecc290263ef1f3c1f4a0e9ea32aaad6
Author: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Date:   Fri Sep 9 15:14:18 2011 +0530

    hw/9pfs: Move fid pathname tracking to seperate data type.
    
    This enables us to add handles to track fids later. The
    V9fsPath added is similar to V9fsString except that the
    size include the NULL byte also.
    
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>

diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h
index 1eda342..8a7dbdb 100644
--- a/fsdev/file-op-9p.h
+++ b/fsdev/file-op-9p.h
@@ -57,43 +57,53 @@ typedef struct FsContext
     struct xattr_operations **xops;
 } FsContext;
 
+typedef struct V9fsPath {
+    int16_t size;
+    char *data;
+} V9fsPath;
+
 void cred_init(FsCred *);
 
 typedef struct FileOperations
 {
-    int (*lstat)(FsContext *, const char *, struct stat *);
-    ssize_t (*readlink)(FsContext *, const char *, char *, size_t);
-    int (*chmod)(FsContext *, const char *, FsCred *);
-    int (*chown)(FsContext *, const char *, FsCred *);
-    int (*mknod)(FsContext *, const char *, FsCred *);
-    int (*utimensat)(FsContext *, const char *, const struct timespec *);
+    int (*lstat)(FsContext *, V9fsPath *, struct stat *);
+    ssize_t (*readlink)(FsContext *, V9fsPath *, char *, size_t);
+    int (*chmod)(FsContext *, V9fsPath *, FsCred *);
+    int (*chown)(FsContext *, V9fsPath *, FsCred *);
+    int (*mknod)(FsContext *, V9fsPath *, const char *, FsCred *);
+    int (*utimensat)(FsContext *, V9fsPath *, const struct timespec *);
     int (*remove)(FsContext *, const char *);
-    int (*symlink)(FsContext *, const char *, const char *, FsCred *);
-    int (*link)(FsContext *, const char *, const char *);
+    int (*symlink)(FsContext *, const char *, V9fsPath *,
+                   const char *, FsCred *);
+    int (*link)(FsContext *, V9fsPath *, V9fsPath *, const char *);
     int (*setuid)(FsContext *, uid_t);
     int (*close)(FsContext *, int);
     int (*closedir)(FsContext *, DIR *);
-    DIR *(*opendir)(FsContext *, const char *);
-    int (*open)(FsContext *, const char *, int);
-    int (*open2)(FsContext *, const char *, int, FsCred *);
+    DIR *(*opendir)(FsContext *, V9fsPath *);
+    int (*open)(FsContext *, V9fsPath *, int);
+    int (*open2)(FsContext *, V9fsPath *, const char *, int, FsCred *);
     void (*rewinddir)(FsContext *, DIR *);
     off_t (*telldir)(FsContext *, DIR *);
     int (*readdir_r)(FsContext *, DIR *, struct dirent *, struct dirent **);
     void (*seekdir)(FsContext *, DIR *, off_t);
     ssize_t (*preadv)(FsContext *, int, const struct iovec *, int, off_t);
     ssize_t (*pwritev)(FsContext *, int, const struct iovec *, int, off_t);
-    int (*mkdir)(FsContext *, const char *, FsCred *);
+    int (*mkdir)(FsContext *, V9fsPath *, const char *, FsCred *);
     int (*fstat)(FsContext *, int, struct stat *);
     int (*rename)(FsContext *, const char *, const char *);
-    int (*truncate)(FsContext *, const char *, off_t);
+    int (*truncate)(FsContext *, V9fsPath *, off_t);
     int (*fsync)(FsContext *, int, int);
-    int (*statfs)(FsContext *s, const char *path, struct statfs *stbuf);
-    ssize_t (*lgetxattr)(FsContext *, const char *,
+    int (*statfs)(FsContext *s, V9fsPath *path, struct statfs *stbuf);
+    ssize_t (*lgetxattr)(FsContext *, V9fsPath *,
                          const char *, void *, size_t);
-    ssize_t (*llistxattr)(FsContext *, const char *, void *, size_t);
-    int (*lsetxattr)(FsContext *, const char *,
+    ssize_t (*llistxattr)(FsContext *, V9fsPath *, void *, size_t);
+    int (*lsetxattr)(FsContext *, V9fsPath *,
                      const char *, void *, size_t, int);
-    int (*lremovexattr)(FsContext *, const char *, const char *);
+    int (*lremovexattr)(FsContext *, V9fsPath *, const char *);
+    int (*name_to_path)(FsContext *, V9fsPath *, const char *, V9fsPath *);
+    int (*renameat)(FsContext *ctx, V9fsPath *olddir, const char *old_name,
+                    V9fsPath *newdir, const char *new_name);
+    int (*unlinkat)(FsContext *ctx, V9fsPath *dir, const char *name, int flags);
     void *opaque;
 } FileOperations;
 
diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c
index c9a88ec..2c50df8 100644
--- a/hw/9pfs/codir.c
+++ b/hw/9pfs/codir.c
@@ -70,29 +70,31 @@ int v9fs_co_mkdir(V9fsState *s, V9fsFidState *fidp, V9fsString *name,
 {
     int err;
     FsCred cred;
-    V9fsString fullname;
+    V9fsPath path;
 
     cred_init(&cred);
     cred.fc_mode = mode;
     cred.fc_uid = uid;
     cred.fc_gid = gid;
-    v9fs_string_init(&fullname);
     qemu_co_rwlock_rdlock(&s->rename_lock);
-    v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name->data);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->mkdir(&s->ctx, fullname.data, &cred);
+            err = s->ops->mkdir(&s->ctx, &fidp->path, name->data,  &cred);
             if (err < 0) {
                 err = -errno;
             } else {
-                err = s->ops->lstat(&s->ctx, fullname.data, stbuf);
-                if (err < 0) {
-                    err = -errno;
+                v9fs_path_init(&path);
+                err = v9fs_name_to_path(s, &fidp->path, name->data, &path);
+                if (!err) {
+                    err = s->ops->lstat(&s->ctx, &path, stbuf);
+                    if (err < 0) {
+                        err = -errno;
+                    }
                 }
+                v9fs_path_free(&path);
             }
         });
     qemu_co_rwlock_unlock(&s->rename_lock);
-    v9fs_string_free(&fullname);
     return err;
 }
 
@@ -103,7 +105,7 @@ int v9fs_co_opendir(V9fsState *s, V9fsFidState *fidp)
     qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
-            fidp->fs.dir = s->ops->opendir(&s->ctx, fidp->path.data);
+            fidp->fs.dir = s->ops->opendir(&s->ctx, &fidp->path);
             if (!fidp->fs.dir) {
                 err = -errno;
             } else {
diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c
index cc62846..69fad36 100644
--- a/hw/9pfs/cofile.c
+++ b/hw/9pfs/cofile.c
@@ -17,14 +17,14 @@
 #include "qemu-coroutine.h"
 #include "virtio-9p-coth.h"
 
-int v9fs_co_lstat(V9fsState *s, V9fsString *path, struct stat *stbuf)
+int v9fs_co_lstat(V9fsState *s, V9fsPath *path, struct stat *stbuf)
 {
     int err;
 
     qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->lstat(&s->ctx, path->data, stbuf);
+            err = s->ops->lstat(&s->ctx, path, stbuf);
             if (err < 0) {
                 err = -errno;
             }
@@ -54,7 +54,7 @@ int v9fs_co_open(V9fsState *s, V9fsFidState *fidp, int flags)
     qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
-            fidp->fs.fd = s->ops->open(&s->ctx, fidp->path.data, flags);
+            fidp->fs.fd = s->ops->open(&s->ctx, &fidp->path, flags);
             if (fidp->fs.fd == -1) {
                 err = -errno;
             } else {
@@ -76,33 +76,40 @@ int v9fs_co_open2(V9fsState *s, V9fsFidState *fidp, V9fsString *name, gid_t gid,
 {
     int err;
     FsCred cred;
-    V9fsString fullname;
+    V9fsPath path;
+
 
     cred_init(&cred);
     cred.fc_mode = mode & 07777;
     cred.fc_uid = fidp->uid;
     cred.fc_gid = gid;
-    v9fs_string_init(&fullname);
     /*
      * Hold the directory fid lock so that directory path name
      * don't change. Read lock is fine because this fid cannot
      * be used by any other operation.
      */
     qemu_co_rwlock_rdlock(&s->rename_lock);
-    v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name->data);
     v9fs_co_run_in_worker(
         {
-            fidp->fs.fd = s->ops->open2(&s->ctx, fullname.data, flags, &cred);
+            fidp->fs.fd = s->ops->open2(&s->ctx, &fidp->path,
+                                        name->data, flags, &cred);
             if (fidp->fs.fd == -1) {
                 err = -errno;
             } else {
-                err = s->ops->lstat(&s->ctx, fullname.data, stbuf);
-                if (err < 0) {
-                    err = -errno;
-                    err = s->ops->close(&s->ctx, fidp->fs.fd);
+                v9fs_path_init(&path);
+                err = v9fs_name_to_path(s, &fidp->path, name->data, &path);
+                if (!err) {
+                    err = s->ops->lstat(&s->ctx, &path, stbuf);
+                    if (err < 0) {
+                        err = -errno;
+                        s->ops->close(&s->ctx, fidp->fs.fd);
+                    } else {
+                        v9fs_path_copy(&fidp->path, &path);
+                    }
                 } else {
-                    v9fs_string_copy(&fidp->path, &fullname);
+                    s->ops->close(&s->ctx, fidp->fs.fd);
                 }
+                v9fs_path_free(&path);
             }
         });
     qemu_co_rwlock_unlock(&s->rename_lock);
@@ -112,7 +119,6 @@ int v9fs_co_open2(V9fsState *s, V9fsFidState *fidp, V9fsString *name, gid_t gid,
             v9fs_reclaim_fd(s);
         }
     }
-    v9fs_string_free(&fullname);
     return err;
 }
 
@@ -149,14 +155,16 @@ int v9fs_co_fsync(V9fsState *s, V9fsFidState *fidp, int datasync)
     return err;
 }
 
-int v9fs_co_link(V9fsState *s, V9fsString *oldpath, V9fsString *newpath)
+int v9fs_co_link(V9fsState *s, V9fsFidState *oldfid,
+                 V9fsFidState *newdirfid, V9fsString *name)
 {
     int err;
 
     qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->link(&s->ctx, oldpath->data, newpath->data);
+            err = s->ops->link(&s->ctx, &oldfid->path,
+                               &newdirfid->path, name->data);
             if (err < 0) {
                 err = -errno;
             }
diff --git a/hw/9pfs/cofs.c b/hw/9pfs/cofs.c
index 98860f9..7f5220e 100644
--- a/hw/9pfs/cofs.c
+++ b/hw/9pfs/cofs.c
@@ -17,7 +17,7 @@
 #include "qemu-coroutine.h"
 #include "virtio-9p-coth.h"
 
-int v9fs_co_readlink(V9fsState *s, V9fsString *path, V9fsString *buf)
+int v9fs_co_readlink(V9fsState *s, V9fsPath *path, V9fsString *buf)
 {
     int err;
     ssize_t len;
@@ -27,7 +27,7 @@ int v9fs_co_readlink(V9fsState *s, V9fsString *path, V9fsString *buf)
 
     v9fs_co_run_in_worker(
         {
-            len = s->ops->readlink(&s->ctx, path->data,
+            len = s->ops->readlink(&s->ctx, path,
                                    buf->data, PATH_MAX - 1);
             if (len > -1) {
                 buf->size = len;
@@ -46,14 +46,14 @@ int v9fs_co_readlink(V9fsState *s, V9fsString *path, V9fsString *buf)
     return err;
 }
 
-int v9fs_co_statfs(V9fsState *s, V9fsString *path, struct statfs *stbuf)
+int v9fs_co_statfs(V9fsState *s, V9fsPath *path, struct statfs *stbuf)
 {
     int err;
 
     qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->statfs(&s->ctx, path->data, stbuf);
+            err = s->ops->statfs(&s->ctx, path, stbuf);
             if (err < 0) {
                 err = -errno;
             }
@@ -62,7 +62,7 @@ int v9fs_co_statfs(V9fsState *s, V9fsString *path, struct statfs *stbuf)
     return err;
 }
 
-int v9fs_co_chmod(V9fsState *s, V9fsString *path, mode_t mode)
+int v9fs_co_chmod(V9fsState *s, V9fsPath *path, mode_t mode)
 {
     int err;
     FsCred cred;
@@ -72,7 +72,7 @@ int v9fs_co_chmod(V9fsState *s, V9fsString *path, mode_t mode)
     qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->chmod(&s->ctx, path->data, &cred);
+            err = s->ops->chmod(&s->ctx, path, &cred);
             if (err < 0) {
                 err = -errno;
             }
@@ -81,7 +81,7 @@ int v9fs_co_chmod(V9fsState *s, V9fsString *path, mode_t mode)
     return err;
 }
 
-int v9fs_co_utimensat(V9fsState *s, V9fsString *path,
+int v9fs_co_utimensat(V9fsState *s, V9fsPath *path,
                       struct timespec times[2])
 {
     int err;
@@ -89,7 +89,7 @@ int v9fs_co_utimensat(V9fsState *s, V9fsString *path,
     qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->utimensat(&s->ctx, path->data, times);
+            err = s->ops->utimensat(&s->ctx, path, times);
             if (err < 0) {
                 err = -errno;
             }
@@ -98,7 +98,7 @@ int v9fs_co_utimensat(V9fsState *s, V9fsString *path,
     return err;
 }
 
-int v9fs_co_chown(V9fsState *s, V9fsString *path, uid_t uid, gid_t gid)
+int v9fs_co_chown(V9fsState *s, V9fsPath *path, uid_t uid, gid_t gid)
 {
     int err;
     FsCred cred;
@@ -109,7 +109,7 @@ int v9fs_co_chown(V9fsState *s, V9fsString *path, uid_t uid, gid_t gid)
     qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->chown(&s->ctx, path->data, &cred);
+            err = s->ops->chown(&s->ctx, path, &cred);
             if (err < 0) {
                 err = -errno;
             }
@@ -118,14 +118,14 @@ int v9fs_co_chown(V9fsState *s, V9fsString *path, uid_t uid, gid_t gid)
     return err;
 }
 
-int v9fs_co_truncate(V9fsState *s, V9fsString *path, off_t size)
+int v9fs_co_truncate(V9fsState *s, V9fsPath *path, off_t size)
 {
     int err;
 
     qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->truncate(&s->ctx, path->data, size);
+            err = s->ops->truncate(&s->ctx, path, size);
             if (err < 0) {
                 err = -errno;
             }
@@ -138,35 +138,38 @@ int v9fs_co_mknod(V9fsState *s, V9fsFidState *fidp, V9fsString *name, uid_t uid,
                   gid_t gid, dev_t dev, mode_t mode, struct stat *stbuf)
 {
     int err;
+    V9fsPath path;
     FsCred cred;
-    V9fsString fullname;
 
     cred_init(&cred);
     cred.fc_uid  = uid;
     cred.fc_gid  = gid;
     cred.fc_mode = mode;
     cred.fc_rdev = dev;
-    v9fs_string_init(&fullname);
     qemu_co_rwlock_rdlock(&s->rename_lock);
-    v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name->data);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->mknod(&s->ctx, fullname.data, &cred);
+            err = s->ops->mknod(&s->ctx, &fidp->path, name->data, &cred);
             if (err < 0) {
                 err = -errno;
             } else {
-                err = s->ops->lstat(&s->ctx, fullname.data, stbuf);
-                if (err < 0) {
-                    err = -errno;
+                v9fs_path_init(&path);
+                err = v9fs_name_to_path(s, &fidp->path, name->data, &path);
+                if (!err) {
+                    err = s->ops->lstat(&s->ctx, &path, stbuf);
+                    if (err < 0) {
+                        err = -errno;
+                    }
                 }
+                v9fs_path_free(&path);
             }
         });
     qemu_co_rwlock_unlock(&s->rename_lock);
-    v9fs_string_free(&fullname);
     return err;
 }
 
-int v9fs_co_remove(V9fsState *s, V9fsString *path)
+/* Only works with path name based fid */
+int v9fs_co_remove(V9fsState *s, V9fsPath *path)
 {
     int err;
 
@@ -182,7 +185,24 @@ int v9fs_co_remove(V9fsState *s, V9fsString *path)
     return err;
 }
 
-int v9fs_co_rename(V9fsState *s, V9fsString *oldpath, V9fsString *newpath)
+int v9fs_co_unlinkat(V9fsState *s, V9fsPath *path, V9fsString *name, int flags)
+{
+    int err;
+
+    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->unlinkat(&s->ctx, path, name->data, flags);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    qemu_co_rwlock_unlock(&s->rename_lock);
+    return err;
+}
+
+/* Only work with path name based fid */
+int v9fs_co_rename(V9fsState *s, V9fsPath *oldpath, V9fsPath *newpath)
 {
     int err;
 
@@ -196,34 +216,68 @@ int v9fs_co_rename(V9fsState *s, V9fsString *oldpath, V9fsString *newpath)
     return err;
 }
 
+int v9fs_co_renameat(V9fsState *s, V9fsPath *olddirpath, V9fsString *oldname,
+                     V9fsPath *newdirpath, V9fsString *newname)
+{
+    int err;
+
+    v9fs_co_run_in_worker(
+        {
+            err = s->ops->renameat(&s->ctx, olddirpath, oldname->data,
+                                   newdirpath, newname->data);
+            if (err < 0) {
+                err = -errno;
+            }
+        });
+    return err;
+}
+
 int v9fs_co_symlink(V9fsState *s, V9fsFidState *dfidp, V9fsString *name,
                     const char *oldpath, gid_t gid, struct stat *stbuf)
 {
     int err;
     FsCred cred;
-    V9fsString fullname;
+    V9fsPath path;
 
 
     cred_init(&cred);
     cred.fc_uid = dfidp->uid;
     cred.fc_gid = gid;
     cred.fc_mode = 0777;
-    v9fs_string_init(&fullname);
     qemu_co_rwlock_rdlock(&s->rename_lock);
-    v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name->data);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->symlink(&s->ctx, oldpath, fullname.data, &cred);
+            err = s->ops->symlink(&s->ctx, oldpath, &dfidp->path,
+                                  name->data, &cred);
             if (err < 0) {
                 err = -errno;
             } else {
-                err = s->ops->lstat(&s->ctx, fullname.data, stbuf);
-                if (err < 0) {
-                    err = -errno;
+                v9fs_path_init(&path);
+                err = v9fs_name_to_path(s, &dfidp->path, name->data, &path);
+                if (!err) {
+                    err = s->ops->lstat(&s->ctx, &path, stbuf);
+                    if (err < 0) {
+                        err = -errno;
+                    }
                 }
+                v9fs_path_free(&path);
             }
         });
     qemu_co_rwlock_unlock(&s->rename_lock);
-    v9fs_string_free(&fullname);
+    return err;
+}
+
+/*
+ * For path name based fid we don't block. So we can
+ * directly call the fs driver ops.
+ */
+int v9fs_co_name_to_path(V9fsState *s, V9fsPath *dirpath,
+                         const char *name, V9fsPath *path)
+{
+    int err;
+    err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
+    if (err < 0) {
+        err = -errno;
+    }
     return err;
 }
diff --git a/hw/9pfs/coxattr.c b/hw/9pfs/coxattr.c
index 7b93c8f..b723240 100644
--- a/hw/9pfs/coxattr.c
+++ b/hw/9pfs/coxattr.c
@@ -17,14 +17,14 @@
 #include "qemu-coroutine.h"
 #include "virtio-9p-coth.h"
 
-int v9fs_co_llistxattr(V9fsState *s, V9fsString *path, void *value, size_t size)
+int v9fs_co_llistxattr(V9fsState *s, V9fsPath *path, void *value, size_t size)
 {
     int err;
 
     qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->llistxattr(&s->ctx, path->data, value, size);
+            err = s->ops->llistxattr(&s->ctx, path, value, size);
             if (err < 0) {
                 err = -errno;
             }
@@ -33,7 +33,7 @@ int v9fs_co_llistxattr(V9fsState *s, V9fsString *path, void *value, size_t size)
     return err;
 }
 
-int v9fs_co_lgetxattr(V9fsState *s, V9fsString *path,
+int v9fs_co_lgetxattr(V9fsState *s, V9fsPath *path,
                       V9fsString *xattr_name,
                       void *value, size_t size)
 {
@@ -42,7 +42,7 @@ int v9fs_co_lgetxattr(V9fsState *s, V9fsString *path,
     qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->lgetxattr(&s->ctx, path->data,
+            err = s->ops->lgetxattr(&s->ctx, path,
                                     xattr_name->data,
                                     value, size);
             if (err < 0) {
@@ -53,7 +53,7 @@ int v9fs_co_lgetxattr(V9fsState *s, V9fsString *path,
     return err;
 }
 
-int v9fs_co_lsetxattr(V9fsState *s, V9fsString *path,
+int v9fs_co_lsetxattr(V9fsState *s, V9fsPath *path,
                       V9fsString *xattr_name, void *value,
                       size_t size, int flags)
 {
@@ -62,7 +62,7 @@ int v9fs_co_lsetxattr(V9fsState *s, V9fsString *path,
     qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->lsetxattr(&s->ctx, path->data,
+            err = s->ops->lsetxattr(&s->ctx, path,
                                     xattr_name->data, value,
                                     size, flags);
             if (err < 0) {
@@ -73,7 +73,7 @@ int v9fs_co_lsetxattr(V9fsState *s, V9fsString *path,
     return err;
 }
 
-int v9fs_co_lremovexattr(V9fsState *s, V9fsString *path,
+int v9fs_co_lremovexattr(V9fsState *s, V9fsPath *path,
                          V9fsString *xattr_name)
 {
     int err;
@@ -81,8 +81,7 @@ int v9fs_co_lremovexattr(V9fsState *s, V9fsString *path,
     qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->lremovexattr(&s->ctx, path->data,
-                                       xattr_name->data);
+            err = s->ops->lremovexattr(&s->ctx, path, xattr_name->data);
             if (err < 0) {
                 err = -errno;
             }
diff --git a/hw/9pfs/virtio-9p-coth.h b/hw/9pfs/virtio-9p-coth.h
index e5f46c5..cd94571 100644
--- a/hw/9pfs/virtio-9p-coth.h
+++ b/hw/9pfs/virtio-9p-coth.h
@@ -56,43 +56,49 @@ typedef struct V9fsThPool {
 
 extern void co_run_in_worker_bh(void *);
 extern int v9fs_init_worker_threads(void);
-extern int v9fs_co_readlink(V9fsState *, V9fsString *, V9fsString *);
+extern int v9fs_co_readlink(V9fsState *, V9fsPath *, V9fsString *);
 extern int v9fs_co_readdir_r(V9fsState *, V9fsFidState *,
                            struct dirent *, struct dirent **result);
 extern off_t v9fs_co_telldir(V9fsState *, V9fsFidState *);
 extern void v9fs_co_seekdir(V9fsState *, V9fsFidState *, off_t);
 extern void v9fs_co_rewinddir(V9fsState *, V9fsFidState *);
-extern int v9fs_co_statfs(V9fsState *, V9fsString *, struct statfs *);
-extern int v9fs_co_lstat(V9fsState *, V9fsString *, struct stat *);
-extern int v9fs_co_chmod(V9fsState *, V9fsString *, mode_t);
-extern int v9fs_co_utimensat(V9fsState *, V9fsString *, struct timespec [2]);
-extern int v9fs_co_chown(V9fsState *, V9fsString *, uid_t, gid_t);
-extern int v9fs_co_truncate(V9fsState *, V9fsString *, off_t);
-extern int v9fs_co_llistxattr(V9fsState *, V9fsString *, void *, size_t);
-extern int v9fs_co_lgetxattr(V9fsState *, V9fsString *,
+extern int v9fs_co_statfs(V9fsState *, V9fsPath *, struct statfs *);
+extern int v9fs_co_lstat(V9fsState *, V9fsPath *, struct stat *);
+extern int v9fs_co_chmod(V9fsState *, V9fsPath *, mode_t);
+extern int v9fs_co_utimensat(V9fsState *, V9fsPath *, struct timespec [2]);
+extern int v9fs_co_chown(V9fsState *, V9fsPath *, uid_t, gid_t);
+extern int v9fs_co_truncate(V9fsState *, V9fsPath *, off_t);
+extern int v9fs_co_llistxattr(V9fsState *, V9fsPath *, void *, size_t);
+extern int v9fs_co_lgetxattr(V9fsState *, V9fsPath *,
                              V9fsString *, void *, size_t);
 extern int v9fs_co_mknod(V9fsState *, V9fsFidState *, V9fsString *, uid_t,
                          gid_t, dev_t, mode_t, struct stat *);
 extern int v9fs_co_mkdir(V9fsState *, V9fsFidState *, V9fsString *,
                          mode_t, uid_t, gid_t, struct stat *);
-extern int v9fs_co_remove(V9fsState *, V9fsString *);
-extern int v9fs_co_rename(V9fsState *, V9fsString *, V9fsString *);
+extern int v9fs_co_remove(V9fsState *, V9fsPath *);
+extern int v9fs_co_rename(V9fsState *, V9fsPath *, V9fsPath *);
+extern int v9fs_co_unlinkat(V9fsState *, V9fsPath *, V9fsString *, int flags);
+extern int v9fs_co_renameat(V9fsState *, V9fsPath *, V9fsString *,
+                            V9fsPath *, V9fsString *);
 extern int v9fs_co_fstat(V9fsState *, int, struct stat *);
 extern int v9fs_co_opendir(V9fsState *, V9fsFidState *);
 extern int v9fs_co_open(V9fsState *, V9fsFidState *, int);
 extern int v9fs_co_open2(V9fsState *, V9fsFidState *, V9fsString *,
                          gid_t, int, int, struct stat *);
-extern int v9fs_co_lsetxattr(V9fsState *, V9fsString *, V9fsString *,
+extern int v9fs_co_lsetxattr(V9fsState *, V9fsPath *, V9fsString *,
                              void *, size_t, int);
-extern int v9fs_co_lremovexattr(V9fsState *, V9fsString *, V9fsString *);
+extern int v9fs_co_lremovexattr(V9fsState *, V9fsPath *, V9fsString *);
 extern int v9fs_co_closedir(V9fsState *, DIR *);
 extern int v9fs_co_close(V9fsState *, int);
 extern int v9fs_co_fsync(V9fsState *, V9fsFidState *, int);
 extern int v9fs_co_symlink(V9fsState *, V9fsFidState *, V9fsString *,
                            const char *, gid_t, struct stat *);
-extern int v9fs_co_link(V9fsState *, V9fsString *, V9fsString *);
+extern int v9fs_co_link(V9fsState *, V9fsFidState *,
+                        V9fsFidState *, V9fsString *);
 extern int v9fs_co_pwritev(V9fsState *, V9fsFidState *,
                            struct iovec *, int, int64_t);
 extern int v9fs_co_preadv(V9fsState *, V9fsFidState *,
                           struct iovec *, int, int64_t);
+extern int v9fs_co_name_to_path(V9fsState *, V9fsPath *,
+                                const char *, V9fsPath *);
 #endif
diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c
index 61cbf8d..55f62f9 100644
--- a/hw/9pfs/virtio-9p-local.c
+++ b/hw/9pfs/virtio-9p-local.c
@@ -22,10 +22,12 @@
 #include <attr/xattr.h>
 
 
-static int local_lstat(FsContext *fs_ctx, const char *path, struct stat *stbuf)
+static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
 {
     int err;
     char buffer[PATH_MAX];
+    char *path = fs_path->data;
+
     err =  lstat(rpath(fs_ctx, path, buffer), stbuf);
     if (err) {
         return err;
@@ -59,6 +61,7 @@ static int local_lstat(FsContext *fs_ctx, const char *path, struct stat *stbuf)
 static int local_set_xattr(const char *path, FsCred *credp)
 {
     int err;
+
     if (credp->fc_uid != -1) {
         err = setxattr(path, "user.virtfs.uid", &credp->fc_uid, sizeof(uid_t),
                 0);
@@ -91,9 +94,10 @@ static int local_set_xattr(const char *path, FsCred *credp)
 }
 
 static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
-        FsCred *credp)
+                                         FsCred *credp)
 {
     char buffer[PATH_MAX];
+
     if (chmod(rpath(fs_ctx, path, buffer), credp->fc_mode & 07777) < 0) {
         return -1;
     }
@@ -110,11 +114,13 @@ static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
     return 0;
 }
 
-static ssize_t local_readlink(FsContext *fs_ctx, const char *path,
-        char *buf, size_t bufsz)
+static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
+                              char *buf, size_t bufsz)
 {
     ssize_t tsize = -1;
     char buffer[PATH_MAX];
+    char *path = fs_path->data;
+
     if (fs_ctx->fs_sm == SM_MAPPED) {
         int fd;
         fd = open(rpath(fs_ctx, path, buffer), O_RDONLY);
@@ -143,15 +149,19 @@ static int local_closedir(FsContext *ctx, DIR *dir)
     return closedir(dir);
 }
 
-static int local_open(FsContext *ctx, const char *path, int flags)
+static int local_open(FsContext *ctx, V9fsPath *fs_path, int flags)
 {
     char buffer[PATH_MAX];
+    char *path = fs_path->data;
+
     return open(rpath(ctx, path, buffer), flags);
 }
 
-static DIR *local_opendir(FsContext *ctx, const char *path)
+static DIR *local_opendir(FsContext *ctx, V9fsPath *fs_path)
 {
     char buffer[PATH_MAX];
+    char *path = fs_path->data;
+
     return opendir(rpath(ctx, path, buffer));
 }
 
@@ -166,7 +176,7 @@ static off_t local_telldir(FsContext *ctx, DIR *dir)
 }
 
 static int local_readdir_r(FsContext *ctx, DIR *dir, struct dirent *entry,
-                         struct dirent **result)
+                           struct dirent **result)
 {
     return readdir_r(dir, entry, result);
 }
@@ -192,7 +202,7 @@ static ssize_t local_preadv(FsContext *ctx, int fd, const struct iovec *iov,
 }
 
 static ssize_t local_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
-                            int iovcnt, off_t offset)
+                             int iovcnt, off_t offset)
 {
 #ifdef CONFIG_PREADV
     return pwritev(fd, iov, iovcnt, offset);
@@ -206,9 +216,11 @@ static ssize_t local_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
 #endif
 }
 
-static int local_chmod(FsContext *fs_ctx, const char *path, FsCred *credp)
+static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
 {
     char buffer[PATH_MAX];
+    char *path = fs_path->data;
+
     if (fs_ctx->fs_sm == SM_MAPPED) {
         return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
     } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
@@ -218,18 +230,25 @@ static int local_chmod(FsContext *fs_ctx, const char *path, FsCred *credp)
     return -1;
 }
 
-static int local_mknod(FsContext *fs_ctx, const char *path, FsCred *credp)
+static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
+                       const char *name, FsCred *credp)
 {
+    char *path;
     int err = -1;
     int serrno = 0;
+    V9fsString fullname;
     char buffer[PATH_MAX];
 
+    v9fs_string_init(&fullname);
+    v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
+    path = fullname.data;
+
     /* Determine the security model */
     if (fs_ctx->fs_sm == SM_MAPPED) {
         err = mknod(rpath(fs_ctx, path, buffer),
                 SM_LOCAL_MODE_BITS|S_IFREG, 0);
         if (err == -1) {
-            return err;
+            goto out;
         }
         local_set_xattr(rpath(fs_ctx, path, buffer), credp);
         if (err == -1) {
@@ -241,7 +260,7 @@ static int local_mknod(FsContext *fs_ctx, const char *path, FsCred *credp)
         err = mknod(rpath(fs_ctx, path, buffer), credp->fc_mode,
                 credp->fc_rdev);
         if (err == -1) {
-            return err;
+            goto out;
         }
         err = local_post_create_passthrough(fs_ctx, path, credp);
         if (err == -1) {
@@ -249,25 +268,34 @@ static int local_mknod(FsContext *fs_ctx, const char *path, FsCred *credp)
             goto err_end;
         }
     }
-    return err;
+    goto out;
 
 err_end:
     remove(rpath(fs_ctx, path, buffer));
     errno = serrno;
+out:
+    v9fs_string_free(&fullname);
     return err;
 }
 
-static int local_mkdir(FsContext *fs_ctx, const char *path, FsCred *credp)
+static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
+                       const char *name, FsCred *credp)
 {
+    char *path;
     int err = -1;
     int serrno = 0;
+    V9fsString fullname;
     char buffer[PATH_MAX];
 
+    v9fs_string_init(&fullname);
+    v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
+    path = fullname.data;
+
     /* Determine the security model */
     if (fs_ctx->fs_sm == SM_MAPPED) {
         err = mkdir(rpath(fs_ctx, path, buffer), SM_LOCAL_DIR_MODE_BITS);
         if (err == -1) {
-            return err;
+            goto out;
         }
         credp->fc_mode = credp->fc_mode|S_IFDIR;
         err = local_set_xattr(rpath(fs_ctx, path, buffer), credp);
@@ -279,7 +307,7 @@ static int local_mkdir(FsContext *fs_ctx, const char *path, FsCred *credp)
                (fs_ctx->fs_sm == SM_NONE)) {
         err = mkdir(rpath(fs_ctx, path, buffer), credp->fc_mode);
         if (err == -1) {
-            return err;
+            goto out;
         }
         err = local_post_create_passthrough(fs_ctx, path, credp);
         if (err == -1) {
@@ -287,11 +315,13 @@ static int local_mkdir(FsContext *fs_ctx, const char *path, FsCred *credp)
             goto err_end;
         }
     }
-    return err;
+    goto out;
 
 err_end:
     remove(rpath(fs_ctx, path, buffer));
     errno = serrno;
+out:
+    v9fs_string_free(&fullname);
     return err;
 }
 
@@ -325,19 +355,26 @@ static int local_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf)
     return err;
 }
 
-static int local_open2(FsContext *fs_ctx, const char *path, int flags,
-        FsCred *credp)
+static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
+                       int flags, FsCred *credp)
 {
+    char *path;
     int fd = -1;
     int err = -1;
     int serrno = 0;
+    V9fsString fullname;
     char buffer[PATH_MAX];
 
+    v9fs_string_init(&fullname);
+    v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
+    path = fullname.data;
+
     /* Determine the security model */
     if (fs_ctx->fs_sm == SM_MAPPED) {
         fd = open(rpath(fs_ctx, path, buffer), flags, SM_LOCAL_MODE_BITS);
         if (fd == -1) {
-            return fd;
+            err = fd;
+            goto out;
         }
         credp->fc_mode = credp->fc_mode|S_IFREG;
         /* Set cleint credentials in xattr */
@@ -350,7 +387,8 @@ static int local_open2(FsContext *fs_ctx, const char *path, int flags,
                (fs_ctx->fs_sm == SM_NONE)) {
         fd = open(rpath(fs_ctx, path, buffer), flags, credp->fc_mode);
         if (fd == -1) {
-            return fd;
+            err = fd;
+            goto out;
         }
         err = local_post_create_passthrough(fs_ctx, path, credp);
         if (err == -1) {
@@ -358,23 +396,32 @@ static int local_open2(FsContext *fs_ctx, const char *path, int flags,
             goto err_end;
         }
     }
-    return fd;
+    err = fd;
+    goto out;
 
 err_end:
     close(fd);
     remove(rpath(fs_ctx, path, buffer));
     errno = serrno;
+out:
+    v9fs_string_free(&fullname);
     return err;
 }
 
 
 static int local_symlink(FsContext *fs_ctx, const char *oldpath,
-        const char *newpath, FsCred *credp)
+                         V9fsPath *dir_path, const char *name, FsCred *credp)
 {
     int err = -1;
     int serrno = 0;
+    char *newpath;
+    V9fsString fullname;
     char buffer[PATH_MAX];
 
+    v9fs_string_init(&fullname);
+    v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
+    newpath = fullname.data;
+
     /* Determine the security model */
     if (fs_ctx->fs_sm == SM_MAPPED) {
         int fd;
@@ -382,7 +429,8 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
         fd = open(rpath(fs_ctx, newpath, buffer), O_CREAT|O_EXCL|O_RDWR,
                 SM_LOCAL_MODE_BITS);
         if (fd == -1) {
-            return fd;
+            err = fd;
+            goto out;
         }
         /* Write the oldpath (target) to the file. */
         oldpath_size = strlen(oldpath);
@@ -408,10 +456,10 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
                (fs_ctx->fs_sm == SM_NONE)) {
         err = symlink(oldpath, rpath(fs_ctx, newpath, buffer));
         if (err) {
-            return err;
+            goto out;
         }
         err = lchown(rpath(fs_ctx, newpath, buffer), credp->fc_uid,
-                credp->fc_gid);
+                     credp->fc_gid);
         if (err == -1) {
             /*
              * If we fail to change ownership and if we are
@@ -424,24 +472,37 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
                 err = 0;
         }
     }
-    return err;
+    goto out;
 
 err_end:
     remove(rpath(fs_ctx, newpath, buffer));
     errno = serrno;
+out:
+    v9fs_string_free(&fullname);
     return err;
 }
 
-static int local_link(FsContext *ctx, const char *oldpath, const char *newpath)
+static int local_link(FsContext *ctx, V9fsPath *oldpath,
+                      V9fsPath *dirpath, const char *name)
 {
+    int ret;
+    V9fsString newpath;
     char buffer[PATH_MAX], buffer1[PATH_MAX];
 
-    return link(rpath(ctx, oldpath, buffer), rpath(ctx, newpath, buffer1));
+    v9fs_string_init(&newpath);
+    v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name);
+
+    ret = link(rpath(ctx, oldpath->data, buffer),
+               rpath(ctx, newpath.data, buffer1));
+    v9fs_string_free(&newpath);
+    return ret;
 }
 
-static int local_truncate(FsContext *ctx, const char *path, off_t size)
+static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
 {
     char buffer[PATH_MAX];
+    char *path = fs_path->data;
+
     return truncate(rpath(ctx, path, buffer), size);
 }
 
@@ -453,9 +514,11 @@ static int local_rename(FsContext *ctx, const char *oldpath,
     return rename(rpath(ctx, oldpath, buffer), rpath(ctx, newpath, buffer1));
 }
 
-static int local_chown(FsContext *fs_ctx, const char *path, FsCred *credp)
+static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
 {
     char buffer[PATH_MAX];
+    char *path = fs_path->data;
+
     if ((credp->fc_uid == -1 && credp->fc_gid == -1) ||
             (fs_ctx->fs_sm == SM_PASSTHROUGH)) {
         return lchown(rpath(fs_ctx, path, buffer), credp->fc_uid,
@@ -470,12 +533,14 @@ static int local_chown(FsContext *fs_ctx, const char *path, FsCred *credp)
     return -1;
 }
 
-static int local_utimensat(FsContext *s, const char *path,
+static int local_utimensat(FsContext *s, V9fsPath *fs_path,
                            const struct timespec *buf)
 {
     char buffer[PATH_MAX];
+    char *path = fs_path->data;
+
     return qemu_utimensat(AT_FDCWD, rpath(s, path, buffer), buf,
-            AT_SYMLINK_NOFOLLOW);
+                          AT_SYMLINK_NOFOLLOW);
 }
 
 static int local_remove(FsContext *ctx, const char *path)
@@ -493,36 +558,93 @@ static int local_fsync(FsContext *ctx, int fd, int datasync)
     }
 }
 
-static int local_statfs(FsContext *s, const char *path, struct statfs *stbuf)
+static int local_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
 {
     char buffer[PATH_MAX];
-   return statfs(rpath(s, path, buffer), stbuf);
+    char *path = fs_path->data;
+
+    return statfs(rpath(s, path, buffer), stbuf);
 }
 
-static ssize_t local_lgetxattr(FsContext *ctx, const char *path,
+static ssize_t local_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
                                const char *name, void *value, size_t size)
 {
+    char *path = fs_path->data;
+
     return v9fs_get_xattr(ctx, path, name, value, size);
 }
 
-static ssize_t local_llistxattr(FsContext *ctx, const char *path,
+static ssize_t local_llistxattr(FsContext *ctx, V9fsPath *fs_path,
                                 void *value, size_t size)
 {
+    char *path = fs_path->data;
+
     return v9fs_list_xattr(ctx, path, value, size);
 }
 
-static int local_lsetxattr(FsContext *ctx, const char *path, const char *name,
+static int local_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
                            void *value, size_t size, int flags)
 {
+    char *path = fs_path->data;
+
     return v9fs_set_xattr(ctx, path, name, value, size, flags);
 }
 
-static int local_lremovexattr(FsContext *ctx,
-                              const char *path, const char *name)
+static int local_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
+                              const char *name)
 {
+    char *path = fs_path->data;
+
     return v9fs_remove_xattr(ctx, path, name);
 }
 
+static int local_name_to_path(FsContext *ctx, V9fsPath *dir_path,
+                              const char *name, V9fsPath *target)
+{
+    if (dir_path) {
+        v9fs_string_sprintf((V9fsString *)target, "%s/%s",
+                            dir_path->data, name);
+    } else {
+        v9fs_string_sprintf((V9fsString *)target, "%s", name);
+    }
+    /* Bump the size for including terminating NULL */
+    target->size++;
+    return 0;
+}
+
+static int local_renameat(FsContext *ctx, V9fsPath *olddir,
+                          const char *old_name, V9fsPath *newdir,
+                          const char *new_name)
+{
+    int ret;
+    V9fsString old_full_name, new_full_name;
+
+    v9fs_string_init(&old_full_name);
+    v9fs_string_init(&new_full_name);
+
+    v9fs_string_sprintf(&old_full_name, "%s/%s", olddir->data, old_name);
+    v9fs_string_sprintf(&new_full_name, "%s/%s", newdir->data, new_name);
+
+    ret = local_rename(ctx, old_full_name.data, new_full_name.data);
+    v9fs_string_free(&old_full_name);
+    v9fs_string_free(&new_full_name);
+    return ret;
+}
+
+static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
+                          const char *name, int flags)
+{
+    int ret;
+    V9fsString fullname;
+    char buffer[PATH_MAX];
+    v9fs_string_init(&fullname);
+
+    v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name);
+    ret = remove(rpath(ctx, fullname.data, buffer));
+    v9fs_string_free(&fullname);
+
+    return ret;
+}
 
 FileOperations local_ops = {
     .lstat = local_lstat,
@@ -555,4 +677,7 @@ FileOperations local_ops = {
     .llistxattr = local_llistxattr,
     .lsetxattr = local_lsetxattr,
     .lremovexattr = local_lremovexattr,
+    .name_to_path = local_name_to_path,
+    .renameat  = local_renameat,
+    .unlinkat = local_unlinkat,
 };
diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index 356bb3b..82f1db5 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -214,16 +214,48 @@ void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
     v9fs_string_sprintf(lhs, "%s", rhs->data);
 }
 
+void v9fs_path_init(V9fsPath *path)
+{
+    path->data = NULL;
+    path->size = 0;
+}
+
+void v9fs_path_free(V9fsPath *path)
+{
+    g_free(path->data);
+    path->data = NULL;
+    path->size = 0;
+}
+
+void v9fs_path_copy(V9fsPath *lhs, V9fsPath *rhs)
+{
+    v9fs_path_free(lhs);
+    lhs->data = g_malloc(rhs->size);
+    memcpy(lhs->data, rhs->data, rhs->size);
+    lhs->size = rhs->size;
+}
+
+int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath,
+                      const char *name, V9fsPath *path)
+{
+    int err;
+    err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
+    if (err < 0) {
+        err = -errno;
+    }
+    return err;
+}
+
 /*
  * Return TRUE if s1 is an ancestor of s2.
  *
  * E.g. "a/b" is an ancestor of "a/b/c" but not of "a/bc/d".
  * As a special case, We treat s1 as ancestor of s2 if they are same!
  */
-static int v9fs_path_is_ancestor(V9fsString *s1, V9fsString *s2)
+static int v9fs_path_is_ancestor(V9fsPath *s1, V9fsPath *s2)
 {
-    if (!strncmp(s1->data, s2->data, s1->size)) {
-        if (s2->data[s1->size] == '\0' || s2->data[s1->size] == '/') {
+    if (!strncmp(s1->data, s2->data, s1->size - 1)) {
+        if (s2->data[s1->size - 1] == '\0' || s2->data[s1->size - 1] == '/') {
             return 1;
         }
     }
@@ -368,7 +400,7 @@ static int free_fid(V9fsState *s, V9fsFidState *fidp)
     } else if (fidp->fid_type == P9_FID_XATTR) {
         retval = v9fs_xattr_fid_clunk(s, fidp);
     }
-    v9fs_string_free(&fidp->path);
+    v9fs_path_free(&fidp->path);
     g_free(fidp);
     return retval;
 }
@@ -484,14 +516,17 @@ void v9fs_reclaim_fd(V9fsState *s)
     }
 }
 
-static int v9fs_mark_fids_unreclaim(V9fsState *s, V9fsString *str)
+static int v9fs_mark_fids_unreclaim(V9fsState *s, V9fsPath *path)
 {
     int err;
     V9fsFidState *fidp, head_fid;
 
     head_fid.next = s->fid_list;
     for (fidp = s->fid_list; fidp; fidp = fidp->next) {
-        if (!strcmp(fidp->path.data, str->data)) {
+        if (fidp->path.size != path->size) {
+            continue;
+        }
+        if (!memcmp(fidp->path.data, path->data, path->size)) {
             /* Mark the fid non reclaimable. */
             fidp->flags |= FID_NON_RECLAIMABLE;
 
@@ -998,7 +1033,7 @@ static uint32_t stat_to_v9mode(const struct stat *stbuf)
     return mode;
 }
 
-static int stat_to_v9stat(V9fsState *s, V9fsString *name,
+static int stat_to_v9stat(V9fsState *s, V9fsPath *name,
                             const struct stat *stbuf,
                             V9fsStat *v9stat)
 {
@@ -1150,13 +1185,16 @@ static void print_sg(struct iovec *sg, int cnt)
     printf("}\n");
 }
 
-static void v9fs_fix_path(V9fsString *dst, V9fsString *src, int len)
+/* Will call this only for path name based fid */
+static void v9fs_fix_path(V9fsPath *dst, V9fsPath *src, int len)
 {
-    V9fsString str;
-    v9fs_string_init(&str);
-    v9fs_string_copy(&str, dst);
-    v9fs_string_sprintf(dst, "%s%s", src->data, str.data+len);
-    v9fs_string_free(&str);
+    V9fsPath str;
+    v9fs_path_init(&str);
+    v9fs_path_copy(&str, dst);
+    v9fs_string_sprintf((V9fsString *)dst, "%s%s", src->data, str.data+len);
+    v9fs_path_free(&str);
+    /* +1 to include terminating NULL */
+    dst->size++;
 }
 
 static void v9fs_version(void *opaque)
@@ -1202,7 +1240,12 @@ static void v9fs_attach(void *opaque)
         goto out_nofid;
     }
     fidp->uid = n_uname;
-    v9fs_string_sprintf(&fidp->path, "%s", "/");
+    err = v9fs_co_name_to_path(s, NULL, "/", &fidp->path);
+    if (err < 0) {
+        err = -EINVAL;
+        clunk_fid(s, fid);
+        goto out;
+    }
     err = fid_to_qid(s, fidp, &qid);
     if (err < 0) {
         err = -EINVAL;
@@ -1400,7 +1443,7 @@ static void v9fs_walk(void *opaque)
     int name_idx;
     V9fsQID *qids = NULL;
     int i, err = 0;
-    V9fsString path;
+    V9fsPath dpath, path;
     uint16_t nwnames;
     struct stat stbuf;
     size_t offset = 7;
@@ -1420,7 +1463,6 @@ static void v9fs_walk(void *opaque)
         for (i = 0; i < nwnames; i++) {
             offset += pdu_unmarshal(pdu, offset, "s", &wnames[i]);
         }
-
     } else if (nwnames > P9_MAXWELEM) {
         err = -EINVAL;
         goto out_nofid;
@@ -1430,22 +1472,29 @@ static void v9fs_walk(void *opaque)
         err = -ENOENT;
         goto out_nofid;
     }
+    v9fs_path_init(&dpath);
+    v9fs_path_init(&path);
+    /*
+     * Both dpath and path initially poin to fidp.
+     * Needed to handle request with nwnames == 0
+     */
+    v9fs_path_copy(&dpath, &fidp->path);
+    v9fs_path_copy(&path, &fidp->path);
+    for (name_idx = 0; name_idx < nwnames; name_idx++) {
+        err = v9fs_co_name_to_path(s, &dpath, wnames[name_idx].data, &path);
+        if (err < 0) {
+            goto out;
+        }
+        err = v9fs_co_lstat(s, &path, &stbuf);
+        if (err < 0) {
+            goto out;
+        }
+        stat_to_qid(&stbuf, &qids[name_idx]);
+        v9fs_path_copy(&dpath, &path);
+    }
     if (fid == newfid) {
         BUG_ON(fidp->fid_type != P9_FID_NONE);
-        v9fs_string_init(&path);
-        for (name_idx = 0; name_idx < nwnames; name_idx++) {
-            v9fs_string_sprintf(&path, "%s/%s",
-                                fidp->path.data, wnames[name_idx].data);
-            v9fs_string_copy(&fidp->path, &path);
-
-            err = v9fs_co_lstat(s, &fidp->path, &stbuf);
-            if (err < 0) {
-                v9fs_string_free(&path);
-                goto out;
-            }
-            stat_to_qid(&stbuf, &qids[name_idx]);
-        }
-        v9fs_string_free(&path);
+        v9fs_path_copy(&fidp->path, &path);
     } else {
         newfidp = alloc_fid(s, newfid);
         if (newfidp == NULL) {
@@ -1453,21 +1502,7 @@ static void v9fs_walk(void *opaque)
             goto out;
         }
         newfidp->uid = fidp->uid;
-        v9fs_string_init(&path);
-        v9fs_string_copy(&newfidp->path, &fidp->path);
-        for (name_idx = 0; name_idx < nwnames; name_idx++) {
-            v9fs_string_sprintf(&path, "%s/%s", newfidp->path.data,
-                                wnames[name_idx].data);
-            v9fs_string_copy(&newfidp->path, &path);
-            err = v9fs_co_lstat(s, &newfidp->path, &stbuf);
-            if (err < 0) {
-                clunk_fid(s, newfidp->fid);
-                v9fs_string_free(&path);
-                goto out;
-            }
-            stat_to_qid(&stbuf, &qids[name_idx]);
-        }
-        v9fs_string_free(&path);
+        v9fs_path_copy(&newfidp->path, &path);
     }
     err = v9fs_walk_marshal(pdu, nwnames, qids);
 out:
@@ -1475,6 +1510,8 @@ out:
     if (newfidp) {
         put_fid(s, newfidp);
     }
+    v9fs_path_free(&dpath);
+    v9fs_path_free(&path);
 out_nofid:
     complete_pdu(s, pdu, err);
     if (nwnames && nwnames <= P9_MAXWELEM) {
@@ -1484,9 +1521,10 @@ out_nofid:
         g_free(wnames);
         g_free(qids);
     }
+    return;
 }
 
-static int32_t get_iounit(V9fsState *s, V9fsString *name)
+static int32_t get_iounit(V9fsState *s, V9fsPath *path)
 {
     struct statfs stbuf;
     int32_t iounit = 0;
@@ -1495,7 +1533,7 @@ static int32_t get_iounit(V9fsState *s, V9fsString *name)
      * iounit should be multiples of f_bsize (host filesystem block size
      * and as well as less than (client msize - P9_IOHDRSZ))
      */
-    if (!v9fs_co_statfs(s, name, &stbuf)) {
+    if (!v9fs_co_statfs(s, path, &stbuf)) {
         iounit = stbuf.f_bsize;
         iounit *= (s->msize - P9_IOHDRSZ)/stbuf.f_bsize;
     }
@@ -1705,7 +1743,7 @@ static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu,
 static int v9fs_do_readdir_with_stat(V9fsState *s, V9fsPDU *pdu,
                                      V9fsFidState *fidp, int32_t max_count)
 {
-    V9fsString name;
+    V9fsPath path;
     V9fsStat v9stat;
     int len, err = 0;
     int32_t count = 0;
@@ -1722,17 +1760,20 @@ static int v9fs_do_readdir_with_stat(V9fsState *s, V9fsPDU *pdu,
     dent = g_malloc(sizeof(struct dirent));
 
     while (1) {
-        v9fs_string_init(&name);
+        v9fs_path_init(&path);
         err = v9fs_co_readdir_r(s, fidp, dent, &result);
         if (err || !result) {
             break;
         }
-        v9fs_string_sprintf(&name, "%s/%s", fidp->path.data, dent->d_name);
-        err = v9fs_co_lstat(s, &name, &stbuf);
+        err = v9fs_co_name_to_path(s, &fidp->path, dent->d_name, &path);
         if (err < 0) {
             goto out;
         }
-        err = stat_to_v9stat(s, &name, &stbuf, &v9stat);
+        err = v9fs_co_lstat(s, &path, &stbuf);
+        if (err < 0) {
+            goto out;
+        }
+        err = stat_to_v9stat(s, &path, &stbuf, &v9stat);
         if (err < 0) {
             goto out;
         }
@@ -1742,18 +1783,18 @@ static int v9fs_do_readdir_with_stat(V9fsState *s, V9fsPDU *pdu,
             /* Ran out of buffer. Set dir back to old position and return */
             v9fs_co_seekdir(s, fidp, saved_dir_pos);
             v9fs_stat_free(&v9stat);
-            v9fs_string_free(&name);
+            v9fs_path_free(&path);
             g_free(dent);
             return count;
         }
         count += len;
         v9fs_stat_free(&v9stat);
-        v9fs_string_free(&name);
+        v9fs_path_free(&path);
         saved_dir_pos = dent->d_off;
     }
 out:
     g_free(dent);
-    v9fs_string_free(&name);
+    v9fs_path_free(&path);
     if (err < 0) {
         return err;
     }
@@ -2062,14 +2103,14 @@ static void v9fs_create(void *opaque)
     V9fsQID qid;
     int32_t perm;
     int8_t mode;
+    V9fsPath path;
     struct stat stbuf;
     V9fsString name;
     V9fsString extension;
-    V9fsString fullname;
     int iounit;
     V9fsPDU *pdu = opaque;
 
-    v9fs_string_init(&fullname);
+    v9fs_path_init(&path);
 
     pdu_unmarshal(pdu, offset, "dsdbs", &fid, &name,
                   &perm, &mode, &extension);
@@ -2079,23 +2120,17 @@ static void v9fs_create(void *opaque)
         err = -EINVAL;
         goto out_nofid;
     }
-
-    v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
-    err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
-    if (!err) {
-        err = -EEXIST;
-        goto out;
-    } else if (err != -ENOENT) {
-        goto out;
-    }
     if (perm & P9_STAT_MODE_DIR) {
         err = v9fs_co_mkdir(pdu->s, fidp, &name, perm & 0777,
                             fidp->uid, -1, &stbuf);
         if (err < 0) {
             goto out;
         }
-        v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
-        v9fs_string_copy(&fidp->path, &fullname);
+        err = v9fs_co_name_to_path(pdu->s, &fidp->path, name.data, &path);
+        if (err < 0) {
+            goto out;
+        }
+        v9fs_path_copy(&fidp->path, &path);
         err = v9fs_co_opendir(pdu->s, fidp);
         if (err < 0) {
             goto out;
@@ -2107,23 +2142,29 @@ static void v9fs_create(void *opaque)
         if (err < 0) {
             goto out;
         }
-        v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
-        v9fs_string_copy(&fidp->path, &fullname);
+        err = v9fs_co_name_to_path(pdu->s, &fidp->path, name.data, &path);
+        if (err < 0) {
+            goto out;
+        }
+        v9fs_path_copy(&fidp->path, &path);
     } else if (perm & P9_STAT_MODE_LINK) {
-        int32_t nfid = atoi(extension.data);
-        V9fsFidState *nfidp = get_fid(pdu->s, nfid);
-        if (nfidp == NULL) {
+        int32_t ofid = atoi(extension.data);
+        V9fsFidState *ofidp = get_fid(pdu->s, ofid);
+        if (ofidp == NULL) {
             err = -EINVAL;
             goto out;
         }
-        v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
-        err = v9fs_co_link(pdu->s, &nfidp->path, &fullname);
-        put_fid(pdu->s, nfidp);
+        err = v9fs_co_link(pdu->s, ofidp, fidp, &name);
+        put_fid(pdu->s, ofidp);
+        if (err < 0) {
+            goto out;
+        }
+        err = v9fs_co_name_to_path(pdu->s, &fidp->path, name.data, &path);
         if (err < 0) {
+            fidp->fid_type = P9_FID_NONE;
             goto out;
         }
-        v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
-        v9fs_string_copy(&fidp->path, &fullname);
+        v9fs_path_copy(&fidp->path, &path);
         err = v9fs_co_lstat(pdu->s, &fidp->path, &stbuf);
         if (err < 0) {
             fidp->fid_type = P9_FID_NONE;
@@ -2157,24 +2198,33 @@ static void v9fs_create(void *opaque)
         if (err < 0) {
             goto out;
         }
-        v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
-        v9fs_string_copy(&fidp->path, &fullname);
+        err = v9fs_co_name_to_path(pdu->s, &fidp->path, name.data, &path);
+        if (err < 0) {
+            goto out;
+        }
+        v9fs_path_copy(&fidp->path, &path);
     } else if (perm & P9_STAT_MODE_NAMED_PIPE) {
         err = v9fs_co_mknod(pdu->s, fidp, &name, fidp->uid, -1,
                             0, S_IFIFO | (perm & 0777), &stbuf);
         if (err < 0) {
             goto out;
         }
-        v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
-        v9fs_string_copy(&fidp->path, &fullname);
+        err = v9fs_co_name_to_path(pdu->s, &fidp->path, name.data, &path);
+        if (err < 0) {
+            goto out;
+        }
+        v9fs_path_copy(&fidp->path, &path);
     } else if (perm & P9_STAT_MODE_SOCKET) {
         err = v9fs_co_mknod(pdu->s, fidp, &name, fidp->uid, -1,
                             0, S_IFSOCK | (perm & 0777), &stbuf);
         if (err < 0) {
             goto out;
         }
-        v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
-        v9fs_string_copy(&fidp->path, &fullname);
+        err = v9fs_co_name_to_path(pdu->s, &fidp->path, name.data, &path);
+        if (err < 0) {
+            goto out;
+        }
+        v9fs_path_copy(&fidp->path, &path);
     } else {
         err = v9fs_co_open2(pdu->s, fidp, &name, -1,
                             omode_to_uflags(mode)|O_CREAT, perm, &stbuf);
@@ -2201,7 +2251,7 @@ out_nofid:
    complete_pdu(pdu->s, pdu, err);
    v9fs_string_free(&name);
    v9fs_string_free(&extension);
-   v9fs_string_free(&fullname);
+   v9fs_path_free(&path);
 }
 
 static void v9fs_symlink(void *opaque)
@@ -2254,12 +2304,10 @@ static void v9fs_link(void *opaque)
     V9fsState *s = pdu->s;
     int32_t dfid, oldfid;
     V9fsFidState *dfidp, *oldfidp;
-    V9fsString name, fullname;
+    V9fsString name;;
     size_t offset = 7;
     int err = 0;
 
-    v9fs_string_init(&fullname);
-
     pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
 
     dfidp = get_fid(s, dfid);
@@ -2273,14 +2321,10 @@ static void v9fs_link(void *opaque)
         err = -ENOENT;
         goto out;
     }
-
-    v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name.data);
-    err = v9fs_co_link(s, &oldfidp->path, &fullname);
+    err = v9fs_co_link(s, oldfidp, dfidp, &name);
     if (!err) {
         err = offset;
     }
-    v9fs_string_free(&fullname);
-
 out:
     put_fid(s, dfidp);
 out_nofid:
@@ -2329,9 +2373,9 @@ static void v9fs_unlinkat(void *opaque)
     V9fsString name;
     int32_t dfid, flags;
     size_t offset = 7;
+    V9fsPath path;
     V9fsFidState *dfidp;
     V9fsPDU *pdu = opaque;
-    V9fsString full_name;
 
     pdu_unmarshal(pdu, offset, "dsd", &dfid, &name, &flags);
 
@@ -2340,36 +2384,44 @@ static void v9fs_unlinkat(void *opaque)
         err = -EINVAL;
         goto out_nofid;
     }
-    v9fs_string_init(&full_name);
-    v9fs_string_sprintf(&full_name, "%s/%s", dfidp->path.data, name.data);
     /*
      * IF the file is unlinked, we cannot reopen
      * the file later. So don't reclaim fd
      */
-    err = v9fs_mark_fids_unreclaim(pdu->s, &full_name);
+    v9fs_path_init(&path);
+    err = v9fs_co_name_to_path(pdu->s, &dfidp->path, name.data, &path);
+    if (err < 0) {
+        goto out_err;
+    }
+    err = v9fs_mark_fids_unreclaim(pdu->s, &path);
     if (err < 0) {
         goto out_err;
     }
-    err = v9fs_co_remove(pdu->s, &full_name);
+    err = v9fs_co_unlinkat(pdu->s, &dfidp->path, &name, flags);
     if (!err) {
         err = offset;
     }
 out_err:
     put_fid(pdu->s, dfidp);
-    v9fs_string_free(&full_name);
+    v9fs_path_free(&path);
 out_nofid:
     complete_pdu(pdu->s, pdu, err);
     v9fs_string_free(&name);
 }
 
+
+/* Only works with path name based fid */
 static int v9fs_complete_rename(V9fsState *s, V9fsFidState *fidp,
                                 int32_t newdirfid, V9fsString *name)
 {
     char *end;
     int err = 0;
+    V9fsPath new_path;
+    V9fsFidState *tfidp;
     V9fsFidState *dirfidp = NULL;
     char *old_name, *new_name;
 
+    v9fs_path_init(&new_path);
     if (newdirfid != -1) {
         dirfidp = get_fid(s, newdirfid);
         if (dirfidp == NULL) {
@@ -2377,12 +2429,7 @@ static int v9fs_complete_rename(V9fsState *s, V9fsFidState *fidp,
             goto out_nofid;
         }
         BUG_ON(dirfidp->fid_type != P9_FID_NONE);
-
-        new_name = g_malloc0(dirfidp->path.size + name->size + 2);
-
-        strcpy(new_name, dirfidp->path.data);
-        strcat(new_name, "/");
-        strcat(new_name + dirfidp->path.size, name->data);
+        v9fs_co_name_to_path(s, &dirfidp->path, name->data, &new_path);
     } else {
         old_name = fidp->path.data;
         end = strrchr(old_name, '/');
@@ -2392,44 +2439,30 @@ static int v9fs_complete_rename(V9fsState *s, V9fsFidState *fidp,
             end = old_name;
         }
         new_name = g_malloc0(end - old_name + name->size + 1);
-
         strncat(new_name, old_name, end - old_name);
         strncat(new_name + (end - old_name), name->data, name->size);
+        v9fs_co_name_to_path(s, NULL, new_name, &new_path);
+        g_free(new_name);
     }
-
-    v9fs_string_free(name);
-    name->data = new_name;
-    name->size = strlen(new_name);
-
-    if (strcmp(new_name, fidp->path.data) != 0) {
-        err = v9fs_co_rename(s, &fidp->path, name);
-        if (err < 0) {
-            goto out;
-        }
-        V9fsFidState *tfidp;
-        /*
-         * Fixup fid's pointing to the old name to
-         * start pointing to the new name
-         */
-        for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
-            if (fidp == tfidp) {
-                /*
-                 * we replace name of this fid towards the end
-                 * so that our below strcmp will work
-                 */
-                continue;
-            }
-            if (v9fs_path_is_ancestor(&fidp->path, &tfidp->path)) {
-                /* replace the name */
-                v9fs_fix_path(&tfidp->path, name, strlen(fidp->path.data));
-            }
+    err = v9fs_co_rename(s, &fidp->path, &new_path);
+    if (err < 0) {
+        goto out;
+    }
+    /*
+     * Fixup fid's pointing to the old name to
+     * start pointing to the new name
+     */
+    for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
+        if (v9fs_path_is_ancestor(&fidp->path, &tfidp->path)) {
+            /* replace the name */
+            v9fs_fix_path(&tfidp->path, &new_path, strlen(fidp->path.data));
         }
-        v9fs_string_copy(&fidp->path, name);
     }
 out:
     if (dirfidp) {
         put_fid(s, dirfidp);
     }
+    v9fs_path_free(&new_path);
 out_nofid:
     return err;
 }
@@ -2466,12 +2499,38 @@ out_nofid:
     v9fs_string_free(&name);
 }
 
+static void v9fs_fix_fid_paths(V9fsState *s, V9fsPath *olddir,
+                               V9fsString *old_name, V9fsPath *newdir,
+                               V9fsString *new_name)
+{
+    V9fsFidState *tfidp;
+    V9fsPath oldpath, newpath;
+
+
+    v9fs_path_init(&oldpath);
+    v9fs_path_init(&newpath);
+    v9fs_co_name_to_path(s, olddir, old_name->data, &oldpath);
+    v9fs_co_name_to_path(s, newdir, new_name->data, &newpath);
+
+    /*
+     * Fixup fid's pointing to the old name to
+     * start pointing to the new name
+     */
+    for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
+        if (v9fs_path_is_ancestor(&oldpath, &tfidp->path)) {
+            /* replace the name */
+            v9fs_fix_path(&tfidp->path, &newpath, strlen(oldpath.data));
+        }
+    }
+    v9fs_path_free(&oldpath);
+    v9fs_path_free(&newpath);
+}
+
 static int v9fs_complete_renameat(V9fsState *s, int32_t olddirfid,
                                   V9fsString *old_name, int32_t newdirfid,
                                   V9fsString *new_name)
 {
     int err = 0;
-    V9fsString old_full_name, new_full_name;
     V9fsFidState *newdirfidp = NULL, *olddirfidp = NULL;
 
     olddirfidp = get_fid(s, olddirfid);
@@ -2479,41 +2538,24 @@ static int v9fs_complete_renameat(V9fsState *s, int32_t olddirfid,
         err = -ENOENT;
         goto out;
     }
-    v9fs_string_init(&old_full_name);
-    v9fs_string_init(&new_full_name);
-
-    v9fs_string_sprintf(&old_full_name, "%s/%s",
-                        olddirfidp->path.data, old_name->data);
     if (newdirfid != -1) {
         newdirfidp = get_fid(s, newdirfid);
         if (newdirfidp == NULL) {
             err = -ENOENT;
             goto out;
         }
-        v9fs_string_sprintf(&new_full_name, "%s/%s",
-                            newdirfidp->path.data, new_name->data);
     } else {
-        v9fs_string_sprintf(&new_full_name, "%s/%s",
-                            olddirfidp->path.data, new_name->data);
+        newdirfidp = get_fid(s, olddirfid);
     }
 
-    if (strcmp(old_full_name.data, new_full_name.data) != 0) {
-        V9fsFidState *tfidp;
-        err = v9fs_co_rename(s, &old_full_name, &new_full_name);
-        if (err < 0) {
-            goto out;
-        }
-        /*
-         * Fixup fid's pointing to the old name to
-         * start pointing to the new name
-         */
-        for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
-            if (v9fs_path_is_ancestor(&old_full_name, &tfidp->path)) {
-                /* replace the name */
-                v9fs_fix_path(&tfidp->path, &new_full_name, old_full_name.size);
-            }
-        }
+    err = v9fs_co_renameat(s, &olddirfidp->path, old_name,
+                           &newdirfidp->path, new_name);
+    if (err < 0) {
+        goto out;
     }
+    /* Only for path based fid  we need to do the below fixup */
+    v9fs_fix_fid_paths(s, &olddirfidp->path, old_name,
+                       &newdirfidp->path, new_name);
 out:
     if (olddirfidp) {
         put_fid(s, olddirfidp);
@@ -2521,8 +2563,6 @@ out:
     if (newdirfidp) {
         put_fid(s, newdirfidp);
     }
-    v9fs_string_free(&old_full_name);
-    v9fs_string_free(&new_full_name);
     return err;
 }
 
@@ -2899,7 +2939,7 @@ static void v9fs_xattrwalk(void *opaque)
         err = -EINVAL;
         goto out;
     }
-    v9fs_string_copy(&xattr_fidp->path, &file_fidp->path);
+    v9fs_path_copy(&xattr_fidp->path, &file_fidp->path);
     if (name.data[0] == 0) {
         /*
          * listxattr request. Get the size first
diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
index 4238a76..8c7c3f0 100644
--- a/hw/9pfs/virtio-9p.h
+++ b/hw/9pfs/virtio-9p.h
@@ -206,7 +206,7 @@ struct V9fsFidState
 {
     int fid_type;
     int32_t fid;
-    V9fsString path;
+    V9fsPath path;
     union {
         int fd;
         DIR *dir;
@@ -396,4 +396,9 @@ extern void v9fs_string_free(V9fsString *str);
 extern void v9fs_string_null(V9fsString *str);
 extern void v9fs_string_sprintf(V9fsString *str, const char *fmt, ...);
 extern void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs);
+extern void v9fs_path_init(V9fsPath *path);
+extern void v9fs_path_free(V9fsPath *path);
+extern void v9fs_path_copy(V9fsPath *lhs, V9fsPath *rhs);
+extern int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath,
+                             const char *name, V9fsPath *path);
 #endif
commit 02cb7f3a256517cbf3136caff2863fbafc57b540
Author: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Date:   Tue May 24 15:10:56 2011 +0530

    hw/9pfs: Use read-write lock for protecting fid path.
    
    On rename we take the write lock and this ensure path
    doesn't change as we operate on them.
    
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>

diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c
index f17f927..c9a88ec 100644
--- a/hw/9pfs/codir.c
+++ b/hw/9pfs/codir.c
@@ -65,22 +65,34 @@ void v9fs_co_rewinddir(V9fsState *s, V9fsFidState *fidp)
         });
 }
 
-int v9fs_co_mkdir(V9fsState *s, char *name, mode_t mode, uid_t uid, gid_t gid)
+int v9fs_co_mkdir(V9fsState *s, V9fsFidState *fidp, V9fsString *name,
+                  mode_t mode, uid_t uid, gid_t gid, struct stat *stbuf)
 {
     int err;
     FsCred cred;
+    V9fsString fullname;
 
     cred_init(&cred);
     cred.fc_mode = mode;
     cred.fc_uid = uid;
     cred.fc_gid = gid;
+    v9fs_string_init(&fullname);
+    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name->data);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->mkdir(&s->ctx, name, &cred);
+            err = s->ops->mkdir(&s->ctx, fullname.data, &cred);
             if (err < 0) {
                 err = -errno;
+            } else {
+                err = s->ops->lstat(&s->ctx, fullname.data, stbuf);
+                if (err < 0) {
+                    err = -errno;
+                }
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_string_free(&fullname);
     return err;
 }
 
@@ -88,6 +100,7 @@ int v9fs_co_opendir(V9fsState *s, V9fsFidState *fidp)
 {
     int err;
 
+    qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
             fidp->fs.dir = s->ops->opendir(&s->ctx, fidp->path.data);
@@ -97,6 +110,7 @@ int v9fs_co_opendir(V9fsState *s, V9fsFidState *fidp)
                 err = 0;
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
     if (!err) {
         total_open_fd++;
         if (total_open_fd > open_fd_hw) {
diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c
index 0caf1e3..cc62846 100644
--- a/hw/9pfs/cofile.c
+++ b/hw/9pfs/cofile.c
@@ -21,6 +21,7 @@ int v9fs_co_lstat(V9fsState *s, V9fsString *path, struct stat *stbuf)
 {
     int err;
 
+    qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
             err = s->ops->lstat(&s->ctx, path->data, stbuf);
@@ -28,6 +29,7 @@ int v9fs_co_lstat(V9fsState *s, V9fsString *path, struct stat *stbuf)
                 err = -errno;
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
     return err;
 }
 
@@ -49,6 +51,7 @@ int v9fs_co_open(V9fsState *s, V9fsFidState *fidp, int flags)
 {
     int err;
 
+    qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
             fidp->fs.fd = s->ops->open(&s->ctx, fidp->path.data, flags);
@@ -58,6 +61,7 @@ int v9fs_co_open(V9fsState *s, V9fsFidState *fidp, int flags)
                 err = 0;
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
     if (!err) {
         total_open_fd++;
         if (total_open_fd > open_fd_hw) {
@@ -67,30 +71,48 @@ int v9fs_co_open(V9fsState *s, V9fsFidState *fidp, int flags)
     return err;
 }
 
-int v9fs_co_open2(V9fsState *s, V9fsFidState *fidp, char *fullname, gid_t gid,
-                  int flags, int mode)
+int v9fs_co_open2(V9fsState *s, V9fsFidState *fidp, V9fsString *name, gid_t gid,
+                  int flags, int mode, struct stat *stbuf)
 {
     int err;
     FsCred cred;
+    V9fsString fullname;
 
     cred_init(&cred);
     cred.fc_mode = mode & 07777;
     cred.fc_uid = fidp->uid;
     cred.fc_gid = gid;
+    v9fs_string_init(&fullname);
+    /*
+     * Hold the directory fid lock so that directory path name
+     * don't change. Read lock is fine because this fid cannot
+     * be used by any other operation.
+     */
+    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name->data);
     v9fs_co_run_in_worker(
         {
-            fidp->fs.fd = s->ops->open2(&s->ctx, fullname, flags, &cred);
-            err = 0;
+            fidp->fs.fd = s->ops->open2(&s->ctx, fullname.data, flags, &cred);
             if (fidp->fs.fd == -1) {
                 err = -errno;
+            } else {
+                err = s->ops->lstat(&s->ctx, fullname.data, stbuf);
+                if (err < 0) {
+                    err = -errno;
+                    err = s->ops->close(&s->ctx, fidp->fs.fd);
+                } else {
+                    v9fs_string_copy(&fidp->path, &fullname);
+                }
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
     if (!err) {
         total_open_fd++;
         if (total_open_fd > open_fd_hw) {
             v9fs_reclaim_fd(s);
         }
     }
+    v9fs_string_free(&fullname);
     return err;
 }
 
@@ -131,6 +153,7 @@ int v9fs_co_link(V9fsState *s, V9fsString *oldpath, V9fsString *newpath)
 {
     int err;
 
+    qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
             err = s->ops->link(&s->ctx, oldpath->data, newpath->data);
@@ -138,6 +161,7 @@ int v9fs_co_link(V9fsState *s, V9fsString *oldpath, V9fsString *newpath)
                 err = -errno;
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
     return err;
 }
 
diff --git a/hw/9pfs/cofs.c b/hw/9pfs/cofs.c
index a78fccb..98860f9 100644
--- a/hw/9pfs/cofs.c
+++ b/hw/9pfs/cofs.c
@@ -23,6 +23,8 @@ int v9fs_co_readlink(V9fsState *s, V9fsString *path, V9fsString *buf)
     ssize_t len;
 
     buf->data = g_malloc(PATH_MAX);
+    qemu_co_rwlock_rdlock(&s->rename_lock);
+
     v9fs_co_run_in_worker(
         {
             len = s->ops->readlink(&s->ctx, path->data,
@@ -35,6 +37,7 @@ int v9fs_co_readlink(V9fsState *s, V9fsString *path, V9fsString *buf)
                 err = -errno;
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
     if (err) {
         g_free(buf->data);
         buf->data = NULL;
@@ -47,6 +50,7 @@ int v9fs_co_statfs(V9fsState *s, V9fsString *path, struct statfs *stbuf)
 {
     int err;
 
+    qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
             err = s->ops->statfs(&s->ctx, path->data, stbuf);
@@ -54,6 +58,7 @@ int v9fs_co_statfs(V9fsState *s, V9fsString *path, struct statfs *stbuf)
                 err = -errno;
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
     return err;
 }
 
@@ -64,6 +69,7 @@ int v9fs_co_chmod(V9fsState *s, V9fsString *path, mode_t mode)
 
     cred_init(&cred);
     cred.fc_mode = mode;
+    qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
             err = s->ops->chmod(&s->ctx, path->data, &cred);
@@ -71,6 +77,7 @@ int v9fs_co_chmod(V9fsState *s, V9fsString *path, mode_t mode)
                 err = -errno;
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
     return err;
 }
 
@@ -79,6 +86,7 @@ int v9fs_co_utimensat(V9fsState *s, V9fsString *path,
 {
     int err;
 
+    qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
             err = s->ops->utimensat(&s->ctx, path->data, times);
@@ -86,6 +94,7 @@ int v9fs_co_utimensat(V9fsState *s, V9fsString *path,
                 err = -errno;
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
     return err;
 }
 
@@ -97,6 +106,7 @@ int v9fs_co_chown(V9fsState *s, V9fsString *path, uid_t uid, gid_t gid)
     cred_init(&cred);
     cred.fc_uid = uid;
     cred.fc_gid = gid;
+    qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
             err = s->ops->chown(&s->ctx, path->data, &cred);
@@ -104,6 +114,7 @@ int v9fs_co_chown(V9fsState *s, V9fsString *path, uid_t uid, gid_t gid)
                 err = -errno;
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
     return err;
 }
 
@@ -111,6 +122,7 @@ int v9fs_co_truncate(V9fsState *s, V9fsString *path, off_t size)
 {
     int err;
 
+    qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
             err = s->ops->truncate(&s->ctx, path->data, size);
@@ -118,27 +130,39 @@ int v9fs_co_truncate(V9fsState *s, V9fsString *path, off_t size)
                 err = -errno;
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
     return err;
 }
 
-int v9fs_co_mknod(V9fsState *s, V9fsString *path, uid_t uid,
-                  gid_t gid, dev_t dev, mode_t mode)
+int v9fs_co_mknod(V9fsState *s, V9fsFidState *fidp, V9fsString *name, uid_t uid,
+                  gid_t gid, dev_t dev, mode_t mode, struct stat *stbuf)
 {
     int err;
     FsCred cred;
+    V9fsString fullname;
 
     cred_init(&cred);
     cred.fc_uid  = uid;
     cred.fc_gid  = gid;
     cred.fc_mode = mode;
     cred.fc_rdev = dev;
+    v9fs_string_init(&fullname);
+    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name->data);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->mknod(&s->ctx, path->data, &cred);
+            err = s->ops->mknod(&s->ctx, fullname.data, &cred);
             if (err < 0) {
                 err = -errno;
+            } else {
+                err = s->ops->lstat(&s->ctx, fullname.data, stbuf);
+                if (err < 0) {
+                    err = -errno;
+                }
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_string_free(&fullname);
     return err;
 }
 
@@ -146,6 +170,7 @@ int v9fs_co_remove(V9fsState *s, V9fsString *path)
 {
     int err;
 
+    qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
             err = s->ops->remove(&s->ctx, path->data);
@@ -153,6 +178,7 @@ int v9fs_co_remove(V9fsState *s, V9fsString *path)
                 err = -errno;
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
     return err;
 }
 
@@ -170,22 +196,34 @@ int v9fs_co_rename(V9fsState *s, V9fsString *oldpath, V9fsString *newpath)
     return err;
 }
 
-int v9fs_co_symlink(V9fsState *s, V9fsFidState *fidp,
-                    const char *oldpath, const char *newpath, gid_t gid)
+int v9fs_co_symlink(V9fsState *s, V9fsFidState *dfidp, V9fsString *name,
+                    const char *oldpath, gid_t gid, struct stat *stbuf)
 {
     int err;
     FsCred cred;
+    V9fsString fullname;
+
 
     cred_init(&cred);
-    cred.fc_uid = fidp->uid;
+    cred.fc_uid = dfidp->uid;
     cred.fc_gid = gid;
     cred.fc_mode = 0777;
+    v9fs_string_init(&fullname);
+    qemu_co_rwlock_rdlock(&s->rename_lock);
+    v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name->data);
     v9fs_co_run_in_worker(
         {
-            err = s->ops->symlink(&s->ctx, oldpath, newpath, &cred);
+            err = s->ops->symlink(&s->ctx, oldpath, fullname.data, &cred);
             if (err < 0) {
                 err = -errno;
+            } else {
+                err = s->ops->lstat(&s->ctx, fullname.data, stbuf);
+                if (err < 0) {
+                    err = -errno;
+                }
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
+    v9fs_string_free(&fullname);
     return err;
 }
diff --git a/hw/9pfs/coxattr.c b/hw/9pfs/coxattr.c
index a289389..7b93c8f 100644
--- a/hw/9pfs/coxattr.c
+++ b/hw/9pfs/coxattr.c
@@ -21,6 +21,7 @@ int v9fs_co_llistxattr(V9fsState *s, V9fsString *path, void *value, size_t size)
 {
     int err;
 
+    qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
             err = s->ops->llistxattr(&s->ctx, path->data, value, size);
@@ -28,6 +29,7 @@ int v9fs_co_llistxattr(V9fsState *s, V9fsString *path, void *value, size_t size)
                 err = -errno;
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
     return err;
 }
 
@@ -37,6 +39,7 @@ int v9fs_co_lgetxattr(V9fsState *s, V9fsString *path,
 {
     int err;
 
+    qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
             err = s->ops->lgetxattr(&s->ctx, path->data,
@@ -46,6 +49,7 @@ int v9fs_co_lgetxattr(V9fsState *s, V9fsString *path,
                 err = -errno;
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
     return err;
 }
 
@@ -55,6 +59,7 @@ int v9fs_co_lsetxattr(V9fsState *s, V9fsString *path,
 {
     int err;
 
+    qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
             err = s->ops->lsetxattr(&s->ctx, path->data,
@@ -64,6 +69,7 @@ int v9fs_co_lsetxattr(V9fsState *s, V9fsString *path,
                 err = -errno;
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
     return err;
 }
 
@@ -72,6 +78,7 @@ int v9fs_co_lremovexattr(V9fsState *s, V9fsString *path,
 {
     int err;
 
+    qemu_co_rwlock_rdlock(&s->rename_lock);
     v9fs_co_run_in_worker(
         {
             err = s->ops->lremovexattr(&s->ctx, path->data,
@@ -80,5 +87,6 @@ int v9fs_co_lremovexattr(V9fsState *s, V9fsString *path,
                 err = -errno;
             }
         });
+    qemu_co_rwlock_unlock(&s->rename_lock);
     return err;
 }
diff --git a/hw/9pfs/virtio-9p-coth.h b/hw/9pfs/virtio-9p-coth.h
index b7be9b5..e5f46c5 100644
--- a/hw/9pfs/virtio-9p-coth.h
+++ b/hw/9pfs/virtio-9p-coth.h
@@ -71,23 +71,25 @@ extern int v9fs_co_truncate(V9fsState *, V9fsString *, off_t);
 extern int v9fs_co_llistxattr(V9fsState *, V9fsString *, void *, size_t);
 extern int v9fs_co_lgetxattr(V9fsState *, V9fsString *,
                              V9fsString *, void *, size_t);
-extern int v9fs_co_mknod(V9fsState *, V9fsString *, uid_t,
-                         gid_t, dev_t, mode_t);
-extern int v9fs_co_mkdir(V9fsState *, char *, mode_t, uid_t, gid_t);
+extern int v9fs_co_mknod(V9fsState *, V9fsFidState *, V9fsString *, uid_t,
+                         gid_t, dev_t, mode_t, struct stat *);
+extern int v9fs_co_mkdir(V9fsState *, V9fsFidState *, V9fsString *,
+                         mode_t, uid_t, gid_t, struct stat *);
 extern int v9fs_co_remove(V9fsState *, V9fsString *);
 extern int v9fs_co_rename(V9fsState *, V9fsString *, V9fsString *);
 extern int v9fs_co_fstat(V9fsState *, int, struct stat *);
 extern int v9fs_co_opendir(V9fsState *, V9fsFidState *);
 extern int v9fs_co_open(V9fsState *, V9fsFidState *, int);
-extern int v9fs_co_open2(V9fsState *, V9fsFidState *, char *, gid_t, int, int);
+extern int v9fs_co_open2(V9fsState *, V9fsFidState *, V9fsString *,
+                         gid_t, int, int, struct stat *);
 extern int v9fs_co_lsetxattr(V9fsState *, V9fsString *, V9fsString *,
                              void *, size_t, int);
 extern int v9fs_co_lremovexattr(V9fsState *, V9fsString *, V9fsString *);
 extern int v9fs_co_closedir(V9fsState *, DIR *);
 extern int v9fs_co_close(V9fsState *, int);
 extern int v9fs_co_fsync(V9fsState *, V9fsFidState *, int);
-extern int v9fs_co_symlink(V9fsState *, V9fsFidState *, const char *,
-                           const char *, gid_t);
+extern int v9fs_co_symlink(V9fsState *, V9fsFidState *, V9fsString *,
+                           const char *, gid_t, struct stat *);
 extern int v9fs_co_link(V9fsState *, V9fsString *, V9fsString *);
 extern int v9fs_co_pwritev(V9fsState *, V9fsFidState *,
                            struct iovec *, int, int64_t);
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index 97f2da5..eea70cb 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -131,6 +131,7 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
                         s->tag_len;
     s->vdev.get_config = virtio_9p_get_config;
     s->fid_list = NULL;
+    qemu_co_rwlock_init(&s->rename_lock);
 
     if (v9fs_init_worker_threads() < 0) {
         fprintf(stderr, "worker thread initialization failed\n");
diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index dc3e32b..356bb3b 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -1582,7 +1582,6 @@ static void v9fs_lcreate(void *opaque)
     gid_t gid;
     ssize_t err = 0;
     ssize_t offset = 7;
-    V9fsString fullname;
     V9fsString name;
     V9fsFidState *fidp;
     struct stat stbuf;
@@ -1590,7 +1589,6 @@ static void v9fs_lcreate(void *opaque)
     int32_t iounit;
     V9fsPDU *pdu = opaque;
 
-    v9fs_string_init(&fullname);
     pdu_unmarshal(pdu, offset, "dsddd", &dfid, &name, &flags,
                   &mode, &gid);
 
@@ -1599,12 +1597,12 @@ static void v9fs_lcreate(void *opaque)
         err = -ENOENT;
         goto out_nofid;
     }
-    v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
 
     /* Ignore direct disk access hint until the server supports it. */
     flags &= ~O_DIRECT;
 
-    err = v9fs_co_open2(pdu->s, fidp, fullname.data, gid, flags, mode);
+    err = v9fs_co_open2(pdu->s, fidp, &name, gid,
+                        flags | O_CREAT, mode, &stbuf);
     if (err < 0) {
         goto out;
     }
@@ -1617,17 +1615,7 @@ static void v9fs_lcreate(void *opaque)
          */
         fidp->flags |= FID_NON_RECLAIMABLE;
     }
-    iounit =  get_iounit(pdu->s, &fullname);
-
-    err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
-    if (err < 0) {
-        fidp->fid_type = P9_FID_NONE;
-        if (fidp->fs.fd > 0) {
-            v9fs_co_close(pdu->s, fidp->fs.fd);
-        }
-        goto out;
-    }
-    v9fs_string_copy(&fidp->path, &fullname);
+    iounit =  get_iounit(pdu->s, &fidp->path);
     stat_to_qid(&stbuf, &qid);
     offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
     err = offset;
@@ -1636,7 +1624,6 @@ out:
 out_nofid:
     complete_pdu(pdu->s, pdu, err);
     v9fs_string_free(&name);
-    v9fs_string_free(&fullname);
 }
 
 static void v9fs_fsync(void *opaque)
@@ -2102,11 +2089,12 @@ static void v9fs_create(void *opaque)
         goto out;
     }
     if (perm & P9_STAT_MODE_DIR) {
-        err = v9fs_co_mkdir(pdu->s, fullname.data, perm & 0777,
-                            fidp->uid, -1);
+        err = v9fs_co_mkdir(pdu->s, fidp, &name, perm & 0777,
+                            fidp->uid, -1, &stbuf);
         if (err < 0) {
             goto out;
         }
+        v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
         v9fs_string_copy(&fidp->path, &fullname);
         err = v9fs_co_opendir(pdu->s, fidp);
         if (err < 0) {
@@ -2114,11 +2102,13 @@ static void v9fs_create(void *opaque)
         }
         fidp->fid_type = P9_FID_DIR;
     } else if (perm & P9_STAT_MODE_SYMLINK) {
-        err = v9fs_co_symlink(pdu->s, fidp, extension.data,
-                              fullname.data, -1);
+        err = v9fs_co_symlink(pdu->s, fidp, &name,
+                              extension.data, -1 , &stbuf);
         if (err < 0) {
             goto out;
         }
+        v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
+        v9fs_string_copy(&fidp->path, &fullname);
     } else if (perm & P9_STAT_MODE_LINK) {
         int32_t nfid = atoi(extension.data);
         V9fsFidState *nfidp = get_fid(pdu->s, nfid);
@@ -2126,12 +2116,19 @@ static void v9fs_create(void *opaque)
             err = -EINVAL;
             goto out;
         }
+        v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
         err = v9fs_co_link(pdu->s, &nfidp->path, &fullname);
+        put_fid(pdu->s, nfidp);
         if (err < 0) {
-            put_fid(pdu->s, nfidp);
             goto out;
         }
-        put_fid(pdu->s, nfidp);
+        v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
+        v9fs_string_copy(&fidp->path, &fullname);
+        err = v9fs_co_lstat(pdu->s, &fidp->path, &stbuf);
+        if (err < 0) {
+            fidp->fid_type = P9_FID_NONE;
+            goto out;
+        }
     } else if (perm & P9_STAT_MODE_DEVICE) {
         char ctype;
         uint32_t major, minor;
@@ -2155,26 +2152,32 @@ static void v9fs_create(void *opaque)
         }
 
         nmode |= perm & 0777;
-        err = v9fs_co_mknod(pdu->s, &fullname, fidp->uid, -1,
-                            makedev(major, minor), nmode);
+        err = v9fs_co_mknod(pdu->s, fidp, &name, fidp->uid, -1,
+                            makedev(major, minor), nmode, &stbuf);
         if (err < 0) {
             goto out;
         }
+        v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
+        v9fs_string_copy(&fidp->path, &fullname);
     } else if (perm & P9_STAT_MODE_NAMED_PIPE) {
-        err = v9fs_co_mknod(pdu->s, &fullname, fidp->uid, -1,
-                            0, S_IFIFO | (perm & 0777));
+        err = v9fs_co_mknod(pdu->s, fidp, &name, fidp->uid, -1,
+                            0, S_IFIFO | (perm & 0777), &stbuf);
         if (err < 0) {
             goto out;
         }
+        v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
+        v9fs_string_copy(&fidp->path, &fullname);
     } else if (perm & P9_STAT_MODE_SOCKET) {
-        err = v9fs_co_mknod(pdu->s, &fullname, fidp->uid, -1,
-                            0, S_IFSOCK | (perm & 0777));
+        err = v9fs_co_mknod(pdu->s, fidp, &name, fidp->uid, -1,
+                            0, S_IFSOCK | (perm & 0777), &stbuf);
         if (err < 0) {
             goto out;
         }
+        v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
+        v9fs_string_copy(&fidp->path, &fullname);
     } else {
-        err = v9fs_co_open2(pdu->s, fidp, fullname.data, -1,
-                            omode_to_uflags(mode)|O_CREAT, perm);
+        err = v9fs_co_open2(pdu->s, fidp, &name, -1,
+                            omode_to_uflags(mode)|O_CREAT, perm, &stbuf);
         if (err < 0) {
             goto out;
         }
@@ -2188,16 +2191,7 @@ static void v9fs_create(void *opaque)
             fidp->flags |= FID_NON_RECLAIMABLE;
         }
     }
-    err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
-    if (err < 0) {
-        fidp->fid_type = P9_FID_NONE;
-        if (fidp->fs.fd) {
-            v9fs_co_close(pdu->s, fidp->fs.fd);
-        }
-        goto out;
-    }
     iounit = get_iounit(pdu->s, &fidp->path);
-    v9fs_string_copy(&fidp->path, &fullname);
     stat_to_qid(&stbuf, &qid);
     offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
     err = offset;
@@ -2215,7 +2209,6 @@ static void v9fs_symlink(void *opaque)
     V9fsPDU *pdu = opaque;
     V9fsString name;
     V9fsString symname;
-    V9fsString fullname;
     V9fsFidState *dfidp;
     V9fsQID qid;
     struct stat stbuf;
@@ -2224,7 +2217,6 @@ static void v9fs_symlink(void *opaque)
     gid_t gid;
     size_t offset = 7;
 
-    v9fs_string_init(&fullname);
     pdu_unmarshal(pdu, offset, "dssd", &dfid, &name, &symname, &gid);
 
     dfidp = get_fid(pdu->s, dfid);
@@ -2232,13 +2224,7 @@ static void v9fs_symlink(void *opaque)
         err = -EINVAL;
         goto out_nofid;
     }
-
-    v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name.data);
-    err = v9fs_co_symlink(pdu->s, dfidp, symname.data, fullname.data, gid);
-    if (err < 0) {
-        goto out;
-    }
-    err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
+    err = v9fs_co_symlink(pdu->s, dfidp, &name, symname.data, gid, &stbuf);
     if (err < 0) {
         goto out;
     }
@@ -2251,7 +2237,6 @@ out_nofid:
     complete_pdu(pdu->s, pdu, err);
     v9fs_string_free(&name);
     v9fs_string_free(&symname);
-    v9fs_string_free(&fullname);
 }
 
 static void v9fs_flush(void *opaque)
@@ -2469,7 +2454,9 @@ static void v9fs_rename(void *opaque)
     }
     BUG_ON(fidp->fid_type != P9_FID_NONE);
 
+    qemu_co_rwlock_wrlock(&s->rename_lock);
     err = v9fs_complete_rename(s, fidp, newdirfid, &name);
+    qemu_co_rwlock_unlock(&s->rename_lock);
     if (!err) {
         err = offset;
     }
@@ -2551,7 +2538,9 @@ static void v9fs_renameat(void *opaque)
     pdu_unmarshal(pdu, offset, "dsds", &olddirfid,
                   &old_name, &newdirfid, &new_name);
 
+    qemu_co_rwlock_wrlock(&s->rename_lock);
     err = v9fs_complete_renameat(s, olddirfid, &old_name, newdirfid, &new_name);
+    qemu_co_rwlock_unlock(&s->rename_lock);
     if (!err) {
         err = offset;
     }
@@ -2735,12 +2724,10 @@ static void v9fs_mknod(void *opaque)
     size_t offset = 7;
     V9fsString name;
     struct stat stbuf;
-    V9fsString fullname;
     V9fsFidState *fidp;
     V9fsPDU *pdu = opaque;
     V9fsState *s = pdu->s;
 
-    v9fs_string_init(&fullname);
     pdu_unmarshal(pdu, offset, "dsdddd", &fid, &name, &mode,
                   &major, &minor, &gid);
 
@@ -2749,13 +2736,8 @@ static void v9fs_mknod(void *opaque)
         err = -ENOENT;
         goto out_nofid;
     }
-    v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
-    err = v9fs_co_mknod(s, &fullname, fidp->uid, gid,
-                        makedev(major, minor), mode);
-    if (err < 0) {
-        goto out;
-    }
-    err = v9fs_co_lstat(s, &fullname, &stbuf);
+    err = v9fs_co_mknod(s, fidp, &name, fidp->uid, gid,
+                        makedev(major, minor), mode, &stbuf);
     if (err < 0) {
         goto out;
     }
@@ -2766,7 +2748,6 @@ out:
     put_fid(s, fidp);
 out_nofid:
     complete_pdu(s, pdu, err);
-    v9fs_string_free(&fullname);
     v9fs_string_free(&name);
 }
 
@@ -2867,14 +2848,13 @@ static void v9fs_mkdir(void *opaque)
     size_t offset = 7;
     int32_t fid;
     struct stat stbuf;
-    V9fsString name, fullname;
     V9fsQID qid;
+    V9fsString name;
     V9fsFidState *fidp;
     gid_t gid;
     int mode;
     int err = 0;
 
-    v9fs_string_init(&fullname);
     pdu_unmarshal(pdu, offset, "dsdd", &fid, &name, &mode, &gid);
 
     fidp = get_fid(pdu->s, fid);
@@ -2882,12 +2862,7 @@ static void v9fs_mkdir(void *opaque)
         err = -ENOENT;
         goto out_nofid;
     }
-    v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
-    err = v9fs_co_mkdir(pdu->s, fullname.data, mode, fidp->uid, gid);
-    if (err < 0) {
-        goto out;
-    }
-    err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
+    err = v9fs_co_mkdir(pdu->s, fidp, &name, mode, fidp->uid, gid, &stbuf);
     if (err < 0) {
         goto out;
     }
@@ -2898,7 +2873,6 @@ out:
     put_fid(pdu->s, fidp);
 out_nofid:
     complete_pdu(pdu->s, pdu, err);
-    v9fs_string_free(&fullname);
     v9fs_string_free(&name);
 }
 
diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
index 8aeee4e..4238a76 100644
--- a/hw/9pfs/virtio-9p.h
+++ b/hw/9pfs/virtio-9p.h
@@ -8,6 +8,8 @@
 #include <sys/resource.h>
 #include "hw/virtio.h"
 #include "fsdev/file-op-9p.h"
+#include "qemu-thread.h"
+#include "qemu-coroutine.h"
 
 /* The feature bitmap for virtio 9P */
 /* The mount point is specified in a config variable */
@@ -237,6 +239,11 @@ typedef struct V9fsState
     size_t config_size;
     enum p9_proto_version proto_version;
     int32_t msize;
+    /*
+     * lock ensuring atomic path update
+     * on rename.
+     */
+    CoRwlock rename_lock;
 } V9fsState;
 
 typedef struct V9fsStatState {
commit 70c18fc08bcc9e9bbd8c00ca5e694e07890687e5
Author: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Date:   Tue May 24 15:21:27 2011 +0530

    hw/9pfs: Make v9fs_string* functions non-static
    
    We will use them later in other files
    
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>

diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index d28edb7..dc3e32b 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -80,20 +80,20 @@ void cred_init(FsCred *credp)
     credp->fc_rdev = -1;
 }
 
-static void v9fs_string_init(V9fsString *str)
+void v9fs_string_init(V9fsString *str)
 {
     str->data = NULL;
     str->size = 0;
 }
 
-static void v9fs_string_free(V9fsString *str)
+void v9fs_string_free(V9fsString *str)
 {
     g_free(str->data);
     str->data = NULL;
     str->size = 0;
 }
 
-static void v9fs_string_null(V9fsString *str)
+void v9fs_string_null(V9fsString *str)
 {
     v9fs_string_free(str);
 }
@@ -192,7 +192,7 @@ alloc_print:
     return vsprintf(*strp, fmt, ap);
 }
 
-static void GCC_FMT_ATTR(2, 3)
+void GCC_FMT_ATTR(2, 3)
 v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
 {
     va_list ap;
@@ -208,7 +208,7 @@ v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
     str->size = err;
 }
 
-static void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
+void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
 {
     v9fs_string_free(lhs);
     v9fs_string_sprintf(lhs, "%s", rhs->data);
diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
index 17d44b4..8aeee4e 100644
--- a/hw/9pfs/virtio-9p.h
+++ b/hw/9pfs/virtio-9p.h
@@ -384,4 +384,9 @@ static inline size_t do_pdu_unpack(void *dst, struct iovec *sg, int sg_count,
 extern void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq);
 extern void virtio_9p_set_fd_limit(void);
 extern void v9fs_reclaim_fd(V9fsState *s);
+extern void v9fs_string_init(V9fsString *str);
+extern void v9fs_string_free(V9fsString *str);
+extern void v9fs_string_null(V9fsString *str);
+extern void v9fs_string_sprintf(V9fsString *str, const char *fmt, ...);
+extern void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs);
 #endif
commit d85a1302a91912c52cdc3fe459b313848a8a0792
Merge: ed95ee8... 363c3c8...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Sep 22 10:31:26 2011 -0500

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

commit ed95ee87a5b8334d91844a4c5af578769a9a0170
Merge: bea09f6... 860329b...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Sep 22 10:30:01 2011 -0500

    Merge remote-tracking branch 'qemu-kvm-tmp/memory/core' into staging

commit bea09f657f95219cc76f90b7eeaec4de77ab664e
Merge: 9ba2a05... 4b710a3...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Sep 22 10:29:46 2011 -0500

    Merge remote-tracking branch 'stefanha/tracing' into staging

commit 9ba2a054db309646946d7e01f87693b09a6bdb11
Merge: bdd2672... 7b0a03a...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Sep 22 10:29:42 2011 -0500

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

commit bdd2672109caa5cbdd955ef5c7a05b49a6b44fbe
Merge: 27cdad6... 2654c96...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Sep 22 10:27:14 2011 -0500

    Merge remote-tracking branch 'qemu-kvm-tmp/memory/batch' into staging

commit 363c3c85350d79d224265aac11db1fbcb61215dc
Author: Nick Thomas <nick at bytemark.co.uk>
Date:   Wed Sep 21 11:55:50 2011 +0100

    block/curl: Don't finish AIOCBs too early
    
    The previous behaviour was to finish AIOCBs inside curl_aio_readv()
    if the data was cached. This caused the following failed assertion
    at hw/ide/pci.c:314: bmdma_cmd_writeb
    
    "Assertion `bm->bus->dma->aiocb == ((void *)0)' failed."
    
    By scheduling a QEMUBH and performing the completion inside the
    callback, we avoid this problem.
    
    Signed-off-by: Nick Thomas <nick at bytemark.co.uk>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/curl.c b/block/curl.c
index 21fed93..4209ac8 100644
--- a/block/curl.c
+++ b/block/curl.c
@@ -47,7 +47,12 @@ struct BDRVCURLState;
 
 typedef struct CURLAIOCB {
     BlockDriverAIOCB common;
+    QEMUBH *bh;
     QEMUIOVector *qiov;
+
+    int64_t sector_num;
+    int nb_sectors;
+
     size_t start;
     size_t end;
 } CURLAIOCB;
@@ -440,43 +445,42 @@ static AIOPool curl_aio_pool = {
     .cancel             = curl_aio_cancel,
 };
 
-static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
-        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque)
+
+static void curl_readv_bh_cb(void *p)
 {
-    BDRVCURLState *s = bs->opaque;
-    CURLAIOCB *acb;
-    size_t start = sector_num * SECTOR_SIZE;
-    size_t end;
     CURLState *state;
 
-    acb = qemu_aio_get(&curl_aio_pool, bs, cb, opaque);
-    if (!acb)
-        return NULL;
+    CURLAIOCB *acb = p;
+    BDRVCURLState *s = acb->common.bs->opaque;
 
-    acb->qiov = qiov;
+    qemu_bh_delete(acb->bh);
+    acb->bh = NULL;
+
+    size_t start = acb->sector_num * SECTOR_SIZE;
+    size_t end;
 
     // In case we have the requested data already (e.g. read-ahead),
     // we can just call the callback and be done.
-
-    switch (curl_find_buf(s, start, nb_sectors * SECTOR_SIZE, acb)) {
+    switch (curl_find_buf(s, start, acb->nb_sectors * SECTOR_SIZE, acb)) {
         case FIND_RET_OK:
             qemu_aio_release(acb);
             // fall through
         case FIND_RET_WAIT:
-            return &acb->common;
+            return;
         default:
             break;
     }
 
     // No cache found, so let's start a new request
-
     state = curl_init_state(s);
-    if (!state)
-        return NULL;
+    if (!state) {
+        acb->common.cb(acb->common.opaque, -EIO);
+        qemu_aio_release(acb);
+        return;
+    }
 
     acb->start = 0;
-    acb->end = (nb_sectors * SECTOR_SIZE);
+    acb->end = (acb->nb_sectors * SECTOR_SIZE);
 
     state->buf_off = 0;
     if (state->orig_buf)
@@ -489,12 +493,38 @@ static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
 
     snprintf(state->range, 127, "%zd-%zd", start, end);
     DPRINTF("CURL (AIO): Reading %d at %zd (%s)\n",
-            (nb_sectors * SECTOR_SIZE), start, state->range);
+            (acb->nb_sectors * SECTOR_SIZE), start, state->range);
     curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range);
 
     curl_multi_add_handle(s->multi, state->curl);
     curl_multi_do(s);
 
+}
+
+static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    CURLAIOCB *acb;
+
+    acb = qemu_aio_get(&curl_aio_pool, bs, cb, opaque);
+
+    if (!acb) {
+        return NULL;
+    }
+
+    acb->qiov = qiov;
+    acb->sector_num = sector_num;
+    acb->nb_sectors = nb_sectors;
+
+    acb->bh = qemu_bh_new(curl_readv_bh_cb, acb);
+
+    if (!acb->bh) {
+        DPRINTF("CURL: qemu_bh_new failed\n");
+        return NULL;
+    }
+
+    qemu_bh_schedule(acb->bh);
     return &acb->common;
 }
 
commit c84dcdc1d6583ebe5841907c99d95deb8c40a6e0
Author: Nick Thomas <nick at bytemark.co.uk>
Date:   Wed Sep 21 11:55:49 2011 +0100

    block/curl: Implement a flush function on the fd handlers
    
    Signed-off-by: Nick Thomas <nick at bytemark.co.uk>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/curl.c b/block/curl.c
index f3f61cc..21fed93 100644
--- a/block/curl.c
+++ b/block/curl.c
@@ -76,6 +76,7 @@ typedef struct BDRVCURLState {
 
 static void curl_clean_state(CURLState *s);
 static void curl_multi_do(void *arg);
+static int curl_aio_flush(void *opaque);
 
 static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
                         void *s, void *sp)
@@ -83,14 +84,16 @@ static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
     DPRINTF("CURL (AIO): Sock action %d on fd %d\n", action, fd);
     switch (action) {
         case CURL_POLL_IN:
-            qemu_aio_set_fd_handler(fd, curl_multi_do, NULL, NULL, NULL, s);
+            qemu_aio_set_fd_handler(fd, curl_multi_do, NULL, curl_aio_flush,
+                                    NULL, s);
             break;
         case CURL_POLL_OUT:
-            qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, NULL, NULL, s);
+            qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, curl_aio_flush,
+                                    NULL, s);
             break;
         case CURL_POLL_INOUT:
-            qemu_aio_set_fd_handler(fd, curl_multi_do,
-                                    curl_multi_do, NULL, NULL, s);
+            qemu_aio_set_fd_handler(fd, curl_multi_do, curl_multi_do,
+                                    curl_aio_flush, NULL, s);
             break;
         case CURL_POLL_REMOVE:
             qemu_aio_set_fd_handler(fd, NULL, NULL, NULL, NULL, NULL);
@@ -412,6 +415,21 @@ out_noclean:
     return -EINVAL;
 }
 
+static int curl_aio_flush(void *opaque)
+{
+    BDRVCURLState *s = opaque;
+    int i, j;
+
+    for (i=0; i < CURL_NUM_STATES; i++) {
+        for(j=0; j < CURL_NUM_ACB; j++) {
+            if (s->states[i].acb[j]) {
+                return 1;
+            }
+        }
+    }
+    return 0;
+}
+
 static void curl_aio_cancel(BlockDriverAIOCB *blockacb)
 {
     // Do we have to implement canceling? Seems to work without...
commit 465f1ab16169f5d71e52f11d4c650a50fd681030
Author: Daniel Verkamp <daniel at drv.nu>
Date:   Sat Aug 27 02:12:28 2011 -0700

    ahci: add port I/O index-data pair
    
    Implement an I/O space index-data register pair as defined by the AHCI
    spec, including the corresponding SATA PCI capability and BAR.
    
    This allows real-mode code to access the AHCI registers; real-mode
    code cannot address the memory-mapped register space because it is
    beyond the first megabyte.
    
    Signed-off-by: Daniel Verkamp <daniel at drv.nu>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 226230c..1c7e3a0 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -370,6 +370,43 @@ static MemoryRegionOps ahci_mem_ops = {
     .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
+static uint64_t ahci_idp_read(void *opaque, target_phys_addr_t addr,
+                              unsigned size)
+{
+    AHCIState *s = opaque;
+
+    if (addr == s->idp_offset) {
+        /* index register */
+        return s->idp_index;
+    } else if (addr == s->idp_offset + 4) {
+        /* data register - do memory read at location selected by index */
+        return ahci_mem_read(opaque, s->idp_index, size);
+    } else {
+        return 0;
+    }
+}
+
+static void ahci_idp_write(void *opaque, target_phys_addr_t addr,
+                           uint64_t val, unsigned size)
+{
+    AHCIState *s = opaque;
+
+    if (addr == s->idp_offset) {
+        /* index register - mask off reserved bits */
+        s->idp_index = (uint32_t)val & ((AHCI_MEM_BAR_SIZE - 1) & ~3);
+    } else if (addr == s->idp_offset + 4) {
+        /* data register - do memory write at location selected by index */
+        ahci_mem_write(opaque, s->idp_index, val, size);
+    }
+}
+
+static MemoryRegionOps ahci_idp_ops = {
+    .read = ahci_idp_read,
+    .write = ahci_idp_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+
 static void ahci_reg_init(AHCIState *s)
 {
     int i;
@@ -1130,7 +1167,9 @@ void ahci_init(AHCIState *s, DeviceState *qdev, int ports)
     s->dev = g_malloc0(sizeof(AHCIDevice) * ports);
     ahci_reg_init(s);
     /* XXX BAR size should be 1k, but that breaks, so bump it to 4k for now */
-    memory_region_init_io(&s->mem, &ahci_mem_ops, s, "ahci", 0x1000);
+    memory_region_init_io(&s->mem, &ahci_mem_ops, s, "ahci", AHCI_MEM_BAR_SIZE);
+    memory_region_init_io(&s->idp, &ahci_idp_ops, s, "ahci-idp", 32);
+
     irqs = qemu_allocate_irqs(ahci_irq_set, s, s->ports);
 
     for (i = 0; i < s->ports; i++) {
@@ -1150,6 +1189,7 @@ void ahci_init(AHCIState *s, DeviceState *qdev, int ports)
 void ahci_uninit(AHCIState *s)
 {
     memory_region_destroy(&s->mem);
+    memory_region_destroy(&s->idp);
     g_free(s->dev);
 }
 
diff --git a/hw/ide/ahci.h b/hw/ide/ahci.h
index 5de986c..b223d2c 100644
--- a/hw/ide/ahci.h
+++ b/hw/ide/ahci.h
@@ -24,7 +24,7 @@
 #ifndef HW_IDE_AHCI_H
 #define HW_IDE_AHCI_H
 
-#define AHCI_PCI_BAR              5
+#define AHCI_MEM_BAR_SIZE         0x1000
 #define AHCI_MAX_PORTS            32
 #define AHCI_MAX_SG               168 /* hardware max is 64K */
 #define AHCI_DMA_BOUNDARY         0xffffffff
@@ -212,6 +212,10 @@
 #define RES_FIS_SDBFIS                     0x58
 #define RES_FIS_UFIS                       0x60
 
+#define SATA_CAP_SIZE           0x8
+#define SATA_CAP_REV            0x2
+#define SATA_CAP_BAR            0x4
+
 typedef struct AHCIControlRegs {
     uint32_t    cap;
     uint32_t    ghc;
@@ -290,6 +294,9 @@ typedef struct AHCIState {
     AHCIDevice *dev;
     AHCIControlRegs control_regs;
     MemoryRegion mem;
+    MemoryRegion idp;       /* Index-Data Pair I/O port space */
+    unsigned idp_offset;    /* Offset of index in I/O port space */
+    uint32_t idp_index;     /* Current IDP index */
     int ports;
     qemu_irq irq;
 } AHCIState;
diff --git a/hw/ide/ich.c b/hw/ide/ich.c
index 0327d0e..3f7510f 100644
--- a/hw/ide/ich.c
+++ b/hw/ide/ich.c
@@ -71,6 +71,14 @@
 #include <hw/ide/pci.h>
 #include <hw/ide/ahci.h>
 
+#define ICH9_SATA_CAP_OFFSET    0xA8
+
+#define ICH9_IDP_BAR            4
+#define ICH9_MEM_BAR            5
+
+#define ICH9_IDP_INDEX          0x10
+#define ICH9_IDP_INDEX_LOG2     0x04
+
 static const VMStateDescription vmstate_ahci = {
     .name = "ahci",
     .unmigratable = 1,
@@ -79,6 +87,8 @@ static const VMStateDescription vmstate_ahci = {
 static int pci_ich9_ahci_init(PCIDevice *dev)
 {
     struct AHCIPCIState *d;
+    int sata_cap_offset;
+    uint8_t *sata_cap;
     d = DO_UPCAST(struct AHCIPCIState, card, dev);
 
     ahci_init(&d->ahci, &dev->qdev, 6);
@@ -97,7 +107,22 @@ static int pci_ich9_ahci_init(PCIDevice *dev)
     msi_init(dev, 0x50, 1, true, false);
     d->ahci.irq = d->card.irq[0];
 
-    pci_register_bar(&d->card, 5, 0, &d->ahci.mem);
+    pci_register_bar(&d->card, ICH9_IDP_BAR, PCI_BASE_ADDRESS_SPACE_IO,
+                     &d->ahci.idp);
+    pci_register_bar(&d->card, ICH9_MEM_BAR, PCI_BASE_ADDRESS_SPACE_MEMORY,
+                     &d->ahci.mem);
+
+    sata_cap_offset = pci_add_capability(&d->card, PCI_CAP_ID_SATA,
+                                         ICH9_SATA_CAP_OFFSET, SATA_CAP_SIZE);
+    if (sata_cap_offset < 0) {
+        return sata_cap_offset;
+    }
+
+    sata_cap = d->card.config + sata_cap_offset;
+    pci_set_word(sata_cap + SATA_CAP_REV, 0x10);
+    pci_set_long(sata_cap + SATA_CAP_BAR,
+                 (ICH9_IDP_BAR + 0x4) | (ICH9_IDP_INDEX_LOG2 << 4));
+    d->ahci.idp_offset = ICH9_IDP_INDEX;
 
     return 0;
 }
diff --git a/hw/pci_regs.h b/hw/pci_regs.h
index e884096..e8357c3 100644
--- a/hw/pci_regs.h
+++ b/hw/pci_regs.h
@@ -211,6 +211,7 @@
 #define  PCI_CAP_ID_AGP3	0x0E	/* AGP Target PCI-PCI bridge */
 #define  PCI_CAP_ID_EXP 	0x10	/* PCI Express */
 #define  PCI_CAP_ID_MSIX	0x11	/* MSI-X */
+#define  PCI_CAP_ID_SATA	0x12	/* Serial ATA */
 #define  PCI_CAP_ID_AF		0x13	/* PCI Advanced Features */
 #define PCI_CAP_LIST_NEXT	1	/* Next capability in the list */
 #define PCI_CAP_FLAGS		2	/* Capability defined flags (16 bits) */
commit 4b710a3cd410eb4eb39fbad2e38efe82c502250e
Author: Lluís Vilanova <vilanova at ac.upc.edu>
Date:   Tue Sep 20 21:03:48 2011 +0200

    trace: Update docs to use example events that exist
    
    The events 'qemu_malloc' and 'qemu_free' used in the examples no longer exist,
    so use 'qemu_vmalloc' and 'qemu_vfree' instead.
    
    Signed-off-by: Lluís Vilanova <vilanova at ac.upc.edu>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/docs/tracing.txt b/docs/tracing.txt
index 2c33a62..95ca16c 100644
--- a/docs/tracing.txt
+++ b/docs/tracing.txt
@@ -31,8 +31,8 @@ There is a set of static trace events declared in the "trace-events" source
 file.  Each trace event declaration names the event, its arguments, and the
 format string which can be used for pretty-printing:
 
-    qemu_malloc(size_t size, void *ptr) "size %zu ptr %p"
-    qemu_free(void *ptr) "ptr %p"
+    qemu_vmalloc(size_t size, void *ptr) "size %zu ptr %p"
+    qemu_vfree(void *ptr) "ptr %p"
 
 The "trace-events" file is processed by the "tracetool" script during build to
 generate code for the trace events.  Trace events are invoked directly from
@@ -40,14 +40,16 @@ source code like this:
 
     #include "trace.h"  /* needed for trace event prototype */
     
-    void *qemu_malloc(size_t size)
+    void *qemu_vmalloc(size_t size)
     {
         void *ptr;
-        if (!size && !allow_zero_malloc()) {
-            abort();
+        size_t align = QEMU_VMALLOC_ALIGN;
+     
+        if (size < align) {
+            align = getpagesize();
         }
-        ptr = oom_check(malloc(size ? size : 1));
-        trace_qemu_malloc(size, ptr);  /* <-- trace event */
+        ptr = qemu_memalign(align, size);
+        trace_qemu_vmalloc(size, ptr);
         return ptr;
     }
 
commit 6c2a40742602c3cbe6a3905229dd539d7c311550
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Mon Sep 5 18:31:21 2011 +0100

    trace: use binary file open mode in simpletrace
    
    For Windows portability the simple trace backend must use the 'b' file
    open mode.  This prevents the stdio library from mangling 0x0a/0x0d
    newline characters.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/trace/simple.c b/trace/simple.c
index 885764a..b639dda 100644
--- a/trace/simple.c
+++ b/trace/simple.c
@@ -234,7 +234,7 @@ void st_set_trace_file_enabled(bool enable)
             .x1 = HEADER_VERSION,
         };
 
-        trace_fp = fopen(trace_file_name, "w");
+        trace_fp = fopen(trace_file_name, "wb");
         if (!trace_fp) {
             return;
         }
commit 85aff1586fe4a0dfc6eda2dfd6e79e78063f4fbb
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Mon Sep 5 08:30:17 2011 +0100

    trace: portable simple trace backend using glib
    
    Convert the simple trace backend to glib so that it works under Windows.
    We cannot use pthread directly but glib provides portable abstractions.
    Also use glib atomics instead of newish gcc builtins which may not be
    supported on Windows toolchains.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/trace/simple.c b/trace/simple.c
index a609368..885764a 100644
--- a/trace/simple.c
+++ b/trace/simple.c
@@ -12,8 +12,10 @@
 #include <stdint.h>
 #include <stdio.h>
 #include <time.h>
+#ifndef _WIN32
 #include <signal.h>
 #include <pthread.h>
+#endif
 #include "qemu-timer.h"
 #include "trace.h"
 #include "trace/control.h"
@@ -54,9 +56,9 @@ enum {
  * Trace records are written out by a dedicated thread.  The thread waits for
  * records to become available, writes them out, and then waits again.
  */
-static pthread_mutex_t trace_lock = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t trace_available_cond = PTHREAD_COND_INITIALIZER;
-static pthread_cond_t trace_empty_cond = PTHREAD_COND_INITIALIZER;
+static GStaticMutex trace_lock = G_STATIC_MUTEX_INIT;
+static GCond *trace_available_cond;
+static GCond *trace_empty_cond;
 static bool trace_available;
 static bool trace_writeout_enabled;
 
@@ -93,29 +95,30 @@ static bool get_trace_record(unsigned int idx, TraceRecord *record)
  */
 static void flush_trace_file(bool wait)
 {
-    pthread_mutex_lock(&trace_lock);
+    g_static_mutex_lock(&trace_lock);
     trace_available = true;
-    pthread_cond_signal(&trace_available_cond);
+    g_cond_signal(trace_available_cond);
 
     if (wait) {
-        pthread_cond_wait(&trace_empty_cond, &trace_lock);
+        g_cond_wait(trace_empty_cond, g_static_mutex_get_mutex(&trace_lock));
     }
 
-    pthread_mutex_unlock(&trace_lock);
+    g_static_mutex_unlock(&trace_lock);
 }
 
 static void wait_for_trace_records_available(void)
 {
-    pthread_mutex_lock(&trace_lock);
+    g_static_mutex_lock(&trace_lock);
     while (!(trace_available && trace_writeout_enabled)) {
-        pthread_cond_signal(&trace_empty_cond);
-        pthread_cond_wait(&trace_available_cond, &trace_lock);
+        g_cond_signal(trace_empty_cond);
+        g_cond_wait(trace_available_cond,
+                    g_static_mutex_get_mutex(&trace_lock));
     }
     trace_available = false;
-    pthread_mutex_unlock(&trace_lock);
+    g_static_mutex_unlock(&trace_lock);
 }
 
-static void *writeout_thread(void *opaque)
+static gpointer writeout_thread(gpointer opaque)
 {
     TraceRecord record;
     unsigned int writeout_idx = 0;
@@ -159,7 +162,7 @@ static void trace(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3,
 
     timestamp = get_clock();
 
-    idx = __sync_fetch_and_add(&trace_idx, 1) % TRACE_BUF_LEN;
+    idx = g_atomic_int_exchange_and_add((gint *)&trace_idx, 1) % TRACE_BUF_LEN;
     trace_buf[idx] = (TraceRecord){
         .event = event,
         .timestamp_ns = timestamp,
@@ -331,28 +334,47 @@ bool trace_event_set_state(const char *name, bool state)
     return false;
 }
 
-bool trace_backend_init(const char *events, const char *file)
+/* Helper function to create a thread with signals blocked.  Use glib's
+ * portable threads since QEMU abstractions cannot be used due to reentrancy in
+ * the tracer.  Also note the signal masking on POSIX hosts so that the thread
+ * does not steal signals when the rest of the program wants them blocked.
+ */
+static GThread *trace_thread_create(GThreadFunc fn)
 {
-    pthread_t thread;
-    pthread_attr_t attr;
+    GThread *thread;
+#ifndef _WIN32
     sigset_t set, oldset;
-    int ret;
-
-    pthread_attr_init(&attr);
-    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
 
     sigfillset(&set);
     pthread_sigmask(SIG_SETMASK, &set, &oldset);
-    ret = pthread_create(&thread, &attr, writeout_thread, NULL);
+#endif
+    thread = g_thread_create(writeout_thread, NULL, FALSE, NULL);
+#ifndef _WIN32
     pthread_sigmask(SIG_SETMASK, &oldset, NULL);
+#endif
 
-    if (ret != 0) {
+    return thread;
+}
+
+bool trace_backend_init(const char *events, const char *file)
+{
+    GThread *thread;
+
+    if (!g_thread_supported()) {
+        g_thread_init(NULL);
+    }
+
+    trace_available_cond = g_cond_new();
+    trace_empty_cond = g_cond_new();
+
+    thread = trace_thread_create(writeout_thread);
+    if (!thread) {
         fprintf(stderr, "warning: unable to initialize simple trace backend\n");
-    } else {
-        atexit(st_flush_trace_buffer);
-        trace_backend_init_events(events);
-        st_set_trace_file(file);
+        return false;
     }
 
+    atexit(st_flush_trace_buffer);
+    trace_backend_init_events(events);
+    st_set_trace_file(file);
     return true;
 }
commit 598a3f35c5ceab0eb7a3cf82f8aadfc2003a31d8
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Sat Sep 3 16:24:47 2011 +0100

    MAINTAINERS: add tracing subsystem
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/MAINTAINERS b/MAINTAINERS
index 72b2099..7c5ea87 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -459,6 +459,12 @@ S: Maintained
 F: slirp/
 T: git://git.kiszka.org/qemu.git queues/slirp
 
+Tracing
+M: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
+S: Maintained
+F: trace/
+T: git://repo.or.cz/qemu/stefanha.git tracing
+
 Usermode Emulation
 ------------------
 BSD user
commit 8f6421179ad29cbdaa9d5c5b39e9c001996c0f07
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Mon Sep 5 16:31:45 2011 +0100

    trace: allow trace events with string arguments
    
    String arguments are useful for producing human-readable traces without
    post-processing (e.g. stderr backend).  Although the simple backend
    cannot handles strings all others can.  Strings should be allowed and
    the simple backend can be extended to support them.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/docs/tracing.txt b/docs/tracing.txt
index d0171aa..2c33a62 100644
--- a/docs/tracing.txt
+++ b/docs/tracing.txt
@@ -70,11 +70,6 @@ Trace events should use types as follows:
    cannot include all user-defined struct declarations and it is therefore
    necessary to use void * for pointers to structs.
 
-   Pointers (including char *) cannot be dereferenced easily (or at all) in
-   some trace backends.  If pointers are used, ensure they are meaningful by
-   themselves and do not assume the data they point to will be traced.  Do
-   not pass in string arguments.
-
  * For everything else, use primitive scalar types (char, int, long) with the
    appropriate signedness.
 
@@ -182,6 +177,9 @@ source tree.  It may not be as powerful as platform-specific or third-party
 trace backends but it is portable.  This is the recommended trace backend
 unless you have specific needs for more advanced backends.
 
+The "simple" backend currently does not capture string arguments, it simply
+records the char* pointer value instead of the string that is pointed to.
+
 ==== Monitor commands ====
 
 * info trace
commit 7b0a03a1eab52ed2f59c8e4cb2210ee74433a820
Author: Christoph Egger <Christoph.Egger at amd.com>
Date:   Wed Sep 21 11:10:52 2011 +0100

    use qemu_* ctype functions
    
    Fix "warning: array subscript has type 'char'" on NetBSD.
    
    Signed-off-by: Christoph Egger <Christoph.Egger at amd.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/cmd.c b/cmd.c
index ecca167..f77897e 100644
--- a/cmd.c
+++ b/cmd.c
@@ -389,7 +389,7 @@ cvtnum(
 	if (sp[1] != '\0')
 		return -1LL;
 
-	c = tolower(*sp);
+	c = qemu_tolower(*sp);
 	switch (c) {
 	default:
 		return i;
diff --git a/ui/keymaps.c b/ui/keymaps.c
index 81003bb..f54a114 100644
--- a/ui/keymaps.c
+++ b/ui/keymaps.c
@@ -146,7 +146,7 @@ static kbd_layout_t *parse_keyboard_layout(const name2keysym_t *table,
 		    if (rest && strstr(rest, "addupper")) {
 			char *c;
 			for (c = line; *c; c++)
-			    *c = toupper(*c);
+			    *c = qemu_toupper(*c);
 			keysym = get_keysym(table, line);
 			if (keysym)
 			    add_keysym(line, keysym, keycode | SCANCODE_SHIFT, k);
commit 8b3692d13620549c2ca85d9201c32d47b74bb755
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Sat Sep 17 12:25:30 2011 +0200

    Remove qemu_host_page_bits
    
    It was introduced with commit 54936004fddc52c321cb3f9a9a51140e782bed5d
    as host_page_bits but never used.
    
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/cpu-all.h b/cpu-all.h
index f5c82cd..42a5fa0 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -290,7 +290,6 @@ extern unsigned long reserved_va;
 
 /* ??? These should be the larger of unsigned long and target_ulong.  */
 extern unsigned long qemu_real_host_page_size;
-extern unsigned long qemu_host_page_bits;
 extern unsigned long qemu_host_page_size;
 extern unsigned long qemu_host_page_mask;
 
diff --git a/exec.c b/exec.c
index c1e045d..1e6f732 100644
--- a/exec.c
+++ b/exec.c
@@ -183,7 +183,6 @@ typedef struct PageDesc {
 #define V_L1_SHIFT (L1_MAP_ADDR_SPACE_BITS - TARGET_PAGE_BITS - V_L1_BITS)
 
 unsigned long qemu_real_host_page_size;
-unsigned long qemu_host_page_bits;
 unsigned long qemu_host_page_size;
 unsigned long qemu_host_page_mask;
 
@@ -274,9 +273,6 @@ static void page_init(void)
         qemu_host_page_size = qemu_real_host_page_size;
     if (qemu_host_page_size < TARGET_PAGE_SIZE)
         qemu_host_page_size = TARGET_PAGE_SIZE;
-    qemu_host_page_bits = 0;
-    while ((1 << qemu_host_page_bits) < qemu_host_page_size)
-        qemu_host_page_bits++;
     qemu_host_page_mask = ~(qemu_host_page_size - 1);
 
 #if defined(CONFIG_BSD) && defined(CONFIG_USER_ONLY)
commit 53380ac37f252ec67a5597e79a3893795bf273ca
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Wed Sep 21 09:28:31 2011 +0200

    Abort on thread layer errors
    
    Makes it easier to catch the bug in gdb as there is no need to set an
    explicit breakpoint.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/qemu-thread-posix.c b/qemu-thread-posix.c
index 2bd02ef..ac3c0c9 100644
--- a/qemu-thread-posix.c
+++ b/qemu-thread-posix.c
@@ -22,7 +22,7 @@
 static void error_exit(int err, const char *msg)
 {
     fprintf(stderr, "qemu: %s: %s\n", msg, strerror(err));
-    exit(1);
+    abort();
 }
 
 void qemu_mutex_init(QemuMutex *mutex)
diff --git a/qemu-thread-win32.c b/qemu-thread-win32.c
index a27332e..db8e744 100644
--- a/qemu-thread-win32.c
+++ b/qemu-thread-win32.c
@@ -24,7 +24,7 @@ static void error_exit(int err, const char *msg)
                   NULL, err, 0, (LPTSTR)&pstr, 2, NULL);
     fprintf(stderr, "qemu: %s: %s\n", msg, pstr);
     LocalFree(pstr);
-    exit(1);
+    abort();
 }
 
 void qemu_mutex_init(QemuMutex *mutex)
commit c2162a8b07dbc5479bce3dff5882344f61a37647
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Wed Sep 21 09:18:32 2011 +0200

    Silence make if nothing is to do for libcacard
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/libcacard/Makefile b/libcacard/Makefile
index 81d9eb5..a145569 100644
--- a/libcacard/Makefile
+++ b/libcacard/Makefile
@@ -27,6 +27,8 @@ clean:
 	rm -Rf .libs
 
 all: vscclient
+# Dummy command so that make thinks it has done something
+	@true
 
 #########################################################################
 # Rules for building libcacard standalone library
commit 43b26fc85157cf34fdaa3e2c7c79ad3ca210bc65
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Tue Sep 20 17:11:58 2011 +0200

    Drop unneeded pthread.h inclusions
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/hw/xen_nic.c b/hw/xen_nic.c
index aeca8da..ef2a2d6 100644
--- a/hw/xen_nic.c
+++ b/hw/xen_nic.c
@@ -25,7 +25,6 @@
 #include <inttypes.h>
 #include <fcntl.h>
 #include <errno.h>
-#include <pthread.h>
 #include <sys/socket.h>
 #include <sys/ioctl.h>
 #include <sys/types.h>
diff --git a/hw/xics.c b/hw/xics.c
index 9bf82aa..80e064e 100644
--- a/hw/xics.c
+++ b/hw/xics.c
@@ -29,8 +29,6 @@
 #include "hw/spapr.h"
 #include "hw/xics.h"
 
-#include <pthread.h>
-
 /*
  * ICP: Presentation layer
  */
diff --git a/ui/spice-display.c b/ui/spice-display.c
index 3a92a12..6c302a3 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -15,8 +15,6 @@
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <pthread.h>
-
 #include "qemu-common.h"
 #include "qemu-spice.h"
 #include "qemu-timer.h"
commit 903ec8eae6cca0986d8288016aca6c26626e7d85
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Tue Sep 13 17:47:52 2011 +0200

    fix compilation with stderr trace backend
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/trace-events b/trace-events
index 829dc92..a31d9aa 100644
--- a/trace-events
+++ b/trace-events
@@ -455,7 +455,7 @@ milkymist_vgafb_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08
 mipsnet_send(uint32_t size) "sending len=%u"
 mipsnet_receive(uint32_t size) "receiving len=%u"
 mipsnet_read(uint64_t addr, uint32_t val) "read addr=0x%" PRIx64 " val=0x%x"
-mipsnet_write(uint64_t addr, uint64_t val) "write addr=0x%" PRIx64 " val=0x%" PRIx64
+mipsnet_write(uint64_t addr, uint64_t val) "write addr=0x%" PRIx64 " val=0x%" PRIx64 ""
 mipsnet_irq(uint32_t isr, uint32_t intctl) "set irq to %d (%02x)"
 
 # xen-all.c
commit a213fcb21c69c7c3b206d7e251d31559859f1545
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Thu Sep 15 12:15:56 2011 +0100

    configure: Make missing pkg-config an error rather than a warning
    
    If pkg-config doesn't exist then make configure fail immediately
    with a useful error message. Now that glib is a required dependency,
    proceeding despite the missing pkg-config will just cause us to
    fail later with a misleading message about glib not being present.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Acked-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/configure b/configure
index 414317a..9ab3ab4 100755
--- a/configure
+++ b/configure
@@ -1340,8 +1340,8 @@ fi
 # pkg-config probe
 
 if ! has $pkg_config; then
-  echo warning: proceeding without "$pkg_config" >&2
-  pkg_config=/bin/false
+  echo "Error: pkg-config binary '$pkg_config' not found"
+  exit 1
 fi
 
 ##########################################
commit 782ea2c7598a9d07393b6024ec5dfcde96ae3d90
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Wed Sep 14 18:27:54 2011 +0200

    target-i386: Remove data type CCTable
    
    Remove also two assert statements which were the last remaining users.
    
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 4a6f675..ae36489 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -991,11 +991,6 @@ static inline int cpu_mmu_index (CPUState *env)
 /* translate.c */
 void optimize_flags_init(void);
 
-typedef struct CCTable {
-    int (*compute_all)(void); /* return all the flags */
-    int (*compute_c)(void);  /* return the C flag */
-} CCTable;
-
 #if defined(CONFIG_USER_ONLY)
 static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
 {
diff --git a/target-i386/translate.c b/target-i386/translate.c
index b966762..b894e97 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -7641,11 +7641,6 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
 
 void optimize_flags_init(void)
 {
-#if TCG_TARGET_REG_BITS == 32
-    assert(sizeof(CCTable) == (1 << 3));
-#else
-    assert(sizeof(CCTable) == (1 << 4));
-#endif
     cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
     cpu_cc_op = tcg_global_mem_new_i32(TCG_AREG0,
                                        offsetof(CPUState, cc_op), "cc_op");
commit 8e72506e20d9e606783de1cdb8d60dd9b9241e30
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Wed Sep 21 09:34:12 2011 +0200

    nbd: fix non-Linux build failure
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/nbd.c b/nbd.c
index 595f4d8..fb5e424 100644
--- a/nbd.c
+++ b/nbd.c
@@ -439,7 +439,7 @@ int nbd_client(int fd)
     return ret;
 }
 #else
-int nbd_init(int fd, int csock, off_t size, size_t blocksize)
+int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
 {
     errno = ENOTSUP;
     return -1;
commit 2654c962b8e06a7203a453b2171daa9269eab544
Author: Avi Kivity <avi at redhat.com>
Date:   Tue Aug 30 14:53:31 2011 +0300

    omap1: convert to memory API (part VI)
    
    Easy RAM stuff.
    
    Acked-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/omap.h b/hw/omap.h
index de83452..0260cc0 100644
--- a/hw/omap.h
+++ b/hw/omap.h
@@ -841,6 +841,8 @@ struct omap_mpu_state_s {
     MemoryRegion pwl_iomem;
     MemoryRegion pwt_iomem;
     MemoryRegion mpui_io_iomem;
+    MemoryRegion imif_ram;
+    MemoryRegion emiff_ram;
 
     struct omap_dma_port_if_s {
         uint32_t (*read[3])(struct omap_mpu_state_s *s,
diff --git a/hw/omap1.c b/hw/omap1.c
index 4b2abb9..f747321 100644
--- a/hw/omap1.c
+++ b/hw/omap1.c
@@ -3793,7 +3793,6 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
     int i;
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *)
             g_malloc0(sizeof(struct omap_mpu_state_s));
-    ram_addr_t imif_base, emiff_base;
     qemu_irq *cpu_irq;
     qemu_irq dma_irqs[6];
     DriveInfo *dinfo;
@@ -3817,12 +3816,10 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
     omap_clk_init(s);
 
     /* Memory-mapped stuff */
-    cpu_register_physical_memory(OMAP_EMIFF_BASE, s->sdram_size,
-                    (emiff_base = qemu_ram_alloc(NULL, "omap1.dram",
-                                                 s->sdram_size)) | IO_MEM_RAM);
-    cpu_register_physical_memory(OMAP_IMIF_BASE, s->sram_size,
-                    (imif_base = qemu_ram_alloc(NULL, "omap1.sram",
-                                                s->sram_size)) | IO_MEM_RAM);
+    memory_region_init_ram(&s->emiff_ram, NULL, "omap1.dram", s->sdram_size);
+    memory_region_add_subregion(system_memory, OMAP_EMIFF_BASE, &s->emiff_ram);
+    memory_region_init_ram(&s->imif_ram, NULL, "omap1.sram", s->sram_size);
+    memory_region_add_subregion(system_memory, OMAP_IMIF_BASE, &s->imif_ram);
 
     omap_clkm_init(system_memory, 0xfffece00, 0xe1008000, s);
 
@@ -3848,9 +3845,9 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
     s->port[tipb_mpui].addr_valid = omap_validate_tipb_mpui_addr;
 
     /* Register SDRAM and SRAM DMA ports for fast transfers.  */
-    soc_dma_port_add_mem(s->dma, qemu_get_ram_ptr(emiff_base),
-                             OMAP_EMIFF_BASE, s->sdram_size);
-    soc_dma_port_add_mem(s->dma, qemu_get_ram_ptr(imif_base),
+    soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(&s->emiff_ram),
+                         OMAP_EMIFF_BASE, s->sdram_size);
+    soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(&s->imif_ram),
                          OMAP_IMIF_BASE, s->sram_size);
 
     s->timer[0] = omap_mpu_timer_init(system_memory, 0xfffec500,
diff --git a/hw/soc_dma.h b/hw/soc_dma.h
index 026479e..904b26c 100644
--- a/hw/soc_dma.h
+++ b/hw/soc_dma.h
@@ -18,6 +18,8 @@
  * with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
+#include "memory.h"
+
 struct soc_dma_s;
 struct soc_dma_ch_s;
 typedef void (*soc_dma_io_t)(void *opaque, uint8_t *buf, int len);
commit 90aeba9dac1e99bfbe2d44867ec44b32b0780577
Author: Avi Kivity <avi at redhat.com>
Date:   Tue Aug 30 14:46:53 2011 +0300

    soc_dma: drop soc_dma_port_add_mem_ram()
    
    It's a trivial wrapper for soc_dma_port_add_mem(), which makes
    the memory API conversion more difficult because it takes a ram
    addr_t.  Drop.
    
    Acked-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/omap1.c b/hw/omap1.c
index 09eb363..4b2abb9 100644
--- a/hw/omap1.c
+++ b/hw/omap1.c
@@ -3848,10 +3848,10 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
     s->port[tipb_mpui].addr_valid = omap_validate_tipb_mpui_addr;
 
     /* Register SDRAM and SRAM DMA ports for fast transfers.  */
-    soc_dma_port_add_mem_ram(s->dma,
-                    emiff_base, OMAP_EMIFF_BASE, s->sdram_size);
-    soc_dma_port_add_mem_ram(s->dma,
-                    imif_base, OMAP_IMIF_BASE, s->sram_size);
+    soc_dma_port_add_mem(s->dma, qemu_get_ram_ptr(emiff_base),
+                             OMAP_EMIFF_BASE, s->sdram_size);
+    soc_dma_port_add_mem(s->dma, qemu_get_ram_ptr(imif_base),
+                         OMAP_IMIF_BASE, s->sram_size);
 
     s->timer[0] = omap_mpu_timer_init(system_memory, 0xfffec500,
                     s->irq[0][OMAP_INT_TIMER1],
diff --git a/hw/omap2.c b/hw/omap2.c
index ca088d9..3d529ce 100644
--- a/hw/omap2.c
+++ b/hw/omap2.c
@@ -2284,8 +2284,10 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
     s->port->addr_valid = omap2_validate_addr;
 
     /* Register SDRAM and SRAM ports for fast DMA transfers.  */
-    soc_dma_port_add_mem_ram(s->dma, q2_base, OMAP2_Q2_BASE, s->sdram_size);
-    soc_dma_port_add_mem_ram(s->dma, sram_base, OMAP2_SRAM_BASE, s->sram_size);
+    soc_dma_port_add_mem(s->dma, qemu_get_ram_ptr(q2_base),
+                         OMAP2_Q2_BASE, s->sdram_size);
+    soc_dma_port_add_mem(s->dma, qemu_get_ram_ptr(sram_base),
+                         OMAP2_SRAM_BASE, s->sram_size);
 
     s->uart[0] = omap2_uart_init(omap_l4ta(s->l4, 19),
                     s->irq[0][OMAP_INT_24XX_UART1_IRQ],
diff --git a/hw/soc_dma.h b/hw/soc_dma.h
index c0ebb8d..026479e 100644
--- a/hw/soc_dma.h
+++ b/hw/soc_dma.h
@@ -105,9 +105,3 @@ static inline void soc_dma_port_add_fifo_out(struct soc_dma_s *dma,
 {
     return soc_dma_port_add_fifo(dma, virt_base, fn, opaque, 1);
 }
-
-static inline void soc_dma_port_add_mem_ram(struct soc_dma_s *dma,
-                ram_addr_t offset, target_phys_addr_t virt_base, size_t size)
-{
-    return soc_dma_port_add_mem(dma, qemu_get_ram_ptr(offset), virt_base, size);
-}
commit 9898b79abe32c5521ef365207d8a1db6c3a6e206
Author: Avi Kivity <avi at redhat.com>
Date:   Tue Aug 30 11:56:30 2011 +0300

    omap_lcdc: remove imif, emiff from structure
    
    Not used.
    
    Acked-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/omap.h b/hw/omap.h
index 25d10f3..de83452 100644
--- a/hw/omap.h
+++ b/hw/omap.h
@@ -744,8 +744,7 @@ void omap_tap_init(struct omap_target_agent_s *ta,
 struct omap_lcd_panel_s;
 void omap_lcdc_reset(struct omap_lcd_panel_s *s);
 struct omap_lcd_panel_s *omap_lcdc_init(target_phys_addr_t base, qemu_irq irq,
-                struct omap_dma_lcd_channel_s *dma,
-                ram_addr_t imif_base, ram_addr_t emiff_base, omap_clk clk);
+                struct omap_dma_lcd_channel_s *dma, omap_clk clk);
 
 /* omap_dss.c */
 struct rfbi_chip_s {
diff --git a/hw/omap1.c b/hw/omap1.c
index f48aa8a..09eb363 100644
--- a/hw/omap1.c
+++ b/hw/omap1.c
@@ -3872,8 +3872,7 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
                     omap_findclk(s, "clk32-kHz"));
 
     s->lcd = omap_lcdc_init(0xfffec000, s->irq[0][OMAP_INT_LCD_CTRL],
-                    omap_dma_get_lcdch(s->dma), imif_base, emiff_base,
-                    omap_findclk(s, "lcd_ck"));
+                    omap_dma_get_lcdch(s->dma), omap_findclk(s, "lcd_ck"));
 
     omap_ulpd_pm_init(system_memory, 0xfffe0800, s);
     omap_pin_cfg_init(system_memory, 0xfffe1000, s);
diff --git a/hw/omap_lcdc.c b/hw/omap_lcdc.c
index a905422..29e6048 100644
--- a/hw/omap_lcdc.c
+++ b/hw/omap_lcdc.c
@@ -24,8 +24,6 @@
 struct omap_lcd_panel_s {
     qemu_irq irq;
     DisplayState *state;
-    ram_addr_t imif_base;
-    ram_addr_t emiff_base;
 
     int plm;
     int tft;
@@ -436,8 +434,7 @@ void omap_lcdc_reset(struct omap_lcd_panel_s *s)
 }
 
 struct omap_lcd_panel_s *omap_lcdc_init(target_phys_addr_t base, qemu_irq irq,
-                struct omap_dma_lcd_channel_s *dma,
-                ram_addr_t imif_base, ram_addr_t emiff_base, omap_clk clk)
+                struct omap_dma_lcd_channel_s *dma, omap_clk clk)
 {
     int iomemtype;
     struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *)
@@ -445,8 +442,6 @@ struct omap_lcd_panel_s *omap_lcdc_init(target_phys_addr_t base, qemu_irq irq,
 
     s->irq = irq;
     s->dma = dma;
-    s->imif_base = imif_base;
-    s->emiff_base = emiff_base;
     omap_lcdc_reset(s);
 
     iomemtype = cpu_register_io_memory(omap_lcdc_readfn,
commit 763b946c286fc3c2b64e6058323a12e66866e660
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 29 14:14:06 2011 +0300

    omap1: convert to memory API (part V)
    
    Tricky aliases.
    
    Acked-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/omap1.c b/hw/omap1.c
index df5d68b..f48aa8a 100644
--- a/hw/omap1.c
+++ b/hw/omap1.c
@@ -3708,14 +3708,16 @@ static const struct omap_map_s {
     { 0 }
 };
 
-static void omap_setup_dsp_mapping(const struct omap_map_s *map)
+static void omap_setup_dsp_mapping(MemoryRegion *system_memory,
+                                   const struct omap_map_s *map)
 {
-    int io;
+    MemoryRegion *io;
 
     for (; map->phys_dsp; map ++) {
-        io = cpu_get_physical_page_desc(map->phys_mpu);
-
-        cpu_register_physical_memory(map->phys_dsp, map->size, io);
+        io = g_new(MemoryRegion, 1);
+        memory_region_init_alias(io, map->name,
+                                 system_memory, map->phys_mpu, map->size);
+        memory_region_add_subregion(system_memory, map->phys_dsp, io);
     }
 }
 
@@ -3978,7 +3980,7 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
      * DSP MMU		fffed200 - fffed2ff
      */
 
-    omap_setup_dsp_mapping(omap15xx_dsp_mm);
+    omap_setup_dsp_mapping(system_memory, omap15xx_dsp_mm);
     omap_setup_mpui_io(system_memory, s);
 
     qemu_register_reset(omap1_mpu_reset, s);
commit 60fe76e3adc76e75ede173e469b642e9e493a741
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 29 14:14:06 2011 +0300

    omap1: convert to memory API (part IV)
    
    Acked-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/omap.h b/hw/omap.h
index 059b48f..25d10f3 100644
--- a/hw/omap.h
+++ b/hw/omap.h
@@ -841,6 +841,7 @@ struct omap_mpu_state_s {
     MemoryRegion clkdsp_iomem;
     MemoryRegion pwl_iomem;
     MemoryRegion pwt_iomem;
+    MemoryRegion mpui_io_iomem;
 
     struct omap_dma_port_if_s {
         uint32_t (*read[3])(struct omap_mpu_state_s *s,
diff --git a/hw/omap1.c b/hw/omap1.c
index fb22d75..df5d68b 100644
--- a/hw/omap1.c
+++ b/hw/omap1.c
@@ -3452,6 +3452,7 @@ void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, I2SCodec *slave)
 
 /* LED Pulse Generators */
 struct omap_lpg_s {
+    MemoryRegion iomem;
     QEMUTimer *tm;
 
     uint8_t control;
@@ -3516,11 +3517,16 @@ static void omap_lpg_reset(struct omap_lpg_s *s)
     omap_lpg_update(s);
 }
 
-static uint32_t omap_lpg_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_lpg_read(void *opaque, target_phys_addr_t addr,
+                              unsigned size)
 {
     struct omap_lpg_s *s = (struct omap_lpg_s *) opaque;
     int offset = addr & OMAP_MPUI_REG_MASK;
 
+    if (size != 1) {
+        return omap_badwidth_read8(opaque, addr);
+    }
+
     switch (offset) {
     case 0x00:	/* LCR */
         return s->control;
@@ -3534,11 +3540,15 @@ static uint32_t omap_lpg_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void omap_lpg_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                           uint64_t value, unsigned size)
 {
     struct omap_lpg_s *s = (struct omap_lpg_s *) opaque;
     int offset = addr & OMAP_MPUI_REG_MASK;
 
+    if (size != 1) {
+        return omap_badwidth_write8(opaque, addr, value);
+    }
+
     switch (offset) {
     case 0x00:	/* LCR */
         if (~value & (1 << 6))					/* LPGRES */
@@ -3558,16 +3568,10 @@ static void omap_lpg_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_lpg_readfn[] = {
-    omap_lpg_read,
-    omap_badwidth_read8,
-    omap_badwidth_read8,
-};
-
-static CPUWriteMemoryFunc * const omap_lpg_writefn[] = {
-    omap_lpg_write,
-    omap_badwidth_write8,
-    omap_badwidth_write8,
+static const MemoryRegionOps omap_lpg_ops = {
+    .read = omap_lpg_read,
+    .write = omap_lpg_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void omap_lpg_clk_update(void *opaque, int line, int on)
@@ -3578,9 +3582,9 @@ static void omap_lpg_clk_update(void *opaque, int line, int on)
     omap_lpg_update(s);
 }
 
-static struct omap_lpg_s *omap_lpg_init(target_phys_addr_t base, omap_clk clk)
+static struct omap_lpg_s *omap_lpg_init(MemoryRegion *system_memory,
+                                        target_phys_addr_t base, omap_clk clk)
 {
-    int iomemtype;
     struct omap_lpg_s *s = (struct omap_lpg_s *)
             g_malloc0(sizeof(struct omap_lpg_s));
 
@@ -3588,9 +3592,8 @@ 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, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x800, iomemtype);
+    memory_region_init_io(&s->iomem, &omap_lpg_ops, s, "omap-lpg", 0x800);
+    memory_region_add_subregion(system_memory, base, &s->iomem);
 
     omap_clk_adduser(clk, qemu_allocate_irqs(omap_lpg_clk_update, s, 1)[0]);
 
@@ -3598,8 +3601,13 @@ static struct omap_lpg_s *omap_lpg_init(target_phys_addr_t base, omap_clk clk)
 }
 
 /* MPUI Peripheral Bridge configuration */
-static uint32_t omap_mpui_io_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_mpui_io_read(void *opaque, target_phys_addr_t addr,
+                                  unsigned size)
 {
+    if (size != 2) {
+        return omap_badwidth_read16(opaque, addr);
+    }
+
     if (addr == OMAP_MPUI_BASE)	/* CMR */
         return 0xfe4d;
 
@@ -3607,23 +3615,26 @@ static uint32_t omap_mpui_io_read(void *opaque, target_phys_addr_t addr)
     return 0;
 }
 
-static CPUReadMemoryFunc * const omap_mpui_io_readfn[] = {
-    omap_badwidth_read16,
-    omap_mpui_io_read,
-    omap_badwidth_read16,
-};
+static void omap_mpui_io_write(void *opaque, target_phys_addr_t addr,
+                               uint64_t value, unsigned size)
+{
+    /* FIXME: infinite loop */
+    omap_badwidth_write16(opaque, addr, value);
+}
 
-static CPUWriteMemoryFunc * const omap_mpui_io_writefn[] = {
-    omap_badwidth_write16,
-    omap_badwidth_write16,
-    omap_badwidth_write16,
+static const MemoryRegionOps omap_mpui_io_ops = {
+    .read = omap_mpui_io_read,
+    .write = omap_mpui_io_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static void omap_setup_mpui_io(struct omap_mpu_state_s *mpu)
+static void omap_setup_mpui_io(MemoryRegion *system_memory,
+                               struct omap_mpu_state_s *mpu)
 {
-    int iomemtype = cpu_register_io_memory(omap_mpui_io_readfn,
-                    omap_mpui_io_writefn, mpu, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(OMAP_MPUI_BASE, 0x7fff, iomemtype);
+    memory_region_init_io(&mpu->mpui_io_iomem, &omap_mpui_io_ops, mpu,
+                          "omap-mpui-io", 0x7fff);
+    memory_region_add_subregion(system_memory, OMAP_MPUI_BASE,
+                                &mpu->mpui_io_iomem);
 }
 
 /* General chip reset */
@@ -3947,8 +3958,10 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
                     0xfffb7000, &s->irq[1][OMAP_INT_McBSP3TX],
                     &s->drq[OMAP_DMA_MCBSP3_TX], omap_findclk(s, "dspxor_ck"));
 
-    s->led[0] = omap_lpg_init(0xfffbd000, omap_findclk(s, "clk32-kHz"));
-    s->led[1] = omap_lpg_init(0xfffbd800, omap_findclk(s, "clk32-kHz"));
+    s->led[0] = omap_lpg_init(system_memory,
+                              0xfffbd000, omap_findclk(s, "clk32-kHz"));
+    s->led[1] = omap_lpg_init(system_memory,
+                              0xfffbd800, omap_findclk(s, "clk32-kHz"));
 
     /* Register mappings not currenlty implemented:
      * MCSI2 Comm	fffb2000 - fffb27ff (not mapped on OMAP310)
@@ -3966,7 +3979,7 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
      */
 
     omap_setup_dsp_mapping(omap15xx_dsp_mm);
-    omap_setup_mpui_io(s);
+    omap_setup_mpui_io(system_memory, s);
 
     qemu_register_reset(omap1_mpu_reset, s);
 
commit a4ebbd18b1985535eea14694cd86c6cd9dd9f0ad
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 29 14:14:06 2011 +0300

    omap1: convert to memory API (part III)
    
    Acked-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/omap.h b/hw/omap.h
index cb3b524..059b48f 100644
--- a/hw/omap.h
+++ b/hw/omap.h
@@ -692,7 +692,8 @@ struct uWireSlave {
     void *opaque;
 };
 struct omap_uwire_s;
-struct omap_uwire_s *omap_uwire_init(target_phys_addr_t base,
+struct omap_uwire_s *omap_uwire_init(MemoryRegion *system_memory,
+                target_phys_addr_t base,
                 qemu_irq *irq, qemu_irq dma, omap_clk clk);
 void omap_uwire_attach(struct omap_uwire_s *s,
                 uWireSlave *slave, int chipselect);
@@ -731,7 +732,8 @@ struct I2SCodec {
     } in, out;
 };
 struct omap_mcbsp_s;
-struct omap_mcbsp_s *omap_mcbsp_init(target_phys_addr_t base,
+struct omap_mcbsp_s *omap_mcbsp_init(MemoryRegion *system_memory,
+                target_phys_addr_t base,
                 qemu_irq *irq, qemu_irq *dma, omap_clk clk);
 void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, I2SCodec *slave);
 
@@ -837,6 +839,8 @@ struct omap_mpu_state_s {
     MemoryRegion tcmi_iomem;
     MemoryRegion clkm_iomem;
     MemoryRegion clkdsp_iomem;
+    MemoryRegion pwl_iomem;
+    MemoryRegion pwt_iomem;
 
     struct omap_dma_port_if_s {
         uint32_t (*read[3])(struct omap_mpu_state_s *s,
diff --git a/hw/omap1.c b/hw/omap1.c
index 05e38fc..fb22d75 100644
--- a/hw/omap1.c
+++ b/hw/omap1.c
@@ -2116,6 +2116,7 @@ void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down)
 
 /* MicroWire Interface */
 struct omap_uwire_s {
+    MemoryRegion iomem;
     qemu_irq txirq;
     qemu_irq rxirq;
     qemu_irq txdrq;
@@ -2153,11 +2154,16 @@ static void omap_uwire_transfer_start(struct omap_uwire_s *s)
     }
 }
 
-static uint32_t omap_uwire_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_uwire_read(void *opaque, target_phys_addr_t addr,
+                                unsigned size)
 {
     struct omap_uwire_s *s = (struct omap_uwire_s *) opaque;
     int offset = addr & OMAP_MPUI_REG_MASK;
 
+    if (size != 2) {
+        return omap_badwidth_read16(opaque, addr);
+    }
+
     switch (offset) {
     case 0x00:	/* RDR */
         s->control &= ~(1 << 15);			/* RDRB */
@@ -2183,11 +2189,15 @@ static uint32_t omap_uwire_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void omap_uwire_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                             uint64_t value, unsigned size)
 {
     struct omap_uwire_s *s = (struct omap_uwire_s *) opaque;
     int offset = addr & OMAP_MPUI_REG_MASK;
 
+    if (size != 2) {
+        return omap_badwidth_write16(opaque, addr, value);
+    }
+
     switch (offset) {
     case 0x00:	/* TDR */
         s->txbuf = value;				/* TD */
@@ -2231,16 +2241,10 @@ static void omap_uwire_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_uwire_readfn[] = {
-    omap_badwidth_read16,
-    omap_uwire_read,
-    omap_badwidth_read16,
-};
-
-static CPUWriteMemoryFunc * const omap_uwire_writefn[] = {
-    omap_badwidth_write16,
-    omap_uwire_write,
-    omap_badwidth_write16,
+static const MemoryRegionOps omap_uwire_ops = {
+    .read = omap_uwire_read,
+    .write = omap_uwire_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void omap_uwire_reset(struct omap_uwire_s *s)
@@ -2253,10 +2257,10 @@ static void omap_uwire_reset(struct omap_uwire_s *s)
     s->setup[4] = 0;
 }
 
-struct omap_uwire_s *omap_uwire_init(target_phys_addr_t base,
+struct omap_uwire_s *omap_uwire_init(MemoryRegion *system_memory,
+                target_phys_addr_t base,
                 qemu_irq *irq, qemu_irq dma, omap_clk clk)
 {
-    int iomemtype;
     struct omap_uwire_s *s = (struct omap_uwire_s *)
             g_malloc0(sizeof(struct omap_uwire_s));
 
@@ -2265,9 +2269,8 @@ struct omap_uwire_s *omap_uwire_init(target_phys_addr_t base,
     s->txdrq = dma;
     omap_uwire_reset(s);
 
-    iomemtype = cpu_register_io_memory(omap_uwire_readfn,
-                    omap_uwire_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x800, iomemtype);
+    memory_region_init_io(&s->iomem, &omap_uwire_ops, s, "omap-uwire", 0x800);
+    memory_region_add_subregion(system_memory, base, &s->iomem);
 
     return s;
 }
@@ -2294,11 +2297,16 @@ static void omap_pwl_update(struct omap_mpu_state_s *s)
     }
 }
 
-static uint32_t omap_pwl_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_pwl_read(void *opaque, target_phys_addr_t addr,
+                              unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
     int offset = addr & OMAP_MPUI_REG_MASK;
 
+    if (size != 1) {
+        return omap_badwidth_read8(opaque, addr);
+    }
+
     switch (offset) {
     case 0x00:	/* PWL_LEVEL */
         return s->pwl.level;
@@ -2310,11 +2318,15 @@ static uint32_t omap_pwl_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void omap_pwl_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                           uint64_t value, unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
     int offset = addr & OMAP_MPUI_REG_MASK;
 
+    if (size != 1) {
+        return omap_badwidth_write8(opaque, addr, value);
+    }
+
     switch (offset) {
     case 0x00:	/* PWL_LEVEL */
         s->pwl.level = value;
@@ -2330,16 +2342,10 @@ static void omap_pwl_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_pwl_readfn[] = {
-    omap_pwl_read,
-    omap_badwidth_read8,
-    omap_badwidth_read8,
-};
-
-static CPUWriteMemoryFunc * const omap_pwl_writefn[] = {
-    omap_pwl_write,
-    omap_badwidth_write8,
-    omap_badwidth_write8,
+static const MemoryRegionOps omap_pwl_ops = {
+    .read = omap_pwl_read,
+    .write = omap_pwl_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void omap_pwl_reset(struct omap_mpu_state_s *s)
@@ -2359,26 +2365,30 @@ static void omap_pwl_clk_update(void *opaque, int line, int on)
     omap_pwl_update(s);
 }
 
-static void omap_pwl_init(target_phys_addr_t base, struct omap_mpu_state_s *s,
+static void omap_pwl_init(MemoryRegion *system_memory,
+                target_phys_addr_t base, struct omap_mpu_state_s *s,
                 omap_clk clk)
 {
-    int iomemtype;
-
     omap_pwl_reset(s);
 
-    iomemtype = cpu_register_io_memory(omap_pwl_readfn,
-                    omap_pwl_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x800, iomemtype);
+    memory_region_init_io(&s->pwl_iomem, &omap_pwl_ops, s,
+                          "omap-pwl", 0x800);
+    memory_region_add_subregion(system_memory, base, &s->pwl_iomem);
 
     omap_clk_adduser(clk, qemu_allocate_irqs(omap_pwl_clk_update, s, 1)[0]);
 }
 
 /* Pulse-Width Tone module */
-static uint32_t omap_pwt_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_pwt_read(void *opaque, target_phys_addr_t addr,
+                              unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
     int offset = addr & OMAP_MPUI_REG_MASK;
 
+    if (size != 1) {
+        return omap_badwidth_read8(opaque, addr);
+    }
+
     switch (offset) {
     case 0x00:	/* FRC */
         return s->pwt.frc;
@@ -2392,11 +2402,15 @@ static uint32_t omap_pwt_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void omap_pwt_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                           uint64_t value, unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
     int offset = addr & OMAP_MPUI_REG_MASK;
 
+    if (size != 1) {
+        return omap_badwidth_write8(opaque, addr, value);
+    }
+
     switch (offset) {
     case 0x00:	/* FRC */
         s->pwt.frc = value & 0x3f;
@@ -2434,16 +2448,10 @@ static void omap_pwt_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_pwt_readfn[] = {
-    omap_pwt_read,
-    omap_badwidth_read8,
-    omap_badwidth_read8,
-};
-
-static CPUWriteMemoryFunc * const omap_pwt_writefn[] = {
-    omap_pwt_write,
-    omap_badwidth_write8,
-    omap_badwidth_write8,
+static const MemoryRegionOps omap_pwt_ops = {
+    .read =omap_pwt_read,
+    .write = omap_pwt_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void omap_pwt_reset(struct omap_mpu_state_s *s)
@@ -2453,21 +2461,21 @@ static void omap_pwt_reset(struct omap_mpu_state_s *s)
     s->pwt.gcr = 0;
 }
 
-static void omap_pwt_init(target_phys_addr_t base, struct omap_mpu_state_s *s,
+static void omap_pwt_init(MemoryRegion *system_memory,
+                target_phys_addr_t base, struct omap_mpu_state_s *s,
                 omap_clk clk)
 {
-    int iomemtype;
-
     s->pwt.clk = clk;
     omap_pwt_reset(s);
 
-    iomemtype = cpu_register_io_memory(omap_pwt_readfn,
-                    omap_pwt_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x800, iomemtype);
+    memory_region_init_io(&s->pwt_iomem, &omap_pwt_ops, s,
+                          "omap-pwt", 0x800);
+    memory_region_add_subregion(system_memory, base, &s->pwt_iomem);
 }
 
 /* Real-time Clock module */
 struct omap_rtc_s {
+    MemoryRegion iomem;
     qemu_irq irq;
     qemu_irq alarm;
     QEMUTimer *clk;
@@ -2500,12 +2508,17 @@ static void omap_rtc_alarm_update(struct omap_rtc_s *s)
         printf("%s: conversion failed\n", __FUNCTION__);
 }
 
-static uint32_t omap_rtc_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_rtc_read(void *opaque, target_phys_addr_t addr,
+                              unsigned size)
 {
     struct omap_rtc_s *s = (struct omap_rtc_s *) opaque;
     int offset = addr & OMAP_MPUI_REG_MASK;
     uint8_t i;
 
+    if (size != 1) {
+        return omap_badwidth_read8(opaque, addr);
+    }
+
     switch (offset) {
     case 0x00:	/* SECONDS_REG */
         return to_bcd(s->current_tm.tm_sec);
@@ -2578,13 +2591,17 @@ static uint32_t omap_rtc_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void omap_rtc_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                           uint64_t value, unsigned size)
 {
     struct omap_rtc_s *s = (struct omap_rtc_s *) opaque;
     int offset = addr & OMAP_MPUI_REG_MASK;
     struct tm new_tm;
     time_t ti[2];
 
+    if (size != 1) {
+        return omap_badwidth_write8(opaque, addr, value);
+    }
+
     switch (offset) {
     case 0x00:	/* SECONDS_REG */
 #ifdef ALMDEBUG
@@ -2765,16 +2782,10 @@ static void omap_rtc_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_rtc_readfn[] = {
-    omap_rtc_read,
-    omap_badwidth_read8,
-    omap_badwidth_read8,
-};
-
-static CPUWriteMemoryFunc * const omap_rtc_writefn[] = {
-    omap_rtc_write,
-    omap_badwidth_write8,
-    omap_badwidth_write8,
+static const MemoryRegionOps omap_rtc_ops = {
+    .read = omap_rtc_read,
+    .write = omap_rtc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void omap_rtc_tick(void *opaque)
@@ -2861,10 +2872,10 @@ static void omap_rtc_reset(struct omap_rtc_s *s)
     omap_rtc_tick(s);
 }
 
-static struct omap_rtc_s *omap_rtc_init(target_phys_addr_t base,
+static struct omap_rtc_s *omap_rtc_init(MemoryRegion *system_memory,
+                target_phys_addr_t base,
                 qemu_irq *irq, omap_clk clk)
 {
-    int iomemtype;
     struct omap_rtc_s *s = (struct omap_rtc_s *)
             g_malloc0(sizeof(struct omap_rtc_s));
 
@@ -2874,15 +2885,16 @@ 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, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x800, iomemtype);
+    memory_region_init_io(&s->iomem, &omap_rtc_ops, s,
+                          "omap-rtc", 0x800);
+    memory_region_add_subregion(system_memory, base, &s->iomem);
 
     return s;
 }
 
 /* Multi-channel Buffered Serial Port interfaces */
 struct omap_mcbsp_s {
+    MemoryRegion iomem;
     qemu_irq txirq;
     qemu_irq rxirq;
     qemu_irq txdrq;
@@ -3088,12 +3100,17 @@ static void omap_mcbsp_req_update(struct omap_mcbsp_s *s)
         omap_mcbsp_rx_stop(s);
 }
 
-static uint32_t omap_mcbsp_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_mcbsp_read(void *opaque, target_phys_addr_t addr,
+                                unsigned size)
 {
     struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque;
     int offset = addr & OMAP_MPUI_REG_MASK;
     uint16_t ret;
 
+    if (size != 2) {
+        return omap_badwidth_read16(opaque, addr);
+    }
+
     switch (offset) {
     case 0x00:	/* DRR2 */
         if (((s->rcr[0] >> 5) & 7) < 3)			/* RWDLEN1 */
@@ -3350,16 +3367,20 @@ static void omap_mcbsp_writew(void *opaque, target_phys_addr_t addr,
     omap_badwidth_write16(opaque, addr, value);
 }
 
-static CPUReadMemoryFunc * const omap_mcbsp_readfn[] = {
-    omap_badwidth_read16,
-    omap_mcbsp_read,
-    omap_badwidth_read16,
-};
+static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr,
+                             uint64_t value, unsigned size)
+{
+    switch (size) {
+    case 2: return omap_mcbsp_writeh(opaque, addr, value);
+    case 4: return omap_mcbsp_writew(opaque, addr, value);
+    default: return omap_badwidth_write16(opaque, addr, value);
+    }
+}
 
-static CPUWriteMemoryFunc * const omap_mcbsp_writefn[] = {
-    omap_badwidth_write16,
-    omap_mcbsp_writeh,
-    omap_mcbsp_writew,
+static const MemoryRegionOps omap_mcbsp_ops = {
+    .read = omap_mcbsp_read,
+    .write = omap_mcbsp_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void omap_mcbsp_reset(struct omap_mcbsp_s *s)
@@ -3381,10 +3402,10 @@ static void omap_mcbsp_reset(struct omap_mcbsp_s *s)
     qemu_del_timer(s->sink_timer);
 }
 
-struct omap_mcbsp_s *omap_mcbsp_init(target_phys_addr_t base,
+struct omap_mcbsp_s *omap_mcbsp_init(MemoryRegion *system_memory,
+                target_phys_addr_t base,
                 qemu_irq *irq, qemu_irq *dma, omap_clk clk)
 {
-    int iomemtype;
     struct omap_mcbsp_s *s = (struct omap_mcbsp_s *)
             g_malloc0(sizeof(struct omap_mcbsp_s));
 
@@ -3396,9 +3417,8 @@ struct omap_mcbsp_s *omap_mcbsp_init(target_phys_addr_t base,
     s->source_timer = qemu_new_timer_ns(vm_clock, omap_mcbsp_source_tick, s);
     omap_mcbsp_reset(s);
 
-    iomemtype = cpu_register_io_memory(omap_mcbsp_readfn,
-                    omap_mcbsp_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x800, iomemtype);
+    memory_region_init_io(&s->iomem, &omap_mcbsp_ops, s, "omap-mcbsp", 0x800);
+    memory_region_add_subregion(system_memory, base, &s->iomem);
 
     return s;
 }
@@ -3903,23 +3923,28 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
                     s->irq[0][OMAP_INT_GPIO_BANK1]);
     sysbus_mmio_map(sysbus_from_qdev(s->gpio), 0, 0xfffce000);
 
-    s->microwire = omap_uwire_init(0xfffb3000, &s->irq[1][OMAP_INT_uWireTX],
+    s->microwire = omap_uwire_init(system_memory,
+                    0xfffb3000, &s->irq[1][OMAP_INT_uWireTX],
                     s->drq[OMAP_DMA_UWIRE_TX], omap_findclk(s, "mpuper_ck"));
 
-    omap_pwl_init(0xfffb5800, s, omap_findclk(s, "armxor_ck"));
-    omap_pwt_init(0xfffb6000, s, omap_findclk(s, "armxor_ck"));
+    omap_pwl_init(system_memory, 0xfffb5800, s, omap_findclk(s, "armxor_ck"));
+    omap_pwt_init(system_memory, 0xfffb6000, s, omap_findclk(s, "armxor_ck"));
 
     s->i2c[0] = omap_i2c_init(0xfffb3800, s->irq[1][OMAP_INT_I2C],
                     &s->drq[OMAP_DMA_I2C_RX], omap_findclk(s, "mpuper_ck"));
 
-    s->rtc = omap_rtc_init(0xfffb4800, &s->irq[1][OMAP_INT_RTC_TIMER],
+    s->rtc = omap_rtc_init(system_memory, 0xfffb4800,
+                    &s->irq[1][OMAP_INT_RTC_TIMER],
                     omap_findclk(s, "clk32-kHz"));
 
-    s->mcbsp1 = omap_mcbsp_init(0xfffb1800, &s->irq[1][OMAP_INT_McBSP1TX],
+    s->mcbsp1 = omap_mcbsp_init(system_memory,
+                    0xfffb1800, &s->irq[1][OMAP_INT_McBSP1TX],
                     &s->drq[OMAP_DMA_MCBSP1_TX], omap_findclk(s, "dspxor_ck"));
-    s->mcbsp2 = omap_mcbsp_init(0xfffb1000, &s->irq[0][OMAP_INT_310_McBSP2_TX],
+    s->mcbsp2 = omap_mcbsp_init(system_memory,
+                    0xfffb1000, &s->irq[0][OMAP_INT_310_McBSP2_TX],
                     &s->drq[OMAP_DMA_MCBSP2_TX], omap_findclk(s, "mpuper_ck"));
-    s->mcbsp3 = omap_mcbsp_init(0xfffb7000, &s->irq[1][OMAP_INT_McBSP3TX],
+    s->mcbsp3 = omap_mcbsp_init(system_memory,
+                    0xfffb7000, &s->irq[1][OMAP_INT_McBSP3TX],
                     &s->drq[OMAP_DMA_MCBSP3_TX], omap_findclk(s, "dspxor_ck"));
 
     s->led[0] = omap_lpg_init(0xfffbd000, omap_findclk(s, "clk32-kHz"));
commit e7aa0ae03402c4ee2ee25e675d440f0bdc4f4b97
Author: Avi Kivity <avi at redhat.com>
Date:   Tue Aug 9 19:35:00 2011 +0300

    omap1: convert to memory API (part II)
    
    Acked-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/omap.h b/hw/omap.h
index eec8f04..cb3b524 100644
--- a/hw/omap.h
+++ b/hw/omap.h
@@ -678,7 +678,8 @@ void omap_uart_reset(struct omap_uart_s *s);
 void omap_uart_attach(struct omap_uart_s *s, CharDriverState *chr);
 
 struct omap_mpuio_s;
-struct omap_mpuio_s *omap_mpuio_init(target_phys_addr_t base,
+struct omap_mpuio_s *omap_mpuio_init(MemoryRegion *system_memory,
+                target_phys_addr_t base,
                 qemu_irq kbd_int, qemu_irq gpio_int, qemu_irq wakeup,
                 omap_clk clk);
 qemu_irq *omap_mpuio_in_get(struct omap_mpuio_s *s);
@@ -833,6 +834,9 @@ struct omap_mpu_state_s {
     MemoryRegion id_iomem_ed4;
     MemoryRegion id_iomem_e20;
     MemoryRegion mpui_iomem;
+    MemoryRegion tcmi_iomem;
+    MemoryRegion clkm_iomem;
+    MemoryRegion clkdsp_iomem;
 
     struct omap_dma_port_if_s {
         uint32_t (*read[3])(struct omap_mpu_state_s *s,
@@ -915,6 +919,7 @@ struct omap_mpu_state_s {
     uint32_t tcmi_regs[17];
 
     struct dpll_ctl_s {
+        MemoryRegion iomem;
         uint16_t mode;
         omap_clk dpll;
     } dpll[3];
diff --git a/hw/omap1.c b/hw/omap1.c
index 0f7e14f..05e38fc 100644
--- a/hw/omap1.c
+++ b/hw/omap1.c
@@ -1236,11 +1236,16 @@ static struct omap_tipb_bridge_s *omap_tipb_bridge_init(
 }
 
 /* Dummy Traffic Controller's Memory Interface */
-static uint32_t omap_tcmi_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_tcmi_read(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
     uint32_t ret;
 
+    if (size != 4) {
+        return omap_badwidth_read32(opaque, addr);
+    }
+
     switch (addr) {
     case 0x00:	/* IMIF_PRIO */
     case 0x04:	/* EMIFS_PRIO */
@@ -1270,10 +1275,14 @@ static uint32_t omap_tcmi_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void omap_tcmi_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                            uint64_t value, unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
 
+    if (size != 4) {
+        return omap_badwidth_write32(opaque, addr, value);
+    }
+
     switch (addr) {
     case 0x00:	/* IMIF_PRIO */
     case 0x04:	/* EMIFS_PRIO */
@@ -1300,16 +1309,10 @@ static void omap_tcmi_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_tcmi_readfn[] = {
-    omap_badwidth_read32,
-    omap_badwidth_read32,
-    omap_tcmi_read,
-};
-
-static CPUWriteMemoryFunc * const omap_tcmi_writefn[] = {
-    omap_badwidth_write32,
-    omap_badwidth_write32,
-    omap_tcmi_write,
+static const MemoryRegionOps omap_tcmi_ops = {
+    .read = omap_tcmi_read,
+    .write = omap_tcmi_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void omap_tcmi_reset(struct omap_mpu_state_s *mpu)
@@ -1331,21 +1334,25 @@ static void omap_tcmi_reset(struct omap_mpu_state_s *mpu)
     mpu->tcmi_regs[0x40 >> 2] = 0x00000000;
 }
 
-static void omap_tcmi_init(target_phys_addr_t base,
+static void omap_tcmi_init(MemoryRegion *memory, target_phys_addr_t base,
                 struct omap_mpu_state_s *mpu)
 {
-    int iomemtype = cpu_register_io_memory(omap_tcmi_readfn,
-                    omap_tcmi_writefn, mpu, DEVICE_NATIVE_ENDIAN);
-
-    cpu_register_physical_memory(base, 0x100, iomemtype);
+    memory_region_init_io(&mpu->tcmi_iomem, &omap_tcmi_ops, mpu,
+                          "omap-tcmi", 0x100);
+    memory_region_add_subregion(memory, base, &mpu->tcmi_iomem);
     omap_tcmi_reset(mpu);
 }
 
 /* Digital phase-locked loops control */
-static uint32_t omap_dpll_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_dpll_read(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
 {
     struct dpll_ctl_s *s = (struct dpll_ctl_s *) opaque;
 
+    if (size != 2) {
+        return omap_badwidth_read16(opaque, addr);
+    }
+
     if (addr == 0x00)	/* CTL_REG */
         return s->mode;
 
@@ -1354,13 +1361,17 @@ static uint32_t omap_dpll_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void omap_dpll_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                            uint64_t value, unsigned size)
 {
     struct dpll_ctl_s *s = (struct dpll_ctl_s *) opaque;
     uint16_t diff;
     static const int bypass_div[4] = { 1, 2, 4, 4 };
     int div, mult;
 
+    if (size != 2) {
+        return omap_badwidth_write16(opaque, addr, value);
+    }
+
     if (addr == 0x00) {	/* CTL_REG */
         /* See omap_ulpd_pm_write() too */
         diff = s->mode & value;
@@ -1386,16 +1397,10 @@ static void omap_dpll_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_dpll_readfn[] = {
-    omap_badwidth_read16,
-    omap_dpll_read,
-    omap_badwidth_read16,
-};
-
-static CPUWriteMemoryFunc * const omap_dpll_writefn[] = {
-    omap_badwidth_write16,
-    omap_dpll_write,
-    omap_badwidth_write16,
+static const MemoryRegionOps omap_dpll_ops = {
+    .read = omap_dpll_read,
+    .write = omap_dpll_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void omap_dpll_reset(struct dpll_ctl_s *s)
@@ -1404,23 +1409,27 @@ static void omap_dpll_reset(struct dpll_ctl_s *s)
     omap_clk_setrate(s->dpll, 1, 1);
 }
 
-static void omap_dpll_init(struct dpll_ctl_s *s, target_phys_addr_t base,
-                omap_clk clk)
+static void omap_dpll_init(MemoryRegion *memory, 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, DEVICE_NATIVE_ENDIAN);
+    memory_region_init_io(&s->iomem, &omap_dpll_ops, s, "omap-dpll", 0x100);
 
     s->dpll = clk;
     omap_dpll_reset(s);
 
-    cpu_register_physical_memory(base, 0x100, iomemtype);
+    memory_region_add_subregion(memory, base, &s->iomem);
 }
 
 /* MPU Clock/Reset/Power Mode Control */
-static uint32_t omap_clkm_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_clkm_read(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
 
+    if (size != 2) {
+        return omap_badwidth_read16(opaque, addr);
+    }
+
     switch (addr) {
     case 0x00:	/* ARM_CKCTL */
         return s->clkm.arm_ckctl;
@@ -1614,7 +1623,7 @@ static inline void omap_clkm_ckout1_update(struct omap_mpu_state_s *s,
 }
 
 static void omap_clkm_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                            uint64_t value, unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
     uint16_t diff;
@@ -1624,6 +1633,10 @@ static void omap_clkm_write(void *opaque, target_phys_addr_t addr,
         "mix mode 1", "mix mode 2", "bypass mode", "mix mode 3", "mix mode 4",
     };
 
+    if (size != 2) {
+        return omap_badwidth_write16(opaque, addr, value);
+    }
+
     switch (addr) {
     case 0x00:	/* ARM_CKCTL */
         diff = s->clkm.arm_ckctl ^ value;
@@ -1690,22 +1703,21 @@ static void omap_clkm_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_clkm_readfn[] = {
-    omap_badwidth_read16,
-    omap_clkm_read,
-    omap_badwidth_read16,
-};
-
-static CPUWriteMemoryFunc * const omap_clkm_writefn[] = {
-    omap_badwidth_write16,
-    omap_clkm_write,
-    omap_badwidth_write16,
+static const MemoryRegionOps omap_clkm_ops = {
+    .read = omap_clkm_read,
+    .write = omap_clkm_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static uint32_t omap_clkdsp_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_clkdsp_read(void *opaque, target_phys_addr_t addr,
+                                 unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
 
+    if (size != 2) {
+        return omap_badwidth_read16(opaque, addr);
+    }
+
     switch (addr) {
     case 0x04:	/* DSP_IDLECT1 */
         return s->clkm.dsp_idlect1;
@@ -1742,11 +1754,15 @@ static inline void omap_clkdsp_idlect2_update(struct omap_mpu_state_s *s,
 }
 
 static void omap_clkdsp_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                              uint64_t value, unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
     uint16_t diff;
 
+    if (size != 2) {
+        return omap_badwidth_write16(opaque, addr, value);
+    }
+
     switch (addr) {
     case 0x04:	/* DSP_IDLECT1 */
         diff = s->clkm.dsp_idlect1 ^ value;
@@ -1773,16 +1789,10 @@ static void omap_clkdsp_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_clkdsp_readfn[] = {
-    omap_badwidth_read16,
-    omap_clkdsp_read,
-    omap_badwidth_read16,
-};
-
-static CPUWriteMemoryFunc * const omap_clkdsp_writefn[] = {
-    omap_badwidth_write16,
-    omap_clkdsp_write,
-    omap_badwidth_write16,
+static const MemoryRegionOps omap_clkdsp_ops = {
+    .read = omap_clkdsp_read,
+    .write = omap_clkdsp_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void omap_clkm_reset(struct omap_mpu_state_s *s)
@@ -1808,15 +1818,13 @@ static void omap_clkm_reset(struct omap_mpu_state_s *s)
     s->clkm.dsp_rstct2 = 0x0000;
 }
 
-static void omap_clkm_init(target_phys_addr_t mpu_base,
+static void omap_clkm_init(MemoryRegion *memory, 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,
-                               DEVICE_NATIVE_ENDIAN),
-        cpu_register_io_memory(omap_clkdsp_readfn, omap_clkdsp_writefn, s,
-                               DEVICE_NATIVE_ENDIAN),
-    };
+    memory_region_init_io(&s->clkm_iomem, &omap_clkm_ops, s,
+                          "omap-clkm", 0x100);
+    memory_region_init_io(&s->clkdsp_iomem, &omap_clkdsp_ops, s,
+                          "omap-clkdsp", 0x1000);
 
     s->clkm.arm_idlect1 = 0x03ff;
     s->clkm.arm_idlect2 = 0x0100;
@@ -1824,8 +1832,8 @@ static void omap_clkm_init(target_phys_addr_t mpu_base,
     omap_clkm_reset(s);
     s->clkm.cold_start = 0x3a;
 
-    cpu_register_physical_memory(mpu_base, 0x100, iomemtype[0]);
-    cpu_register_physical_memory(dsp_base, 0x1000, iomemtype[1]);
+    memory_region_add_subregion(memory, mpu_base, &s->clkm_iomem);
+    memory_region_add_subregion(memory, dsp_base, &s->clkdsp_iomem);
 }
 
 /* MPU I/O */
@@ -1835,6 +1843,7 @@ struct omap_mpuio_s {
     qemu_irq *in;
     qemu_irq handler[16];
     qemu_irq wakeup;
+    MemoryRegion iomem;
 
     uint16_t inputs;
     uint16_t outputs;
@@ -1889,12 +1898,17 @@ static void omap_mpuio_kbd_update(struct omap_mpuio_s *s)
     s->row_latch = ~rows;
 }
 
-static uint32_t omap_mpuio_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_mpuio_read(void *opaque, target_phys_addr_t addr,
+                                unsigned size)
 {
     struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque;
     int offset = addr & OMAP_MPUI_REG_MASK;
     uint16_t ret;
 
+    if (size != 2) {
+        return omap_badwidth_read16(opaque, addr);
+    }
+
     switch (offset) {
     case 0x00:	/* INPUT_LATCH */
         return s->inputs;
@@ -1945,13 +1959,17 @@ static uint32_t omap_mpuio_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void omap_mpuio_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                             uint64_t value, unsigned size)
 {
     struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque;
     int offset = addr & OMAP_MPUI_REG_MASK;
     uint16_t diff;
     int ln;
 
+    if (size != 2) {
+        return omap_badwidth_write16(opaque, addr, value);
+    }
+
     switch (offset) {
     case 0x04:	/* OUTPUT_REG */
         diff = (s->outputs ^ value) & ~s->dir;
@@ -2017,16 +2035,10 @@ static void omap_mpuio_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_mpuio_readfn[] = {
-    omap_badwidth_read16,
-    omap_mpuio_read,
-    omap_badwidth_read16,
-};
-
-static CPUWriteMemoryFunc * const omap_mpuio_writefn[] = {
-    omap_badwidth_write16,
-    omap_mpuio_write,
-    omap_badwidth_write16,
+static const MemoryRegionOps omap_mpuio_ops  = {
+    .read = omap_mpuio_read,
+    .write = omap_mpuio_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void omap_mpuio_reset(struct omap_mpuio_s *s)
@@ -2054,11 +2066,11 @@ static void omap_mpuio_onoff(void *opaque, int line, int on)
         omap_mpuio_kbd_update(s);
 }
 
-struct omap_mpuio_s *omap_mpuio_init(target_phys_addr_t base,
+struct omap_mpuio_s *omap_mpuio_init(MemoryRegion *memory,
+                target_phys_addr_t base,
                 qemu_irq kbd_int, qemu_irq gpio_int, qemu_irq wakeup,
                 omap_clk clk)
 {
-    int iomemtype;
     struct omap_mpuio_s *s = (struct omap_mpuio_s *)
             g_malloc0(sizeof(struct omap_mpuio_s));
 
@@ -2068,9 +2080,9 @@ struct omap_mpuio_s *omap_mpuio_init(target_phys_addr_t base,
     s->in = qemu_allocate_irqs(omap_mpuio_set, s, 16);
     omap_mpuio_reset(s);
 
-    iomemtype = cpu_register_io_memory(omap_mpuio_readfn,
-                    omap_mpuio_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x800, iomemtype);
+    memory_region_init_io(&s->iomem, &omap_mpuio_ops, s,
+                          "omap-mpuio", 0x800);
+    memory_region_add_subregion(memory, base, &s->iomem);
 
     omap_clk_adduser(clk, qemu_allocate_irqs(omap_mpuio_onoff, s, 1)[0]);
 
@@ -3779,7 +3791,7 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
                     (imif_base = qemu_ram_alloc(NULL, "omap1.sram",
                                                 s->sram_size)) | IO_MEM_RAM);
 
-    omap_clkm_init(0xfffece00, 0xe1008000, s);
+    omap_clkm_init(system_memory, 0xfffece00, 0xe1008000, s);
 
     cpu_irq = arm_pic_init_cpu(s->env);
     s->ih[0] = omap_inth_init(0xfffecb00, 0x100, 1, &s->irq[0],
@@ -3843,7 +3855,7 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
                     s->irq[0][OMAP_INT_BRIDGE_PUB],
                     omap_findclk(s, "tipb_ck"));
 
-    omap_tcmi_init(0xfffecc00, s);
+    omap_tcmi_init(system_memory, 0xfffecc00, s);
 
     s->uart[0] = omap_uart_init(0xfffb0000, s->irq[1][OMAP_INT_UART1],
                     omap_findclk(s, "uart1_ck"),
@@ -3864,9 +3876,12 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
                     "uart3",
                     serial_hds[0] && serial_hds[1] ? serial_hds[2] : NULL);
 
-    omap_dpll_init(&s->dpll[0], 0xfffecf00, omap_findclk(s, "dpll1"));
-    omap_dpll_init(&s->dpll[1], 0xfffed000, omap_findclk(s, "dpll2"));
-    omap_dpll_init(&s->dpll[2], 0xfffed100, omap_findclk(s, "dpll3"));
+    omap_dpll_init(system_memory,
+                   &s->dpll[0], 0xfffecf00, omap_findclk(s, "dpll1"));
+    omap_dpll_init(system_memory,
+                   &s->dpll[1], 0xfffed000, omap_findclk(s, "dpll2"));
+    omap_dpll_init(system_memory,
+                   &s->dpll[2], 0xfffed100, omap_findclk(s, "dpll3"));
 
     dinfo = drive_get(IF_SD, 0, 0);
     if (!dinfo) {
@@ -3877,7 +3892,7 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
                     s->irq[1][OMAP_INT_OQN], &s->drq[OMAP_DMA_MMC_TX],
                     omap_findclk(s, "mmc_ck"));
 
-    s->mpuio = omap_mpuio_init(0xfffb5000,
+    s->mpuio = omap_mpuio_init(system_memory, 0xfffb5000,
                     s->irq[1][OMAP_INT_KEYBOARD], s->irq[1][OMAP_INT_MPUIO],
                     s->wakeup, omap_findclk(s, "clk32-kHz"));
 
commit 4b3fedf3a580fbd3dccaca80feaedbda2510d77c
Author: Avi Kivity <avi at redhat.com>
Date:   Tue Aug 9 19:35:00 2011 +0300

    omap1: convert to memory API (part I)
    
    Acked-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/omap.h b/hw/omap.h
index d9ab006..eec8f04 100644
--- a/hw/omap.h
+++ b/hw/omap.h
@@ -826,6 +826,14 @@ struct omap_mpu_state_s {
 
     qemu_irq wakeup;
 
+    MemoryRegion ulpd_pm_iomem;
+    MemoryRegion pin_cfg_iomem;
+    MemoryRegion id_iomem;
+    MemoryRegion id_iomem_e18;
+    MemoryRegion id_iomem_ed4;
+    MemoryRegion id_iomem_e20;
+    MemoryRegion mpui_iomem;
+
     struct omap_dma_port_if_s {
         uint32_t (*read[3])(struct omap_mpu_state_s *s,
                         target_phys_addr_t offset);
@@ -947,7 +955,8 @@ struct omap_mpu_state_s {
 };
 
 /* omap1.c */
-struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
+struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
+                unsigned long sdram_size,
                 const char *core);
 
 /* omap2.c */
diff --git a/hw/omap1.c b/hw/omap1.c
index 614fd31..0f7e14f 100644
--- a/hw/omap1.c
+++ b/hw/omap1.c
@@ -84,6 +84,7 @@ void omap_badwidth_write32(void *opaque, target_phys_addr_t addr,
 
 /* MPU OS timers */
 struct omap_mpu_timer_s {
+    MemoryRegion iomem;
     qemu_irq irq;
     omap_clk clk;
     uint32_t val;
@@ -179,10 +180,15 @@ static void omap_timer_clk_setup(struct omap_mpu_timer_s *timer)
     timer->rate = omap_clk_getrate(timer->clk);
 }
 
-static uint32_t omap_mpu_timer_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_mpu_timer_read(void *opaque, target_phys_addr_t addr,
+                                    unsigned size)
 {
     struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) opaque;
 
+    if (size != 4) {
+        return omap_badwidth_read32(opaque, addr);
+    }
+
     switch (addr) {
     case 0x00:	/* CNTL_TIMER */
         return (s->enable << 5) | (s->ptv << 2) | (s->ar << 1) | s->st;
@@ -199,10 +205,14 @@ static uint32_t omap_mpu_timer_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void omap_mpu_timer_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                                 uint64_t value, unsigned size)
 {
     struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) opaque;
 
+    if (size != 4) {
+        return omap_badwidth_write32(opaque, addr, value);
+    }
+
     switch (addr) {
     case 0x00:	/* CNTL_TIMER */
         omap_timer_sync(s);
@@ -226,16 +236,10 @@ static void omap_mpu_timer_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_mpu_timer_readfn[] = {
-    omap_badwidth_read32,
-    omap_badwidth_read32,
-    omap_mpu_timer_read,
-};
-
-static CPUWriteMemoryFunc * const omap_mpu_timer_writefn[] = {
-    omap_badwidth_write32,
-    omap_badwidth_write32,
-    omap_mpu_timer_write,
+static const MemoryRegionOps omap_mpu_timer_ops = {
+    .read = omap_mpu_timer_read,
+    .write = omap_mpu_timer_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
 static void omap_mpu_timer_reset(struct omap_mpu_timer_s *s)
@@ -250,10 +254,10 @@ static void omap_mpu_timer_reset(struct omap_mpu_timer_s *s)
     s->it_ena = 1;
 }
 
-static struct omap_mpu_timer_s *omap_mpu_timer_init(target_phys_addr_t base,
+static struct omap_mpu_timer_s *omap_mpu_timer_init(MemoryRegion *system_memory,
+                target_phys_addr_t base,
                 qemu_irq irq, omap_clk clk)
 {
-    int iomemtype;
     struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *)
             g_malloc0(sizeof(struct omap_mpu_timer_s));
 
@@ -264,9 +268,10 @@ static struct omap_mpu_timer_s *omap_mpu_timer_init(target_phys_addr_t base,
     omap_mpu_timer_reset(s);
     omap_timer_clk_setup(s);
 
-    iomemtype = cpu_register_io_memory(omap_mpu_timer_readfn,
-                    omap_mpu_timer_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x100, iomemtype);
+    memory_region_init_io(&s->iomem, &omap_mpu_timer_ops, s,
+                          "omap-mpu-timer", 0x100);
+
+    memory_region_add_subregion(system_memory, base, &s->iomem);
 
     return s;
 }
@@ -274,16 +279,22 @@ static struct omap_mpu_timer_s *omap_mpu_timer_init(target_phys_addr_t base,
 /* Watchdog timer */
 struct omap_watchdog_timer_s {
     struct omap_mpu_timer_s timer;
+    MemoryRegion iomem;
     uint8_t last_wr;
     int mode;
     int free;
     int reset;
 };
 
-static uint32_t omap_wd_timer_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_wd_timer_read(void *opaque, target_phys_addr_t addr,
+                                   unsigned size)
 {
     struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) opaque;
 
+    if (size != 2) {
+        return omap_badwidth_read16(opaque, addr);
+    }
+
     switch (addr) {
     case 0x00:	/* CNTL_TIMER */
         return (s->timer.ptv << 9) | (s->timer.ar << 8) |
@@ -301,10 +312,14 @@ static uint32_t omap_wd_timer_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void omap_wd_timer_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                                uint64_t value, unsigned size)
 {
     struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) opaque;
 
+    if (size != 2) {
+        return omap_badwidth_write16(opaque, addr, value);
+    }
+
     switch (addr) {
     case 0x00:	/* CNTL_TIMER */
         omap_timer_sync(&s->timer);
@@ -344,16 +359,10 @@ static void omap_wd_timer_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_wd_timer_readfn[] = {
-    omap_badwidth_read16,
-    omap_wd_timer_read,
-    omap_badwidth_read16,
-};
-
-static CPUWriteMemoryFunc * const omap_wd_timer_writefn[] = {
-    omap_badwidth_write16,
-    omap_wd_timer_write,
-    omap_badwidth_write16,
+static const MemoryRegionOps omap_wd_timer_ops = {
+    .read = omap_wd_timer_read,
+    .write = omap_wd_timer_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void omap_wd_timer_reset(struct omap_watchdog_timer_s *s)
@@ -374,10 +383,10 @@ static void omap_wd_timer_reset(struct omap_watchdog_timer_s *s)
     omap_timer_update(&s->timer);
 }
 
-static struct omap_watchdog_timer_s *omap_wd_timer_init(target_phys_addr_t base,
+static struct omap_watchdog_timer_s *omap_wd_timer_init(MemoryRegion *memory,
+                target_phys_addr_t base,
                 qemu_irq irq, omap_clk clk)
 {
-    int iomemtype;
     struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *)
             g_malloc0(sizeof(struct omap_watchdog_timer_s));
 
@@ -387,9 +396,9 @@ static struct omap_watchdog_timer_s *omap_wd_timer_init(target_phys_addr_t base,
     omap_wd_timer_reset(s);
     omap_timer_clk_setup(&s->timer);
 
-    iomemtype = cpu_register_io_memory(omap_wd_timer_readfn,
-                    omap_wd_timer_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x100, iomemtype);
+    memory_region_init_io(&s->iomem, &omap_wd_timer_ops, s,
+                          "omap-wd-timer", 0x100);
+    memory_region_add_subregion(memory, base, &s->iomem);
 
     return s;
 }
@@ -397,13 +406,19 @@ static struct omap_watchdog_timer_s *omap_wd_timer_init(target_phys_addr_t base,
 /* 32-kHz timer */
 struct omap_32khz_timer_s {
     struct omap_mpu_timer_s timer;
+    MemoryRegion iomem;
 };
 
-static uint32_t omap_os_timer_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_os_timer_read(void *opaque, target_phys_addr_t addr,
+                                   unsigned size)
 {
     struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque;
     int offset = addr & OMAP_MPUI_REG_MASK;
 
+    if (size != 4) {
+        return omap_badwidth_read32(opaque, addr);
+    }
+
     switch (offset) {
     case 0x00:	/* TVR */
         return s->timer.reset_val;
@@ -422,11 +437,15 @@ static uint32_t omap_os_timer_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void omap_os_timer_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                                uint64_t value, unsigned size)
 {
     struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque;
     int offset = addr & OMAP_MPUI_REG_MASK;
 
+    if (size != 4) {
+        return omap_badwidth_write32(opaque, addr, value);
+    }
+
     switch (offset) {
     case 0x00:	/* TVR */
         s->timer.reset_val = value & 0x00ffffff;
@@ -452,16 +471,10 @@ static void omap_os_timer_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_os_timer_readfn[] = {
-    omap_badwidth_read32,
-    omap_badwidth_read32,
-    omap_os_timer_read,
-};
-
-static CPUWriteMemoryFunc * const omap_os_timer_writefn[] = {
-    omap_badwidth_write32,
-    omap_badwidth_write32,
-    omap_os_timer_write,
+static const MemoryRegionOps omap_os_timer_ops = {
+    .read = omap_os_timer_read,
+    .write = omap_os_timer_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void omap_os_timer_reset(struct omap_32khz_timer_s *s)
@@ -476,10 +489,10 @@ static void omap_os_timer_reset(struct omap_32khz_timer_s *s)
     s->timer.ar = 1;
 }
 
-static struct omap_32khz_timer_s *omap_os_timer_init(target_phys_addr_t base,
+static struct omap_32khz_timer_s *omap_os_timer_init(MemoryRegion *memory,
+                target_phys_addr_t base,
                 qemu_irq irq, omap_clk clk)
 {
-    int iomemtype;
     struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *)
             g_malloc0(sizeof(struct omap_32khz_timer_s));
 
@@ -489,19 +502,24 @@ static struct omap_32khz_timer_s *omap_os_timer_init(target_phys_addr_t base,
     omap_os_timer_reset(s);
     omap_timer_clk_setup(&s->timer);
 
-    iomemtype = cpu_register_io_memory(omap_os_timer_readfn,
-                    omap_os_timer_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x800, iomemtype);
+    memory_region_init_io(&s->iomem, &omap_os_timer_ops, s,
+                          "omap-os-timer", 0x800);
+    memory_region_add_subregion(memory, base, &s->iomem);
 
     return s;
 }
 
 /* Ultra Low-Power Device Module */
-static uint32_t omap_ulpd_pm_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_ulpd_pm_read(void *opaque, target_phys_addr_t addr,
+                                  unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
     uint16_t ret;
 
+    if (size != 2) {
+        return omap_badwidth_read16(opaque, addr);
+    }
+
     switch (addr) {
     case 0x14:	/* IT_STATUS */
         ret = s->ulpd_pm_regs[addr >> 2];
@@ -560,7 +578,7 @@ static inline void omap_ulpd_req_update(struct omap_mpu_state_s *s,
 }
 
 static void omap_ulpd_pm_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                               uint64_t value, unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
     int64_t now, ticks;
@@ -568,6 +586,10 @@ static void omap_ulpd_pm_write(void *opaque, target_phys_addr_t addr,
     static const int bypass_div[4] = { 1, 2, 4, 4 };
     uint16_t diff;
 
+    if (size != 2) {
+        return omap_badwidth_write16(opaque, addr, value);
+    }
+
     switch (addr) {
     case 0x00:	/* COUNTER_32_LSB */
     case 0x04:	/* COUNTER_32_MSB */
@@ -674,16 +696,10 @@ static void omap_ulpd_pm_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_ulpd_pm_readfn[] = {
-    omap_badwidth_read16,
-    omap_ulpd_pm_read,
-    omap_badwidth_read16,
-};
-
-static CPUWriteMemoryFunc * const omap_ulpd_pm_writefn[] = {
-    omap_badwidth_write16,
-    omap_ulpd_pm_write,
-    omap_badwidth_write16,
+static const MemoryRegionOps omap_ulpd_pm_ops = {
+    .read = omap_ulpd_pm_read,
+    .write = omap_ulpd_pm_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void omap_ulpd_pm_reset(struct omap_mpu_state_s *mpu)
@@ -713,21 +729,26 @@ static void omap_ulpd_pm_reset(struct omap_mpu_state_s *mpu)
     omap_clk_reparent(omap_findclk(mpu, "ck_48m"), omap_findclk(mpu, "dpll4"));
 }
 
-static void omap_ulpd_pm_init(target_phys_addr_t base,
+static void omap_ulpd_pm_init(MemoryRegion *system_memory,
+                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, DEVICE_NATIVE_ENDIAN);
-
-    cpu_register_physical_memory(base, 0x800, iomemtype);
+    memory_region_init_io(&mpu->ulpd_pm_iomem, &omap_ulpd_pm_ops, mpu,
+                          "omap-ulpd-pm", 0x800);
+    memory_region_add_subregion(system_memory, base, &mpu->ulpd_pm_iomem);
     omap_ulpd_pm_reset(mpu);
 }
 
 /* OMAP Pin Configuration */
-static uint32_t omap_pin_cfg_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_pin_cfg_read(void *opaque, target_phys_addr_t addr,
+                                  unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
 
+    if (size != 4) {
+        return omap_badwidth_read32(opaque, addr);
+    }
+
     switch (addr) {
     case 0x00:	/* FUNC_MUX_CTRL_0 */
     case 0x04:	/* FUNC_MUX_CTRL_1 */
@@ -827,11 +848,15 @@ static inline void omap_pin_modconf1_update(struct omap_mpu_state_s *s,
 }
 
 static void omap_pin_cfg_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                               uint64_t value, unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
     uint32_t diff;
 
+    if (size != 4) {
+        return omap_badwidth_write32(opaque, addr, value);
+    }
+
     switch (addr) {
     case 0x00:	/* FUNC_MUX_CTRL_0 */
         diff = s->func_mux_ctrl[addr >> 2] ^ value;
@@ -900,16 +925,10 @@ static void omap_pin_cfg_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_pin_cfg_readfn[] = {
-    omap_badwidth_read32,
-    omap_badwidth_read32,
-    omap_pin_cfg_read,
-};
-
-static CPUWriteMemoryFunc * const omap_pin_cfg_writefn[] = {
-    omap_badwidth_write32,
-    omap_badwidth_write32,
-    omap_pin_cfg_write,
+static const MemoryRegionOps omap_pin_cfg_ops = {
+    .read = omap_pin_cfg_read,
+    .write = omap_pin_cfg_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void omap_pin_cfg_reset(struct omap_mpu_state_s *mpu)
@@ -928,21 +947,26 @@ static void omap_pin_cfg_reset(struct omap_mpu_state_s *mpu)
     memset(mpu->mod_conf_ctrl, 0, sizeof(mpu->mod_conf_ctrl));
 }
 
-static void omap_pin_cfg_init(target_phys_addr_t base,
+static void omap_pin_cfg_init(MemoryRegion *system_memory,
+                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, DEVICE_NATIVE_ENDIAN);
-
-    cpu_register_physical_memory(base, 0x800, iomemtype);
+    memory_region_init_io(&mpu->pin_cfg_iomem, &omap_pin_cfg_ops, mpu,
+                          "omap-pin-cfg", 0x800);
+    memory_region_add_subregion(system_memory, base, &mpu->pin_cfg_iomem);
     omap_pin_cfg_reset(mpu);
 }
 
 /* Device Identification, Die Identification */
-static uint32_t omap_id_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_id_read(void *opaque, target_phys_addr_t addr,
+                             unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
 
+    if (size != 4) {
+        return omap_badwidth_read32(opaque, addr);
+    }
+
     switch (addr) {
     case 0xfffe1800:	/* DIE_ID_LSB */
         return 0xc9581f0e;
@@ -982,38 +1006,48 @@ static uint32_t omap_id_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void omap_id_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                          uint64_t value, unsigned size)
 {
+    if (size != 4) {
+        return omap_badwidth_write32(opaque, addr, value);
+    }
+
     OMAP_BAD_REG(addr);
 }
 
-static CPUReadMemoryFunc * const omap_id_readfn[] = {
-    omap_badwidth_read32,
-    omap_badwidth_read32,
-    omap_id_read,
-};
-
-static CPUWriteMemoryFunc * const omap_id_writefn[] = {
-    omap_badwidth_write32,
-    omap_badwidth_write32,
-    omap_id_write,
+static const MemoryRegionOps omap_id_ops = {
+    .read = omap_id_read,
+    .write = omap_id_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static void omap_id_init(struct omap_mpu_state_s *mpu)
+static void omap_id_init(MemoryRegion *memory, struct omap_mpu_state_s *mpu)
 {
-    int iomemtype = cpu_register_io_memory(omap_id_readfn,
-                    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))
-        cpu_register_physical_memory_offset(0xfffe2000, 0x800, iomemtype, 0xfffe2000);
+    memory_region_init_io(&mpu->id_iomem, &omap_id_ops, mpu,
+                          "omap-id", 0x100000000ULL);
+    memory_region_init_alias(&mpu->id_iomem_e18, "omap-id-e18", &mpu->id_iomem,
+                             0xfffe1800, 0x800);
+    memory_region_add_subregion(memory, 0xfffe1800, &mpu->id_iomem_e18);
+    memory_region_init_alias(&mpu->id_iomem_ed4, "omap-id-ed4", &mpu->id_iomem,
+                             0xfffed400, 0x100);
+    memory_region_add_subregion(memory, 0xfffed400, &mpu->id_iomem_ed4);
+    if (!cpu_is_omap15xx(mpu)) {
+        memory_region_init_alias(&mpu->id_iomem_ed4, "omap-id-e20",
+                                 &mpu->id_iomem, 0xfffe2000, 0x800);
+        memory_region_add_subregion(memory, 0xfffe2000, &mpu->id_iomem_e20);
+    }
 }
 
 /* MPUI Control (Dummy) */
-static uint32_t omap_mpui_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_mpui_read(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
 
+    if (size != 4) {
+        return omap_badwidth_read32(opaque, addr);
+    }
+
     switch (addr) {
     case 0x00:	/* CTRL */
         return s->mpui_ctrl;
@@ -1039,10 +1073,14 @@ static uint32_t omap_mpui_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void omap_mpui_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                            uint64_t value, unsigned size)
 {
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
 
+    if (size != 4) {
+        return omap_badwidth_write32(opaque, addr, value);
+    }
+
     switch (addr) {
     case 0x00:	/* CTRL */
         s->mpui_ctrl = value & 0x007fffff;
@@ -1064,16 +1102,10 @@ static void omap_mpui_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_mpui_readfn[] = {
-    omap_badwidth_read32,
-    omap_badwidth_read32,
-    omap_mpui_read,
-};
-
-static CPUWriteMemoryFunc * const omap_mpui_writefn[] = {
-    omap_badwidth_write32,
-    omap_badwidth_write32,
-    omap_mpui_write,
+static const MemoryRegionOps omap_mpui_ops = {
+    .read = omap_mpui_read,
+    .write = omap_mpui_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void omap_mpui_reset(struct omap_mpu_state_s *s)
@@ -1081,13 +1113,12 @@ static void omap_mpui_reset(struct omap_mpu_state_s *s)
     s->mpui_ctrl = 0x0003ff1b;
 }
 
-static void omap_mpui_init(target_phys_addr_t base,
+static void omap_mpui_init(MemoryRegion *memory, target_phys_addr_t base,
                 struct omap_mpu_state_s *mpu)
 {
-    int iomemtype = cpu_register_io_memory(omap_mpui_readfn,
-                    omap_mpui_writefn, mpu, DEVICE_NATIVE_ENDIAN);
-
-    cpu_register_physical_memory(base, 0x100, iomemtype);
+    memory_region_init_io(&mpu->mpui_iomem, &omap_mpui_ops, mpu,
+                          "omap-mpui", 0x100);
+    memory_region_add_subregion(memory, base, &mpu->mpui_iomem);
 
     omap_mpui_reset(mpu);
 }
@@ -1095,6 +1126,7 @@ static void omap_mpui_init(target_phys_addr_t base,
 /* TIPB Bridges */
 struct omap_tipb_bridge_s {
     qemu_irq abort;
+    MemoryRegion iomem;
 
     int width_intr;
     uint16_t control;
@@ -1103,10 +1135,15 @@ struct omap_tipb_bridge_s {
     uint16_t enh_control;
 };
 
-static uint32_t omap_tipb_bridge_read(void *opaque, target_phys_addr_t addr)
+static uint64_t omap_tipb_bridge_read(void *opaque, target_phys_addr_t addr,
+                                      unsigned size)
 {
     struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) opaque;
 
+    if (size < 2) {
+        return omap_badwidth_read16(opaque, addr);
+    }
+
     switch (addr) {
     case 0x00:	/* TIPB_CNTL */
         return s->control;
@@ -1129,10 +1166,14 @@ static uint32_t omap_tipb_bridge_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void omap_tipb_bridge_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+                                   uint64_t value, unsigned size)
 {
     struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) opaque;
 
+    if (size < 2) {
+        return omap_badwidth_write16(opaque, addr, value);
+    }
+
     switch (addr) {
     case 0x00:	/* TIPB_CNTL */
         s->control = value & 0xffff;
@@ -1163,16 +1204,10 @@ static void omap_tipb_bridge_write(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const omap_tipb_bridge_readfn[] = {
-    omap_badwidth_read16,
-    omap_tipb_bridge_read,
-    omap_tipb_bridge_read,
-};
-
-static CPUWriteMemoryFunc * const omap_tipb_bridge_writefn[] = {
-    omap_badwidth_write16,
-    omap_tipb_bridge_write,
-    omap_tipb_bridge_write,
+static const MemoryRegionOps omap_tipb_bridge_ops = {
+    .read = omap_tipb_bridge_read,
+    .write = omap_tipb_bridge_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void omap_tipb_bridge_reset(struct omap_tipb_bridge_s *s)
@@ -1183,19 +1218,19 @@ static void omap_tipb_bridge_reset(struct omap_tipb_bridge_s *s)
     s->enh_control = 0x000f;
 }
 
-static struct omap_tipb_bridge_s *omap_tipb_bridge_init(target_phys_addr_t base,
-                qemu_irq abort_irq, omap_clk clk)
+static struct omap_tipb_bridge_s *omap_tipb_bridge_init(
+    MemoryRegion *memory, target_phys_addr_t base,
+    qemu_irq abort_irq, omap_clk clk)
 {
-    int iomemtype;
     struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *)
             g_malloc0(sizeof(struct omap_tipb_bridge_s));
 
     s->abort = abort_irq;
     omap_tipb_bridge_reset(s);
 
-    iomemtype = cpu_register_io_memory(omap_tipb_bridge_readfn,
-                    omap_tipb_bridge_writefn, s, DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(base, 0x100, iomemtype);
+    memory_region_init_io(&s->iomem, &omap_tipb_bridge_ops, s,
+                          "omap-tipb-bridge", 0x100);
+    memory_region_add_subregion(memory, base, &s->iomem);
 
     return s;
 }
@@ -3706,7 +3741,8 @@ static int omap_validate_tipb_mpui_addr(struct omap_mpu_state_s *s,
     return range_covers_byte(0xe1010000, 0xe1020004 - 0xe1010000, addr);
 }
 
-struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
+struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
+                unsigned long sdram_size,
                 const char *core)
 {
     int i;
@@ -3772,21 +3808,21 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
     soc_dma_port_add_mem_ram(s->dma,
                     imif_base, OMAP_IMIF_BASE, s->sram_size);
 
-    s->timer[0] = omap_mpu_timer_init(0xfffec500,
+    s->timer[0] = omap_mpu_timer_init(system_memory, 0xfffec500,
                     s->irq[0][OMAP_INT_TIMER1],
                     omap_findclk(s, "mputim_ck"));
-    s->timer[1] = omap_mpu_timer_init(0xfffec600,
+    s->timer[1] = omap_mpu_timer_init(system_memory, 0xfffec600,
                     s->irq[0][OMAP_INT_TIMER2],
                     omap_findclk(s, "mputim_ck"));
-    s->timer[2] = omap_mpu_timer_init(0xfffec700,
+    s->timer[2] = omap_mpu_timer_init(system_memory, 0xfffec700,
                     s->irq[0][OMAP_INT_TIMER3],
                     omap_findclk(s, "mputim_ck"));
 
-    s->wdt = omap_wd_timer_init(0xfffec800,
+    s->wdt = omap_wd_timer_init(system_memory, 0xfffec800,
                     s->irq[0][OMAP_INT_WD_TIMER],
                     omap_findclk(s, "armwdt_ck"));
 
-    s->os_timer = omap_os_timer_init(0xfffb9000,
+    s->os_timer = omap_os_timer_init(system_memory, 0xfffb9000,
                     s->irq[1][OMAP_INT_OS_TIMER],
                     omap_findclk(s, "clk32-kHz"));
 
@@ -3794,16 +3830,16 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
                     omap_dma_get_lcdch(s->dma), imif_base, emiff_base,
                     omap_findclk(s, "lcd_ck"));
 
-    omap_ulpd_pm_init(0xfffe0800, s);
-    omap_pin_cfg_init(0xfffe1000, s);
-    omap_id_init(s);
+    omap_ulpd_pm_init(system_memory, 0xfffe0800, s);
+    omap_pin_cfg_init(system_memory, 0xfffe1000, s);
+    omap_id_init(system_memory, s);
 
-    omap_mpui_init(0xfffec900, s);
+    omap_mpui_init(system_memory, 0xfffec900, s);
 
-    s->private_tipb = omap_tipb_bridge_init(0xfffeca00,
+    s->private_tipb = omap_tipb_bridge_init(system_memory, 0xfffeca00,
                     s->irq[0][OMAP_INT_BRIDGE_PRIV],
                     omap_findclk(s, "tipb_ck"));
-    s->public_tipb = omap_tipb_bridge_init(0xfffed300,
+    s->public_tipb = omap_tipb_bridge_init(system_memory, 0xfffed300,
                     s->irq[0][OMAP_INT_BRIDGE_PUB],
                     omap_findclk(s, "tipb_ck"));
 
diff --git a/hw/omap_sx1.c b/hw/omap_sx1.c
index 15cfbb5..fe53545 100644
--- a/hw/omap_sx1.c
+++ b/hw/omap_sx1.c
@@ -32,6 +32,7 @@
 #include "arm-misc.h"
 #include "flash.h"
 #include "blockdev.h"
+#include "exec-memory.h"
 
 /*****************************************************************************/
 /* Siemens SX1 Cellphone V1 */
@@ -121,6 +122,7 @@ static void sx1_init(ram_addr_t ram_size,
                 const int version)
 {
     struct omap_mpu_state_s *cpu;
+    MemoryRegion *address_space = get_system_memory();
     int io;
     static uint32_t cs0val = 0x00213090;
     static uint32_t cs1val = 0x00215070;
@@ -135,7 +137,7 @@ static void sx1_init(ram_addr_t ram_size,
         flash_size = flash2_size;
     }
 
-    cpu = omap310_mpu_init(sx1_binfo.ram_size, cpu_model);
+    cpu = omap310_mpu_init(address_space, sx1_binfo.ram_size, cpu_model);
 
     /* External Flash (EMIFS) */
     cpu_register_physical_memory(OMAP_CS0_BASE, flash_size,
diff --git a/hw/palm.c b/hw/palm.c
index 4c67e75..d8f50e3 100644
--- a/hw/palm.c
+++ b/hw/palm.c
@@ -25,6 +25,7 @@
 #include "arm-misc.h"
 #include "devices.h"
 #include "loader.h"
+#include "exec-memory.h"
 
 static uint32_t static_readb(void *opaque, target_phys_addr_t offset)
 {
@@ -198,6 +199,7 @@ static void palmte_init(ram_addr_t ram_size,
                 const char *kernel_filename, const char *kernel_cmdline,
                 const char *initrd_filename, const char *cpu_model)
 {
+    MemoryRegion *address_space_mem = get_system_memory();
     struct omap_mpu_state_s *cpu;
     int flash_size = 0x00800000;
     int sdram_size = palmte_binfo.ram_size;
@@ -209,7 +211,7 @@ static void palmte_init(ram_addr_t ram_size,
     int rom_size, rom_loaded = 0;
     DisplayState *ds = get_displaystate();
 
-    cpu = omap310_mpu_init(sdram_size, cpu_model);
+    cpu = omap310_mpu_init(address_space_mem, sdram_size, cpu_model);
 
     /* External Flash (EMIFS) */
     cpu_register_physical_memory(OMAP_CS0_BASE, flash_size,
commit 27cdad67a1bc23b38c765b677ed8064bfb8d3e44
Author: Richard Henderson <rth at twiddle.net>
Date:   Tue Sep 20 15:36:24 2011 -0700

    Revert "alpha-softmmu: Disable for the 0.15 release branch."
    
    This reverts commit 46f08792bb4a69ab8aab897c174d82b006026140.
    
    This was not supposed to be applied to mainline.
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Edgar E. Iglesias <edgar.iglesias at gmail.com>

diff --git a/configure b/configure
index ad924c4..414317a 100755
--- a/configure
+++ b/configure
@@ -855,6 +855,7 @@ if [ "$softmmu" = "yes" ] ; then
     default_target_list="\
 i386-softmmu \
 x86_64-softmmu \
+alpha-softmmu \
 arm-softmmu \
 cris-softmmu \
 lm32-softmmu \
commit 03c39eb558472ab3b13a39e9159b2e1ffa6c3a43
Merge: c8af89a... 336411c...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Tue Sep 20 15:22:10 2011 -0500

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

commit c8af89af96dac46922f6664cf0ca238a6b1adf0d
Merge: 39ba59c... 16a06b2...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Tue Sep 20 15:21:03 2011 -0500

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

commit 39ba59c21bdc3b1dda09219919b87fe001e7d5d9
Merge: 7f67d89... 144d192...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Tue Sep 20 15:18:10 2011 -0500

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

commit 7f67d8922e2da59c02852de39f888d7873e8645c
Merge: 27acf66... 6e0ca88...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Tue Sep 20 15:16:00 2011 -0500

    Merge remote-tracking branch 'qmp/queue/qmp' into staging

commit 336411cafd385be1fc3de4472595d409ac7fe2b2
Author: Michael S. Tsirkin <mst at redhat.com>
Date:   Tue Sep 6 20:58:22 2011 +0300

    pci_bridge: simplify memory regions some more
    
    replace alloc/free with struct members.
    todo: smash with initial implementation after
    testing.
    
    Signed-off-by: Michael S. Tsirkin <mst at redhat.com>

diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c
index 25e9b7c..b6287cd 100644
--- a/hw/pci_bridge.c
+++ b/hw/pci_bridge.c
@@ -160,26 +160,25 @@ static void pci_bridge_cleanup_alias(MemoryRegion *alias,
 
 static void pci_bridge_region_init(PCIBridge *br)
 {
-    PCIBus *sec_bus = &br->sec_bus;
     PCIBus *parent = br->dev.bus;
     uint16_t cmd = pci_get_word(br->dev.config + PCI_COMMAND);
 
     pci_bridge_init_alias(br, &br->alias_pref_mem,
                           PCI_BASE_ADDRESS_MEM_PREFETCH,
                           "pci_bridge_pref_mem",
-                          sec_bus->address_space_mem,
+                          &br->address_space_mem,
                           parent->address_space_mem,
                           cmd & PCI_COMMAND_MEMORY);
     pci_bridge_init_alias(br, &br->alias_mem,
                           PCI_BASE_ADDRESS_SPACE_MEMORY,
                           "pci_bridge_mem",
-                          sec_bus->address_space_mem,
+                          &br->address_space_mem,
                           parent->address_space_mem,
                           cmd & PCI_COMMAND_MEMORY);
     pci_bridge_init_alias(br, &br->alias_io,
                           PCI_BASE_ADDRESS_SPACE_IO,
                           "pci_bridge_io",
-                          sec_bus->address_space_io,
+                          &br->address_space_io,
                           parent->address_space_io,
                           cmd & PCI_COMMAND_IO);
    /* TODO: optinal VGA and VGA palette snooping support. */
@@ -319,10 +318,10 @@ int pci_bridge_initfn(PCIDevice *dev)
                         br->bus_name);
     sec_bus->parent_dev = dev;
     sec_bus->map_irq = br->map_irq;
-    sec_bus->address_space_mem = g_new(MemoryRegion, 1);
-    memory_region_init(sec_bus->address_space_mem, "pci_pridge_pci", INT64_MAX);
-    sec_bus->address_space_io = g_new(MemoryRegion, 1);
-    memory_region_init(sec_bus->address_space_io, "pci_bridge_io", 65536);
+    sec_bus->address_space_mem = &br->address_space_mem;
+    memory_region_init(&br->address_space_mem, "pci_pridge_pci", INT64_MAX);
+    sec_bus->address_space_io = &br->address_space_io;
+    memory_region_init(&br->address_space_io, "pci_bridge_io", 65536);
     pci_bridge_region_init(br);
     QLIST_INIT(&sec_bus->child);
     QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling);
@@ -333,14 +332,11 @@ int pci_bridge_initfn(PCIDevice *dev)
 int pci_bridge_exitfn(PCIDevice *pci_dev)
 {
     PCIBridge *s = DO_UPCAST(PCIBridge, dev, pci_dev);
-    PCIBus *sec_bus = &s->sec_bus;
     assert(QLIST_EMPTY(&s->sec_bus.child));
     QLIST_REMOVE(&s->sec_bus, sibling);
     pci_bridge_region_cleanup(s);
-    memory_region_destroy(sec_bus->address_space_mem);
-    g_free(sec_bus->address_space_mem);
-    memory_region_destroy(sec_bus->address_space_io);
-    g_free(sec_bus->address_space_io);
+    memory_region_destroy(&s->address_space_mem);
+    memory_region_destroy(&s->address_space_io);
     /* qbus_free() is called automatically by qdev_free() */
     return 0;
 }
diff --git a/hw/pci_internals.h b/hw/pci_internals.h
index 71c8b51..96690b7 100644
--- a/hw/pci_internals.h
+++ b/hw/pci_internals.h
@@ -41,6 +41,21 @@ struct PCIBridge {
 
     /* private member */
     PCIBus sec_bus;
+    /*
+     * Memory regions for the bridge's address spaces.  These regions are not
+     * directly added to system_memory/system_io or its descendants.
+     * Bridge's secondary bus points to these, so that devices
+     * under the bridge see these regions as its address spaces.
+     * The regions are as large as the entire address space -
+     * they don't take into account any windows.
+     */
+    MemoryRegion address_space_mem;
+    MemoryRegion address_space_io;
+    /*
+     * Aliases for each of the address space windows that the bridge
+     * can forward. Mapped into the bridge's parent's address space,
+     * as subregions.
+     */
     MemoryRegion alias_pref_mem;
     MemoryRegion alias_mem;
     MemoryRegion alias_io;
commit 27acf660aa1678ff3e7291fa81f4d5d4020b20f8
Author: Juan Quintela <quintela at redhat.com>
Date:   Tue Sep 20 15:16:27 2011 +0200

    wavaudio: Use stdio instead of QEMUFile
    
    QEMUFile * is only intended for migration nowadays.  Using it for
    anything else just adds pain and a layer of buffers for no good
    reason.
    
    Signed-off-by: Juan Quintela <quintela at redhat.com>
    CC:  malc <av1474 at comtv.ru>
    Signed-off-by: malc <av1474 at comtv.ru>

diff --git a/audio/wavaudio.c b/audio/wavaudio.c
index aed1817..a449b51 100644
--- a/audio/wavaudio.c
+++ b/audio/wavaudio.c
@@ -30,7 +30,7 @@
 
 typedef struct WAVVoiceOut {
     HWVoiceOut hw;
-    QEMUFile *f;
+    FILE *f;
     int64_t old_ticks;
     void *pcm_buf;
     int total_samples;
@@ -76,7 +76,10 @@ static int wav_run_out (HWVoiceOut *hw, int live)
         dst = advance (wav->pcm_buf, rpos << hw->info.shift);
 
         hw->clip (dst, src, convert_samples);
-        qemu_put_buffer (wav->f, dst, convert_samples << hw->info.shift);
+        if (fwrite (dst, convert_samples << hw->info.shift, 1, wav->f) != 1) {
+            dolog ("wav_run_out: fwrite of %d bytes failed\nReaons: %s\n",
+                   convert_samples << hw->info.shift, strerror (errno));
+        }
 
         rpos = (rpos + convert_samples) % hw->samples;
         samples -= convert_samples;
@@ -152,7 +155,7 @@ static int wav_init_out (HWVoiceOut *hw, struct audsettings *as)
     le_store (hdr + 28, hw->info.freq << (bits16 + stereo), 4);
     le_store (hdr + 32, 1 << (bits16 + stereo), 2);
 
-    wav->f = qemu_fopen (conf.wav_path, "wb");
+    wav->f = fopen (conf.wav_path, "wb");
     if (!wav->f) {
         dolog ("Failed to open wave file `%s'\nReason: %s\n",
                conf.wav_path, strerror (errno));
@@ -161,7 +164,11 @@ static int wav_init_out (HWVoiceOut *hw, struct audsettings *as)
         return -1;
     }
 
-    qemu_put_buffer (wav->f, hdr, sizeof (hdr));
+    if (fwrite (hdr, sizeof (hdr), 1, wav->f) != 1) {
+        dolog ("wav_init_out: failed to write header\nReason: %s\n",
+               strerror(errno));
+        return -1;
+    }
     return 0;
 }
 
@@ -180,13 +187,32 @@ static void wav_fini_out (HWVoiceOut *hw)
     le_store (rlen, rifflen, 4);
     le_store (dlen, datalen, 4);
 
-    qemu_fseek (wav->f, 4, SEEK_SET);
-    qemu_put_buffer (wav->f, rlen, 4);
-
-    qemu_fseek (wav->f, 32, SEEK_CUR);
-    qemu_put_buffer (wav->f, dlen, 4);
+    if (fseek (wav->f, 4, SEEK_SET)) {
+        dolog ("wav_fini_out: fseek to rlen failed\nReason: %s\n",
+               strerror(errno));
+        goto doclose;
+    }
+    if (fwrite (rlen, 4, 1, wav->f) != 1) {
+        dolog ("wav_fini_out: failed to write rlen\nReason: %s\n",
+               strerror (errno));
+        goto doclose;
+    }
+    if (fseek (wav->f, 32, SEEK_CUR)) {
+        dolog ("wav_fini_out: fseek to dlen failed\nReason: %s\n",
+               strerror (errno));
+        goto doclose;
+    }
+    if (fwrite (dlen, 4, 1, wav->f) != 1) {
+        dolog ("wav_fini_out: failed to write dlen\nReaons: %s\n",
+               strerror (errno));
+        goto doclose;
+    }
 
-    qemu_fclose (wav->f);
+ doclose:
+    if (fclose (wav->f))  {
+        dolog ("wav_fini_out: fclose %p failed\nReason: %s\n",
+               wav->f, strerror (errno));
+    }
     wav->f = NULL;
 
     g_free (wav->pcm_buf);
commit b04df2a4401826ceced971f5f1433c1a3f2b5a98
Author: Juan Quintela <quintela at redhat.com>
Date:   Tue Sep 20 15:16:28 2011 +0200

    wavcapture: Use stdio instead of QEMUFile
    
    QEMUFile * is only intended for migration nowadays.  Using it for
    anything else just adds pain and a layer of buffers for no good
    reason.
    
    Signed-off-by: Juan Quintela <quintela at redhat.com>
    CC: malc <av1474 at comtv.ru>
    Signed-off-by: malc <av1474 at comtv.ru>

diff --git a/audio/wavcapture.c b/audio/wavcapture.c
index c64f0ef..4f785f5 100644
--- a/audio/wavcapture.c
+++ b/audio/wavcapture.c
@@ -3,7 +3,7 @@
 #include "audio.h"
 
 typedef struct {
-    QEMUFile *f;
+    FILE *f;
     int bytes;
     char *path;
     int freq;
@@ -35,17 +35,37 @@ static void wav_destroy (void *opaque)
     uint8_t dlen[4];
     uint32_t datalen = wav->bytes;
     uint32_t rifflen = datalen + 36;
+    Monitor *mon = cur_mon;
 
     if (wav->f) {
         le_store (rlen, rifflen, 4);
         le_store (dlen, datalen, 4);
 
-        qemu_fseek (wav->f, 4, SEEK_SET);
-        qemu_put_buffer (wav->f, rlen, 4);
-
-        qemu_fseek (wav->f, 32, SEEK_CUR);
-        qemu_put_buffer (wav->f, dlen, 4);
-        qemu_fclose (wav->f);
+        if (fseek (wav->f, 4, SEEK_SET)) {
+            monitor_printf (mon, "wav_destroy: rlen fseek failed\nReason: %s\n",
+                            strerror (errno));
+            goto doclose;
+        }
+        if (fwrite (rlen, 4, 1, wav->f) != 1) {
+            monitor_printf (mon, "wav_destroy: rlen fwrite failed\nReason %s\n",
+                            strerror (errno));
+            goto doclose;
+        }
+        if (fseek (wav->f, 32, SEEK_CUR)) {
+            monitor_printf (mon, "wav_destroy: dlen fseek failed\nReason %s\n",
+                            strerror (errno));
+            goto doclose;
+        }
+        if (fwrite (dlen, 1, 4, wav->f) != 4) {
+            monitor_printf (mon, "wav_destroy: dlen fwrite failed\nReason %s\n",
+                            strerror (errno));
+            goto doclose;
+        }
+    doclose:
+        if (fclose (wav->f)) {
+            fprintf (stderr, "wav_destroy: fclose failed: %s",
+                     strerror (errno));
+        }
     }
 
     g_free (wav->path);
@@ -55,7 +75,10 @@ static void wav_capture (void *opaque, void *buf, int size)
 {
     WAVState *wav = opaque;
 
-    qemu_put_buffer (wav->f, buf, size);
+    if (fwrite (buf, size, 1, wav->f) != 1) {
+        monitor_printf (cur_mon, "wav_capture: fwrite error\nReason: %s",
+                        strerror (errno));
+    }
     wav->bytes += size;
 }
 
@@ -71,9 +94,9 @@ static void wav_capture_info (void *opaque)
     WAVState *wav = opaque;
     char *path = wav->path;
 
-    monitor_printf(cur_mon, "Capturing audio(%d,%d,%d) to %s: %d bytes\n",
-                   wav->freq, wav->bits, wav->nchannels,
-                   path ? path : "<not available>", wav->bytes);
+    monitor_printf (cur_mon, "Capturing audio(%d,%d,%d) to %s: %d bytes\n",
+                    wav->freq, wav->bits, wav->nchannels,
+                    path ? path : "<not available>", wav->bytes);
 }
 
 static struct capture_ops wav_capture_ops = {
@@ -98,13 +121,13 @@ int wav_start_capture (CaptureState *s, const char *path, int freq,
     CaptureVoiceOut *cap;
 
     if (bits != 8 && bits != 16) {
-        monitor_printf(mon, "incorrect bit count %d, must be 8 or 16\n", bits);
+        monitor_printf (mon, "incorrect bit count %d, must be 8 or 16\n", bits);
         return -1;
     }
 
     if (nchannels != 1 && nchannels != 2) {
-        monitor_printf(mon, "incorrect channel count %d, must be 1 or 2\n",
-                       nchannels);
+        monitor_printf (mon, "incorrect channel count %d, must be 1 or 2\n",
+                        nchannels);
         return -1;
     }
 
@@ -130,10 +153,10 @@ int wav_start_capture (CaptureState *s, const char *path, int freq,
     le_store (hdr + 28, freq << shift, 4);
     le_store (hdr + 32, 1 << shift, 2);
 
-    wav->f = qemu_fopen (path, "wb");
+    wav->f = fopen (path, "wb");
     if (!wav->f) {
-        monitor_printf(mon, "Failed to open wave file `%s'\nReason: %s\n",
-                       path, strerror (errno));
+        monitor_printf (mon, "Failed to open wave file `%s'\nReason: %s\n",
+                        path, strerror (errno));
         g_free (wav);
         return -1;
     }
@@ -143,19 +166,29 @@ int wav_start_capture (CaptureState *s, const char *path, int freq,
     wav->nchannels = nchannels;
     wav->freq = freq;
 
-    qemu_put_buffer (wav->f, hdr, sizeof (hdr));
+    if (fwrite (hdr, sizeof (hdr), 1, wav->f) != 1) {
+        monitor_printf (mon, "Failed to write header\nReason: %s\n",
+                        strerror (errno));
+        goto error_free;
+    }
 
     cap = AUD_add_capture (&as, &ops, wav);
     if (!cap) {
-        monitor_printf(mon, "Failed to add audio capture\n");
-        g_free (wav->path);
-        qemu_fclose (wav->f);
-        g_free (wav);
-        return -1;
+        monitor_printf (mon, "Failed to add audio capture\n");
+        goto error_free;
     }
 
     wav->cap = cap;
     s->opaque = wav;
     s->ops = wav_capture_ops;
     return 0;
+
+error_free:
+    g_free (wav->path);
+    if (fclose (wav->f)) {
+        monitor_printf (mon, "Failed to close wave file\nReason: %s\n",
+                        strerror (errno));
+    }
+    g_free (wav);
+    return -1;
 }
commit 16a06b24306b5733a4ef2e585964838e47735a54
Author: Sage Weil <sage at newdream.net>
Date:   Mon Sep 19 13:35:26 2011 -0700

    rbd: allow escaping in config string
    
    The config string is variously delimited by =, @, and /, depending on the
    field.  Allow these characters to be escaped by preceeding them with \.
    
    Signed-off-by: Sage Weil <sage at newdream.net>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/rbd.c b/block/rbd.c
index 98efd2c..3068c82 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -102,8 +102,15 @@ static int qemu_rbd_next_tok(char *dst, int dst_len,
     *p = NULL;
 
     if (delim != '\0') {
-        end = strchr(src, delim);
-        if (end) {
+        for (end = src; *end; ++end) {
+            if (*end == delim) {
+                break;
+            }
+            if (*end == '\\' && end[1] != '\0') {
+                end++;
+            }
+        }
+        if (*end == delim) {
             *p = end + 1;
             *end = '\0';
         }
@@ -122,6 +129,19 @@ static int qemu_rbd_next_tok(char *dst, int dst_len,
     return 0;
 }
 
+static void qemu_rbd_unescape(char *src)
+{
+    char *p;
+
+    for (p = src; *src; ++src, ++p) {
+        if (*src == '\\' && src[1] != '\0') {
+            src++;
+        }
+        *p = *src;
+    }
+    *p = '\0';
+}
+
 static int qemu_rbd_parsename(const char *filename,
                               char *pool, int pool_len,
                               char *snap, int snap_len,
@@ -146,6 +166,7 @@ static int qemu_rbd_parsename(const char *filename,
         ret = -EINVAL;
         goto done;
     }
+    qemu_rbd_unescape(pool);
 
     if (strchr(p, '@')) {
         ret = qemu_rbd_next_tok(name, name_len, p, '@', "object name", &p);
@@ -153,9 +174,11 @@ static int qemu_rbd_parsename(const char *filename,
             goto done;
         }
         ret = qemu_rbd_next_tok(snap, snap_len, p, ':', "snap name", &p);
+        qemu_rbd_unescape(snap);
     } else {
         ret = qemu_rbd_next_tok(name, name_len, p, ':', "object name", &p);
     }
+    qemu_rbd_unescape(name);
     if (ret < 0 || !p) {
         goto done;
     }
@@ -211,6 +234,7 @@ static int qemu_rbd_set_conf(rados_t cluster, const char *conf)
         if (ret < 0) {
             break;
         }
+        qemu_rbd_unescape(name);
 
         if (!p) {
             error_report("conf option %s has no value", name);
@@ -223,6 +247,7 @@ static int qemu_rbd_set_conf(rados_t cluster, const char *conf)
         if (ret < 0) {
             break;
         }
+        qemu_rbd_unescape(value);
 
         if (strcmp(name, "conf") == 0) {
             ret = rados_conf_read_file(cluster, value);
commit cf26a4e6f82c5fa2efd8e7dc43d2496b14b0e595
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Mon Sep 19 17:05:12 2011 +0200

    linux-aio: remove process requests callback
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/linux-aio.c b/linux-aio.c
index 5265a02..bffa6cd 100644
--- a/linux-aio.c
+++ b/linux-aio.c
@@ -68,15 +68,6 @@ static void qemu_laio_process_completion(struct qemu_laio_state *s,
     qemu_aio_release(laiocb);
 }
 
-/*
- * All requests are directly processed when they complete, so there's nothing
- * left to do during qemu_aio_wait().
- */
-static int qemu_laio_process_requests(void *opaque)
-{
-    return 0;
-}
-
 static void qemu_laio_completion_cb(void *opaque)
 {
     struct qemu_laio_state *s = opaque;
@@ -215,7 +206,7 @@ void *laio_init(void)
         goto out_close_efd;
 
     qemu_aio_set_fd_handler(s->efd, qemu_laio_completion_cb, NULL,
-        qemu_laio_flush_cb, qemu_laio_process_requests, s);
+        qemu_laio_flush_cb, NULL, s);
 
     return s;
 
commit e1d3b254999bd628c7defdda860422baddb73781
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Mon Sep 19 16:37:13 2011 +0200

    block: avoid SIGUSR2
    
    Now that iothread is always compiled sending a signal seems only an
    additional step. This patch also avoid writing to two pipe (one from signal
    and one in qemu_service_io).
    
    Work with kvm enabled or disabled. strace output is more readable (less syscalls).
    
    [ kwolf: Merged build fix by Paolo Bonzini ]
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/cpus.c b/cpus.c
index 54c188c..d0cfe91 100644
--- a/cpus.c
+++ b/cpus.c
@@ -380,11 +380,6 @@ static int qemu_signal_init(void)
     int sigfd;
     sigset_t set;
 
-    /* SIGUSR2 used by posix-aio-compat.c */
-    sigemptyset(&set);
-    sigaddset(&set, SIGUSR2);
-    pthread_sigmask(SIG_UNBLOCK, &set, NULL);
-
     /*
      * SIG_IPI must be blocked in the main thread and must not be caught
      * by sigwait() in the signal thread. Otherwise, the cpu thread will
diff --git a/posix-aio-compat.c b/posix-aio-compat.c
index 63a8fae..d3c1174 100644
--- a/posix-aio-compat.c
+++ b/posix-aio-compat.c
@@ -42,7 +42,6 @@ struct qemu_paiocb {
     int aio_niov;
     size_t aio_nbytes;
 #define aio_ioctl_cmd   aio_nbytes /* for QEMU_AIO_IOCTL */
-    int ev_signo;
     off_t aio_offset;
 
     QTAILQ_ENTRY(qemu_paiocb) node;
@@ -308,12 +307,10 @@ static ssize_t handle_aiocb_rw(struct qemu_paiocb *aiocb)
     return nbytes;
 }
 
+static void posix_aio_notify_event(void);
+
 static void *aio_thread(void *unused)
 {
-    pid_t pid;
-
-    pid = getpid();
-
     mutex_lock(&lock);
     pending_threads--;
     mutex_unlock(&lock);
@@ -380,7 +377,7 @@ static void *aio_thread(void *unused)
         aiocb->ret = ret;
         mutex_unlock(&lock);
 
-        if (kill(pid, aiocb->ev_signo)) die("kill failed");
+        posix_aio_notify_event();
     }
 
     cur_threads--;
@@ -547,18 +544,14 @@ static int posix_aio_flush(void *opaque)
 
 static PosixAioState *posix_aio_state;
 
-static void aio_signal_handler(int signum)
+static void posix_aio_notify_event(void)
 {
-    if (posix_aio_state) {
-        char byte = 0;
-        ssize_t ret;
-
-        ret = write(posix_aio_state->wfd, &byte, sizeof(byte));
-        if (ret < 0 && errno != EAGAIN)
-            die("write()");
-    }
+    char byte = 0;
+    ssize_t ret;
 
-    qemu_service_io();
+    ret = write(posix_aio_state->wfd, &byte, sizeof(byte));
+    if (ret < 0 && errno != EAGAIN)
+        die("write()");
 }
 
 static void paio_remove(struct qemu_paiocb *acb)
@@ -622,7 +615,6 @@ BlockDriverAIOCB *paio_submit(BlockDriverState *bs, int fd,
         return NULL;
     acb->aio_type = type;
     acb->aio_fildes = fd;
-    acb->ev_signo = SIGUSR2;
 
     if (qiov) {
         acb->aio_iov = qiov->iov;
@@ -650,7 +642,6 @@ BlockDriverAIOCB *paio_ioctl(BlockDriverState *bs, int fd,
         return NULL;
     acb->aio_type = QEMU_AIO_IOCTL;
     acb->aio_fildes = fd;
-    acb->ev_signo = SIGUSR2;
     acb->aio_offset = 0;
     acb->aio_ioctl_buf = buf;
     acb->aio_ioctl_cmd = req;
@@ -664,7 +655,6 @@ BlockDriverAIOCB *paio_ioctl(BlockDriverState *bs, int fd,
 
 int paio_init(void)
 {
-    struct sigaction act;
     PosixAioState *s;
     int fds[2];
     int ret;
@@ -674,11 +664,6 @@ int paio_init(void)
 
     s = g_malloc(sizeof(PosixAioState));
 
-    sigfillset(&act.sa_mask);
-    act.sa_flags = 0; /* do not restart syscalls to interrupt select() */
-    act.sa_handler = aio_signal_handler;
-    sigaction(SIGUSR2, &act, NULL);
-
     s->first_aio = NULL;
     if (qemu_pipe(fds) == -1) {
         fprintf(stderr, "failed to create pipe\n");
commit bd5da23265ba3bb11a9f0913e016e3c3a16abf8e
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Fri Sep 9 16:47:26 2011 +0200

    scsi: fix sign extension problems
    
    When assigning a 32-bit value to cmd->xfer (which is 64-bits)
    it can be erroneously sign extended because the intermediate
    32-bit computation is signed.  Fix this by standardizing on
    the ld*_be_p functions.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 0248294..aca65a1 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -542,15 +542,15 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
         break;
     case 1:
     case 2:
-        cmd->xfer = buf[8] | (buf[7] << 8);
+        cmd->xfer = lduw_be_p(&buf[7]);
         cmd->len = 10;
         break;
     case 4:
-        cmd->xfer = buf[13] | (buf[12] << 8) | (buf[11] << 16) | (buf[10] << 24);
+        cmd->xfer = ldl_be_p(&buf[10]);
         cmd->len = 16;
         break;
     case 5:
-        cmd->xfer = buf[9] | (buf[8] << 8) | (buf[7] << 16) | (buf[6] << 24);
+        cmd->xfer = ldl_be_p(&buf[6]);
         cmd->len = 12;
         break;
     default:
@@ -710,23 +710,15 @@ static uint64_t scsi_cmd_lba(SCSICommand *cmd)
 
     switch (buf[0] >> 5) {
     case 0:
-        lba = (uint64_t) buf[3] | ((uint64_t) buf[2] << 8) |
-              (((uint64_t) buf[1] & 0x1f) << 16);
+        lba = ldl_be_p(&buf[0]) & 0x1fffff;
         break;
     case 1:
     case 2:
-        lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) |
-              ((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24);
+    case 5:
+        lba = ldl_be_p(&buf[2]);
         break;
     case 4:
-        lba = (uint64_t) buf[9] | ((uint64_t) buf[8] << 8) |
-              ((uint64_t) buf[7] << 16) | ((uint64_t) buf[6] << 24) |
-              ((uint64_t) buf[5] << 32) | ((uint64_t) buf[4] << 40) |
-              ((uint64_t) buf[3] << 48) | ((uint64_t) buf[2] << 56);
-        break;
-    case 5:
-        lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) |
-              ((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24);
+        lba = ldq_be_p(&buf[2]);
         break;
     default:
         lba = -1;
commit 7a3f5fe9afbef3c55c1527f61fcfd0b9d4783c0d
Author: Sage Weil <sage at newdream.net>
Date:   Thu Sep 15 14:11:11 2011 -0700

    rbd: call flush, if available
    
    librbd recently added async writeback and flush support.  If the new
    rbd_flush() call is available, call it.
    
    Signed-off-by: Sage Weil <sage at newdream.net>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/rbd.c b/block/rbd.c
index 23d8751..98efd2c 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -680,6 +680,17 @@ static BlockDriverAIOCB *qemu_rbd_aio_writev(BlockDriverState *bs,
     return rbd_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
 }
 
+static int qemu_rbd_flush(BlockDriverState *bs)
+{
+#if LIBRBD_VERSION_CODE >= LIBRBD_VERSION(0, 1, 1)
+    /* rbd_flush added in 0.1.1 */
+    BDRVRBDState *s = bs->opaque;
+    return rbd_flush(s->image);
+#else
+    return 0;
+#endif
+}
+
 static int qemu_rbd_getinfo(BlockDriverState *bs, BlockDriverInfo *bdi)
 {
     BDRVRBDState *s = bs->opaque;
@@ -815,6 +826,7 @@ static BlockDriver bdrv_rbd = {
     .bdrv_file_open     = qemu_rbd_open,
     .bdrv_close         = qemu_rbd_close,
     .bdrv_create        = qemu_rbd_create,
+    .bdrv_flush         = qemu_rbd_flush,
     .bdrv_get_info      = qemu_rbd_getinfo,
     .create_options     = qemu_rbd_create_options,
     .bdrv_getlength     = qemu_rbd_getlength,
commit 9e1fbcde578b0ab3cd2732e5334e772ab19371ac
Author: Sage Weil <sage at newdream.net>
Date:   Thu Sep 15 14:11:10 2011 -0700

    rbd: update comment heading
    
    Properly document the configuration string syntax and semantics.  Remove
    (out of date) details about the librbd implementation.
    
    Signed-off-by: Sage Weil <sage at newdream.net>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/rbd.c b/block/rbd.c
index f64b2e0..23d8751 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -13,35 +13,33 @@
 
 #include "qemu-common.h"
 #include "qemu-error.h"
-
 #include "block_int.h"
 
 #include <rbd/librbd.h>
 
-
-
 /*
  * When specifying the image filename use:
  *
  * rbd:poolname/devicename[@snapshotname][:option1=value1[:option2=value2...]]
  *
- * poolname must be the name of an existing rados pool
+ * poolname must be the name of an existing rados pool.
  *
- * devicename is the basename for all objects used to
- * emulate the raw device.
+ * devicename is the name of the rbd image.
  *
- * Each option given is used to configure rados, and may be
- * any Ceph option, or "conf". The "conf" option specifies
- * a Ceph configuration file to read.
+ * Each option given is used to configure rados, and may be any valid
+ * Ceph option, "id", or "conf".
  *
- * Metadata information (image size, ...) is stored in an
- * object with the name "devicename.rbd".
+ * The "id" option indicates what user we should authenticate as to
+ * the Ceph cluster.  If it is excluded we will use the Ceph default
+ * (normally 'admin').
  *
- * 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"
+ * The "conf" option specifies a Ceph configuration file to read.  If
+ * it is not specified, we will read from the default Ceph locations
+ * (e.g., /etc/ceph/ceph.conf).  To avoid reading _any_ configuration
+ * file, specify conf=/dev/null.
  *
+ * Configuration values containing :, @, or = can be escaped with a
+ * leading "\".
  */
 
 #define OBJ_MAX_SIZE (1UL << OBJ_DEFAULT_OBJ_ORDER)
commit f9fe18ec772d2852caaa7ca3cb72720d6822edca
Author: Sage Weil <sage at newdream.net>
Date:   Thu Sep 15 14:11:08 2011 -0700

    rbd: ignore failures when reading from default conf location
    
    If we are reading from the default config location, ignore any failures.
    It is perfectly legal for the user to specify exactly the options they need
    and to not rely on any config file.
    
    Signed-off-by: Sage Weil <sage at newdream.net>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/rbd.c b/block/rbd.c
index 1b78d51..f64b2e0 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -298,11 +298,8 @@ static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options)
     }
 
     if (strstr(conf, "conf=") == NULL) {
-        if (rados_conf_read_file(cluster, NULL) < 0) {
-            error_report("error reading config file");
-            rados_shutdown(cluster);
-            return -EIO;
-        }
+        /* try default location, but ignore failure */
+        rados_conf_read_file(cluster, NULL);
     }
 
     if (conf[0] != '\0' &&
@@ -441,11 +438,8 @@ static int qemu_rbd_open(BlockDriverState *bs, const char *filename, int flags)
     }
 
     if (strstr(conf, "conf=") == NULL) {
-        r = rados_conf_read_file(s->cluster, NULL);
-        if (r < 0) {
-            error_report("error reading config file");
-            goto failed_shutdown;
-        }
+        /* try default location, but ignore failure */
+        rados_conf_read_file(s->cluster, NULL);
     }
 
     if (conf[0] != '\0') {
commit a26a13da687f757c07e2a5c26fa411840405e6d7
Author: Alexander Motin <mav at FreeBSD.org>
Date:   Mon Sep 12 11:19:25 2011 +0300

    AHCI Port Interrupt Enable register cleaning on soft reset
    
    I've found that FreeBSD AHCI driver doesn't work with AHCI hardware
    emulation of QEMU 0.15.0. I believe the problem is on QEMU's side. As I
    see, it clears port's Interrupt Enable register each time when reset of
    any level happens. Is is reasonable for the global controller reset. It
    is probably not good, but acceptable for FreeBSD driver for the port
    hard reset. But it is IMO wrong for the device soft reset. None of real
    hardware I know behaves that way.
    
    Signed-off-by: Alexander Motin <mav at FreeBSD.org>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index a8659cf..464c28b 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -499,10 +499,7 @@ static void ahci_reset_port(AHCIState *s, int port)
     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;
@@ -1159,12 +1156,17 @@ void ahci_uninit(AHCIState *s)
 void ahci_reset(void *opaque)
 {
     struct AHCIPCIState *d = opaque;
+    AHCIPortRegs *pr;
     int i;
 
     d->ahci.control_regs.irqstatus = 0;
     d->ahci.control_regs.ghc = 0;
 
     for (i = 0; i < d->ahci.ports; i++) {
+        pr = &d->ahci.dev[i].port_regs;
+        pr->irq_stat = 0;
+        pr->irq_mask = 0;
+        pr->scr_ctl = 0;
         ahci_reset_port(&d->ahci, i);
     }
 }
commit 21cfa41e91b5f49e8aa35ce768dcbfe436021db6
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Fri Sep 16 13:34:46 2011 +0200

    posix-aio-compat: Removed unused offset variable
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/posix-aio-compat.c b/posix-aio-compat.c
index 3193dbf..63a8fae 100644
--- a/posix-aio-compat.c
+++ b/posix-aio-compat.c
@@ -181,7 +181,6 @@ qemu_pwritev(int fd, const struct iovec *iov, int nr_iov, off_t offset)
 
 static ssize_t handle_aiocb_rw_vector(struct qemu_paiocb *aiocb)
 {
-    size_t offset = 0;
     ssize_t len;
 
     do {
@@ -189,12 +188,12 @@ static ssize_t handle_aiocb_rw_vector(struct qemu_paiocb *aiocb)
             len = qemu_pwritev(aiocb->aio_fildes,
                                aiocb->aio_iov,
                                aiocb->aio_niov,
-                               aiocb->aio_offset + offset);
+                               aiocb->aio_offset);
          else
             len = qemu_preadv(aiocb->aio_fildes,
                               aiocb->aio_iov,
                               aiocb->aio_niov,
-                              aiocb->aio_offset + offset);
+                              aiocb->aio_offset);
     } while (len == -1 && errno == EINTR);
 
     if (len == -1)
commit b3c0bfb6f949d8f1c97f390f951c0bab3e703810
Author: Fam Zheng <famcool at gmail.com>
Date:   Mon Sep 19 10:26:42 2011 +0800

    VMDK: fix leak of extent_file
    
    Release extent_file on error in vmdk_parse_extents. Added closing files
    in freeing extents.
    
    Signed-off-by: Fam Zheng <famcool at gmail.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/vmdk.c b/block/vmdk.c
index 6c8edfc..5d16ec4 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -179,11 +179,16 @@ static void vmdk_free_extents(BlockDriverState *bs)
 {
     int i;
     BDRVVmdkState *s = bs->opaque;
+    VmdkExtent *e;
 
     for (i = 0; i < s->num_extents; i++) {
-        g_free(s->extents[i].l1_table);
-        g_free(s->extents[i].l2_cache);
-        g_free(s->extents[i].l1_backup_table);
+        e = &s->extents[i];
+        g_free(e->l1_table);
+        g_free(e->l2_cache);
+        g_free(e->l1_backup_table);
+        if (e->file != bs->file) {
+            bdrv_delete(e->file);
+        }
     }
     g_free(s->extents);
 }
@@ -619,12 +624,13 @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags,
     s->desc_offset = 0;
     ret = vmdk_parse_extents(buf, bs, bs->file->filename);
     if (ret) {
+        vmdk_free_extents(bs);
         return ret;
     }
 
     /* try to open parent images, if exist */
     if (vmdk_parent_open(bs)) {
-        g_free(s->extents);
+        vmdk_free_extents(bs);
         return -EINVAL;
     }
     s->parent_cid = vmdk_read_cid(bs, 1);
commit 7285477ab11831b1cf56e45878a89170dd06d9b9
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Fri Sep 16 16:40:04 2011 +0200

    scsi-disk: lazily allocate bounce buffer
    
    It will not be needed for reads and writes if the HBA provides a sglist.
    In addition, this lets scsi-disk refuse commands with an excessive
    allocation length, as well as limit memory on usual well-behaved guests.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 84e8662..48abe49 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -55,6 +55,7 @@ typedef struct SCSIDiskReq {
     /* Both sector and sector_count are in terms of qemu 512 byte blocks.  */
     uint64_t sector;
     uint32_t sector_count;
+    uint32_t buflen;
     struct iovec iov;
     QEMUIOVector qiov;
     uint32_t status;
@@ -78,13 +79,15 @@ struct SCSIDiskState
 };
 
 static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type);
-static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf);
+static int scsi_disk_emulate_command(SCSIDiskReq *r);
 
 static void scsi_free_request(SCSIRequest *req)
 {
     SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
 
-    qemu_vfree(r->iov.iov_base);
+    if (r->iov.iov_base) {
+        qemu_vfree(r->iov.iov_base);
+    }
 }
 
 /* Helper function for command completion with sense.  */
@@ -110,7 +113,13 @@ static void scsi_cancel_io(SCSIRequest *req)
 
 static uint32_t scsi_init_iovec(SCSIDiskReq *r)
 {
-    r->iov.iov_len = MIN(r->sector_count * 512, SCSI_DMA_BUF_SIZE);
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+
+    if (!r->iov.iov_base) {
+        r->buflen = SCSI_DMA_BUF_SIZE;
+        r->iov.iov_base = qemu_blockalign(s->bs, r->buflen);
+    }
+    r->iov.iov_len = MIN(r->sector_count * 512, r->buflen);
     qemu_iovec_init_external(&r->qiov, &r->iov, 1);
     return r->qiov.size / 512;
 }
@@ -323,7 +332,7 @@ static void scsi_dma_restart_bh(void *opaque)
                 scsi_write_data(&r->req);
                 break;
             case SCSI_REQ_STATUS_RETRY_FLUSH:
-                ret = scsi_disk_emulate_command(r, r->iov.iov_base);
+                ret = scsi_disk_emulate_command(r);
                 if (ret == 0) {
                     scsi_req_complete(&r->req, GOOD);
                 }
@@ -838,13 +847,31 @@ static int scsi_disk_emulate_start_stop(SCSIDiskReq *r)
     return 0;
 }
 
-static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
+static int scsi_disk_emulate_command(SCSIDiskReq *r)
 {
     SCSIRequest *req = &r->req;
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
     uint64_t nb_sectors;
+    uint8_t *outbuf;
     int buflen = 0;
 
+    if (!r->iov.iov_base) {
+        /*
+         * FIXME: we shouldn't return anything bigger than 4k, but the code
+         * requires the buffer to be as big as req->cmd.xfer in several
+         * places.  So, do not allow CDBs with a very large ALLOCATION
+         * LENGTH.  The real fix would be to modify scsi_read_data and
+         * dma_buf_read, so that they return data beyond the buflen
+         * as all zeros.
+         */
+        if (req->cmd.xfer > 65536) {
+            goto illegal_request;
+        }
+        r->buflen = MAX(4096, req->cmd.xfer);
+        r->iov.iov_base = qemu_blockalign(s->bs, r->buflen);
+    }
+
+    outbuf = r->iov.iov_base;
     switch (req->cmd.buf[0]) {
     case TEST_UNIT_READY:
         if (s->tray_open || !bdrv_is_inserted(s->bs))
@@ -995,11 +1022,9 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
     int32_t len;
     uint8_t command;
-    uint8_t *outbuf;
     int rc;
 
     command = buf[0];
-    outbuf = (uint8_t *)r->iov.iov_base;
     DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", req->lun, req->tag, buf[0]);
 
 #ifdef DEBUG_SCSI
@@ -1028,7 +1053,7 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
     case GET_CONFIGURATION:
     case SERVICE_ACTION_IN_16:
     case VERIFY_10:
-        rc = scsi_disk_emulate_command(r, outbuf);
+        rc = scsi_disk_emulate_command(r);
         if (rc < 0) {
             return 0;
         }
@@ -1279,11 +1304,8 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag,
 {
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
     SCSIRequest *req;
-    SCSIDiskReq *r;
 
     req = scsi_req_alloc(&scsi_disk_reqops, &s->qdev, tag, lun, hba_private);
-    r = DO_UPCAST(SCSIDiskReq, req, req);
-    r->iov.iov_base = qemu_blockalign(s->bs, SCSI_DMA_BUF_SIZE);
     return req;
 }
 
commit 103b40f51e4012b3b0ad20f615562a1806d7f49a
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Fri Sep 16 16:40:03 2011 +0200

    scsi-disk: commonize iovec creation between reads and writes
    
    Also, consistently use qiov.size instead of iov.iov_len.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 4a60820..84e8662 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -108,6 +108,13 @@ static void scsi_cancel_io(SCSIRequest *req)
     r->req.aiocb = NULL;
 }
 
+static uint32_t scsi_init_iovec(SCSIDiskReq *r)
+{
+    r->iov.iov_len = MIN(r->sector_count * 512, SCSI_DMA_BUF_SIZE);
+    qemu_iovec_init_external(&r->qiov, &r->iov, 1);
+    return r->qiov.size / 512;
+}
+
 static void scsi_read_complete(void * opaque, int ret)
 {
     SCSIDiskReq *r = (SCSIDiskReq *)opaque;
@@ -125,12 +132,12 @@ static void scsi_read_complete(void * opaque, int ret)
         }
     }
 
-    DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->iov.iov_len);
+    DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->qiov.size);
 
-    n = r->iov.iov_len / 512;
+    n = r->qiov.size / 512;
     r->sector += n;
     r->sector_count -= n;
-    scsi_req_data(&r->req, r->iov.iov_len);
+    scsi_req_data(&r->req, r->qiov.size);
 }
 
 static void scsi_flush_complete(void * opaque, int ret)
@@ -181,16 +188,10 @@ static void scsi_read_data(SCSIRequest *req)
         return;
     }
 
-    n = r->sector_count;
-    if (n > SCSI_DMA_BUF_SIZE / 512)
-        n = SCSI_DMA_BUF_SIZE / 512;
-
     if (s->tray_open) {
         scsi_read_complete(r, -ENOMEDIUM);
     }
-    r->iov.iov_len = n * 512;
-    qemu_iovec_init_external(&r->qiov, &r->iov, 1);
-
+    n = scsi_init_iovec(r);
     bdrv_acct_start(s->bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
     r->req.aiocb = bdrv_aio_readv(s->bs, r->sector, &r->qiov, n,
                               scsi_read_complete, r);
@@ -239,7 +240,6 @@ static void scsi_write_complete(void * opaque, int ret)
 {
     SCSIDiskReq *r = (SCSIDiskReq *)opaque;
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
-    uint32_t len;
     uint32_t n;
 
     if (r->req.aiocb != NULL) {
@@ -253,19 +253,15 @@ static void scsi_write_complete(void * opaque, int ret)
         }
     }
 
-    n = r->iov.iov_len / 512;
+    n = r->qiov.size / 512;
     r->sector += n;
     r->sector_count -= n;
     if (r->sector_count == 0) {
         scsi_req_complete(&r->req, GOOD);
     } else {
-        len = r->sector_count * 512;
-        if (len > SCSI_DMA_BUF_SIZE) {
-            len = SCSI_DMA_BUF_SIZE;
-        }
-        r->iov.iov_len = len;
-        DPRINTF("Write complete tag=0x%x more=%d\n", r->req.tag, len);
-        scsi_req_data(&r->req, len);
+        scsi_init_iovec(r);
+        DPRINTF("Write complete tag=0x%x more=%d\n", r->req.tag, r->qiov.size);
+        scsi_req_data(&r->req, r->qiov.size);
     }
 }
 
@@ -284,21 +280,19 @@ static void scsi_write_data(SCSIRequest *req)
         return;
     }
 
-    n = r->iov.iov_len / 512;
+    n = r->qiov.size / 512;
     if (n) {
         if (s->tray_open) {
             scsi_write_complete(r, -ENOMEDIUM);
         }
-        qemu_iovec_init_external(&r->qiov, &r->iov, 1);
-
         bdrv_acct_start(s->bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_WRITE);
         r->req.aiocb = bdrv_aio_writev(s->bs, r->sector, &r->qiov, n,
-                                   scsi_write_complete, r);
+                                       scsi_write_complete, r);
         if (r->req.aiocb == NULL) {
             scsi_write_complete(r, -ENOMEM);
         }
     } else {
-        /* Invoke completion routine to fetch data from host.  */
+        /* Called for the first time.  Ask the driver to send us more data.  */
         scsi_write_complete(r, 0);
     }
 }
commit c3adb5b9168a57790b5074489b6f0275ac3cc8b5
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Fri Sep 16 16:40:02 2011 +0200

    dma-helpers: rewrite completion/cancellation
    
    This fixes various problems with completion/cancellation:
    
    * if the io_func fails to get an AIOCB, the callback wasn't called
    
    * If DMA encounters a bounce buffer conflict, and the DMA operation is
    canceled before the bottom half fires, bad things happen.
    
    * memory is not unmapped after cancellation, again causing problems
    when doing DMA to I/O areas
    
    * cancellation could leak the iovec
    
    * the callback was missed if the I/O operation failed without returning
    an AIOCB
    
    and probably more that I've missed.  The patch fixes them by sharing
    the cleanup code between completion and cancellation.  The dma_bdrv_cb
    now returns a boolean completed/not completed flag, and the wrapper
    dma_continue takes care of tasks to do upon completion.
    
    Most of these are basically impossible in practice, but it is better
    to be tidy...
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/dma-helpers.c b/dma-helpers.c
index 717e384..86d2d0a 100644
--- a/dma-helpers.c
+++ b/dma-helpers.c
@@ -43,6 +43,7 @@ typedef struct {
     QEMUSGList *sg;
     uint64_t sector_num;
     bool to_dev;
+    bool in_cancel;
     int sg_cur_index;
     target_phys_addr_t sg_cur_byte;
     QEMUIOVector iov;
@@ -58,7 +59,7 @@ static void reschedule_dma(void *opaque)
 
     qemu_bh_delete(dbs->bh);
     dbs->bh = NULL;
-    dma_bdrv_cb(opaque, 0);
+    dma_bdrv_cb(dbs, 0);
 }
 
 static void continue_after_map_failure(void *opaque)
@@ -78,6 +79,26 @@ static void dma_bdrv_unmap(DMAAIOCB *dbs)
                                   dbs->iov.iov[i].iov_len, !dbs->to_dev,
                                   dbs->iov.iov[i].iov_len);
     }
+    qemu_iovec_reset(&dbs->iov);
+}
+
+static void dma_complete(DMAAIOCB *dbs, int ret)
+{
+    dma_bdrv_unmap(dbs);
+    if (dbs->common.cb) {
+        dbs->common.cb(dbs->common.opaque, ret);
+    }
+    qemu_iovec_destroy(&dbs->iov);
+    if (dbs->bh) {
+        qemu_bh_delete(dbs->bh);
+        dbs->bh = NULL;
+    }
+    if (!dbs->in_cancel) {
+        /* Requests may complete while dma_aio_cancel is in progress.  In
+         * this case, the AIOCB should not be released because it is still
+         * referenced by dma_aio_cancel.  */
+        qemu_aio_release(dbs);
+    }
 }
 
 static void dma_bdrv_cb(void *opaque, int ret)
@@ -89,12 +110,9 @@ static void dma_bdrv_cb(void *opaque, int ret)
     dbs->acb = NULL;
     dbs->sector_num += dbs->iov.size / 512;
     dma_bdrv_unmap(dbs);
-    qemu_iovec_reset(&dbs->iov);
 
     if (dbs->sg_cur_index == dbs->sg->nsg || ret < 0) {
-        dbs->common.cb(dbs->common.opaque, ret);
-        qemu_iovec_destroy(&dbs->iov);
-        qemu_aio_release(dbs);
+        dma_complete(dbs, ret);
         return;
     }
 
@@ -120,9 +138,7 @@ static void dma_bdrv_cb(void *opaque, int ret)
     dbs->acb = dbs->io_func(dbs->bs, dbs->sector_num, &dbs->iov,
                             dbs->iov.size / 512, dma_bdrv_cb, dbs);
     if (!dbs->acb) {
-        dma_bdrv_unmap(dbs);
-        qemu_iovec_destroy(&dbs->iov);
-        return;
+        dma_complete(dbs, -EIO);
     }
 }
 
@@ -131,8 +147,14 @@ static void dma_aio_cancel(BlockDriverAIOCB *acb)
     DMAAIOCB *dbs = container_of(acb, DMAAIOCB, common);
 
     if (dbs->acb) {
-        bdrv_aio_cancel(dbs->acb);
+        BlockDriverAIOCB *acb = dbs->acb;
+        dbs->acb = NULL;
+        dbs->in_cancel = true;
+        bdrv_aio_cancel(acb);
+        dbs->in_cancel = false;
     }
+    dbs->common.cb = NULL;
+    dma_complete(dbs, 0);
 }
 
 static AIOPool dma_aio_pool = {
@@ -158,10 +180,6 @@ BlockDriverAIOCB *dma_bdrv_io(
     dbs->bh = NULL;
     qemu_iovec_init(&dbs->iov, sg->nsg);
     dma_bdrv_cb(dbs, 0);
-    if (!dbs->acb) {
-        qemu_aio_release(dbs);
-        return NULL;
-    }
     return &dbs->common;
 }
 
commit 10dc8aef419b4ce77670fb080ffe995bf9d7b0a1
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Fri Sep 16 16:40:01 2011 +0200

    dma-helpers: allow including from target-independent code
    
    Target-independent code cannot construct sglists, but it can take
    them from the outside as a black box.  Allow this.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/dma.h b/dma.h
index b222346..2bdc236 100644
--- a/dma.h
+++ b/dma.h
@@ -15,10 +15,13 @@
 #include "hw/hw.h"
 #include "block.h"
 
-typedef struct {
+typedef struct ScatterGatherEntry ScatterGatherEntry;
+
+#if defined(TARGET_PHYS_ADDR_BITS)
+struct ScatterGatherEntry {
     target_phys_addr_t base;
     target_phys_addr_t len;
-} ScatterGatherEntry;
+};
 
 struct QEMUSGList {
     ScatterGatherEntry *sg;
@@ -31,6 +34,7 @@ void qemu_sglist_init(QEMUSGList *qsg, int alloc_hint);
 void qemu_sglist_add(QEMUSGList *qsg, target_phys_addr_t base,
                      target_phys_addr_t len);
 void qemu_sglist_destroy(QEMUSGList *qsg);
+#endif
 
 typedef BlockDriverAIOCB *DMAIOFunc(BlockDriverState *bs, int64_t sector_num,
                                  QEMUIOVector *iov, int nb_sectors,
commit 7df32ca08ad0afdac623e43a99984c26177468f0
Author: Michael S. Tsirkin <mst at redhat.com>
Date:   Sun Sep 4 16:50:55 2011 +0300

    pci: implement bridge filtering
    
    Support bridge filtering on top of the memory
    API as suggested by Avi Kivity:
    
    Create a memory region for the bridge's address space.  This region is
    not directly added to system_memory or its descendants.  Devices under
    the bridge see this region as its pci_address_space().  The region is
    as large as the entire address space - it does not take into account
    any windows.
    
    For each of the three windows (pref, non-pref, vga), create an alias
    with the appropriate start and size.  Map the alias into the bridge's
    parent's pci_address_space(), as subregions.
    
    Signed-off-by: Michael S. Tsirkin <mst at redhat.com>

diff --git a/hw/pci.c b/hw/pci.c
index 0765963..5c4f071 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -878,7 +878,6 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
     r = &pci_dev->io_regions[region_num];
     r->addr = PCI_BAR_UNMAPPED;
     r->size = size;
-    r->filtered_size = size;
     r->type = type;
     r->memory = NULL;
 
@@ -909,41 +908,6 @@ pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num)
     return pci_dev->io_regions[region_num].addr;
 }
 
-static void pci_bridge_filter(PCIDevice *d, pcibus_t *addr, pcibus_t *size,
-                              uint8_t type)
-{
-    pcibus_t base = *addr;
-    pcibus_t limit = *addr + *size - 1;
-    PCIDevice *br;
-
-    for (br = d->bus->parent_dev; br; br = br->bus->parent_dev) {
-        uint16_t cmd = pci_get_word(d->config + PCI_COMMAND);
-
-        if (type & PCI_BASE_ADDRESS_SPACE_IO) {
-            if (!(cmd & PCI_COMMAND_IO)) {
-                goto no_map;
-            }
-        } else {
-            if (!(cmd & PCI_COMMAND_MEMORY)) {
-                goto no_map;
-            }
-        }
-
-        base = MAX(base, pci_bridge_get_base(br, type));
-        limit = MIN(limit, pci_bridge_get_limit(br, type));
-    }
-
-    if (base > limit) {
-        goto no_map;
-    }
-    *addr = base;
-    *size = limit - base + 1;
-    return;
-no_map:
-    *addr = PCI_BAR_UNMAPPED;
-    *size = 0;
-}
-
 static pcibus_t pci_bar_address(PCIDevice *d,
 				int reg, uint8_t type, pcibus_t size)
 {
@@ -1013,7 +977,7 @@ static void pci_update_mappings(PCIDevice *d)
 {
     PCIIORegion *r;
     int i;
-    pcibus_t new_addr, filtered_size;
+    pcibus_t new_addr;
 
     for(i = 0; i < PCI_NUM_REGIONS; i++) {
         r = &d->io_regions[i];
@@ -1024,14 +988,8 @@ static void pci_update_mappings(PCIDevice *d)
 
         new_addr = pci_bar_address(d, i, r->type, r->size);
 
-        /* bridge filtering */
-        filtered_size = r->size;
-        if (new_addr != PCI_BAR_UNMAPPED) {
-            pci_bridge_filter(d, &new_addr, &filtered_size, r->type);
-        }
-
         /* This bar isn't changed */
-        if (new_addr == r->addr && filtered_size == r->filtered_size)
+        if (new_addr == r->addr)
             continue;
 
         /* now do the real mapping */
@@ -1039,15 +997,7 @@ static void pci_update_mappings(PCIDevice *d)
             memory_region_del_subregion(r->address_space, r->memory);
         }
         r->addr = new_addr;
-        r->filtered_size = filtered_size;
         if (r->addr != PCI_BAR_UNMAPPED) {
-            /*
-             * TODO: currently almost all the map funcions assumes
-             * filtered_size == size and addr & ~(size - 1) == addr.
-             * However with bridge filtering, they aren't always true.
-             * Teach them such cases, such that filtered_size < size and
-             * addr & (size - 1) != 0.
-             */
             if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
                 memory_region_add_subregion_overlap(r->address_space,
                                                     r->addr,
@@ -1564,22 +1514,6 @@ PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model,
     return res;
 }
 
-static void pci_bridge_update_mappings_fn(PCIBus *b, PCIDevice *d)
-{
-    pci_update_mappings(d);
-}
-
-void pci_bridge_update_mappings(PCIBus *b)
-{
-    PCIBus *child;
-
-    pci_for_each_device_under_bus(b, pci_bridge_update_mappings_fn);
-
-    QLIST_FOREACH(child, &b->child, sibling) {
-        pci_bridge_update_mappings(child);
-    }
-}
-
 /* Whether a given bus number is in range of the secondary
  * bus of the given bridge device. */
 static bool pci_secondary_bus_in_range(PCIDevice *dev, int bus_num)
diff --git a/hw/pci.h b/hw/pci.h
index ce317bf..7b62df1 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -90,7 +90,6 @@ typedef struct PCIIORegion {
     pcibus_t addr; /* current PCI mapping address. -1 means not mapped */
 #define PCI_BAR_UNMAPPED (~(pcibus_t)0)
     pcibus_t size;
-    pcibus_t filtered_size;
     uint8_t type;
     MemoryRegion *memory;
     MemoryRegion *address_space;
@@ -273,7 +272,6 @@ int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
 
 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);
 
 void pci_device_deassert_intx(PCIDevice *dev);
 
diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c
index e0b339e..25e9b7c 100644
--- a/hw/pci_bridge.c
+++ b/hw/pci_bridge.c
@@ -135,6 +135,77 @@ pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type)
     return limit;
 }
 
+static void pci_bridge_init_alias(PCIBridge *bridge, MemoryRegion *alias,
+                                  uint8_t type, const char *name,
+                                  MemoryRegion *space,
+                                  MemoryRegion *parent_space,
+                                  bool enabled)
+{
+    pcibus_t base = pci_bridge_get_base(&bridge->dev, type);
+    pcibus_t limit = pci_bridge_get_limit(&bridge->dev, type);
+    /* TODO: this doesn't handle base = 0 limit = 2^64 - 1 correctly.
+     * Apparently no way to do this with existing memory APIs. */
+    pcibus_t size = enabled && limit >= base ? limit + 1 - base : 0;
+
+    memory_region_init_alias(alias, name, space, base, size);
+    memory_region_add_subregion_overlap(parent_space, base, alias, 1);
+}
+
+static void pci_bridge_cleanup_alias(MemoryRegion *alias,
+                                     MemoryRegion *parent_space)
+{
+    memory_region_del_subregion(parent_space, alias);
+    memory_region_destroy(alias);
+}
+
+static void pci_bridge_region_init(PCIBridge *br)
+{
+    PCIBus *sec_bus = &br->sec_bus;
+    PCIBus *parent = br->dev.bus;
+    uint16_t cmd = pci_get_word(br->dev.config + PCI_COMMAND);
+
+    pci_bridge_init_alias(br, &br->alias_pref_mem,
+                          PCI_BASE_ADDRESS_MEM_PREFETCH,
+                          "pci_bridge_pref_mem",
+                          sec_bus->address_space_mem,
+                          parent->address_space_mem,
+                          cmd & PCI_COMMAND_MEMORY);
+    pci_bridge_init_alias(br, &br->alias_mem,
+                          PCI_BASE_ADDRESS_SPACE_MEMORY,
+                          "pci_bridge_mem",
+                          sec_bus->address_space_mem,
+                          parent->address_space_mem,
+                          cmd & PCI_COMMAND_MEMORY);
+    pci_bridge_init_alias(br, &br->alias_io,
+                          PCI_BASE_ADDRESS_SPACE_IO,
+                          "pci_bridge_io",
+                          sec_bus->address_space_io,
+                          parent->address_space_io,
+                          cmd & PCI_COMMAND_IO);
+   /* TODO: optinal VGA and VGA palette snooping support. */
+}
+
+static void pci_bridge_region_cleanup(PCIBridge *br)
+{
+    PCIBus *parent = br->dev.bus;
+    pci_bridge_cleanup_alias(&br->alias_io,
+                             parent->address_space_io);
+    pci_bridge_cleanup_alias(&br->alias_mem,
+                             parent->address_space_mem);
+    pci_bridge_cleanup_alias(&br->alias_pref_mem,
+                             parent->address_space_mem);
+}
+
+static void pci_bridge_update_mappings(PCIBridge *br)
+{
+    /* Make updates atomic to: handle the case of one VCPU updating the bridge
+     * while another accesses an unaffected region. */
+    memory_region_transaction_begin();
+    pci_bridge_region_cleanup(br);
+    pci_bridge_region_init(br);
+    memory_region_transaction_commit();
+}
+
 /* default write_config function for PCI-to-PCI bridge */
 void pci_bridge_write_config(PCIDevice *d,
                              uint32_t address, uint32_t val, int len)
@@ -145,13 +216,15 @@ void pci_bridge_write_config(PCIDevice *d,
 
     pci_default_write_config(d, address, val, len);
 
-    if (/* io base/limit */
+    if (ranges_overlap(address, len, PCI_COMMAND, 2) ||
+
+        /* io base/limit */
         ranges_overlap(address, len, PCI_IO_BASE, 2) ||
 
         /* memory base/limit, prefetchable base/limit and
            io base/limit upper 16 */
         ranges_overlap(address, len, PCI_MEMORY_BASE, 20)) {
-        pci_bridge_update_mappings(&s->sec_bus);
+        pci_bridge_update_mappings(s);
     }
 
     newctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL);
@@ -246,10 +319,11 @@ int pci_bridge_initfn(PCIDevice *dev)
                         br->bus_name);
     sec_bus->parent_dev = dev;
     sec_bus->map_irq = br->map_irq;
-    /* TODO: use memory API to perform memory filtering. */
-    sec_bus->address_space_mem = parent->address_space_mem;
-    sec_bus->address_space_io = parent->address_space_io;
-
+    sec_bus->address_space_mem = g_new(MemoryRegion, 1);
+    memory_region_init(sec_bus->address_space_mem, "pci_pridge_pci", INT64_MAX);
+    sec_bus->address_space_io = g_new(MemoryRegion, 1);
+    memory_region_init(sec_bus->address_space_io, "pci_bridge_io", 65536);
+    pci_bridge_region_init(br);
     QLIST_INIT(&sec_bus->child);
     QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling);
     return 0;
@@ -259,8 +333,14 @@ int pci_bridge_initfn(PCIDevice *dev)
 int pci_bridge_exitfn(PCIDevice *pci_dev)
 {
     PCIBridge *s = DO_UPCAST(PCIBridge, dev, pci_dev);
+    PCIBus *sec_bus = &s->sec_bus;
     assert(QLIST_EMPTY(&s->sec_bus.child));
     QLIST_REMOVE(&s->sec_bus, sibling);
+    pci_bridge_region_cleanup(s);
+    memory_region_destroy(sec_bus->address_space_mem);
+    g_free(sec_bus->address_space_mem);
+    memory_region_destroy(sec_bus->address_space_io);
+    g_free(sec_bus->address_space_io);
     /* qbus_free() is called automatically by qdev_free() */
     return 0;
 }
diff --git a/hw/pci_internals.h b/hw/pci_internals.h
index 10b4adf..71c8b51 100644
--- a/hw/pci_internals.h
+++ b/hw/pci_internals.h
@@ -41,6 +41,9 @@ struct PCIBridge {
 
     /* private member */
     PCIBus sec_bus;
+    MemoryRegion alias_pref_mem;
+    MemoryRegion alias_mem;
+    MemoryRegion alias_io;
     pci_map_irq_fn map_irq;
     const char *bus_name;
 };
commit 778d1799397e1353b69f16547d359f944fb49ea6
Author: Wen Congyang <wency at cn.fujitsu.com>
Date:   Fri Aug 26 13:00:33 2011 +0300

    pci_bridge: use parent bus's address space
    
    The switch to the new memory API caused the following problem:
    
    The pci device may call pci_register_bar() to use PCI bus's address
    space.  But we don't init PCI bus's address space if it is not bus
    0.  A crash was reported:
    http://lists.gnu.org/archive/html/qemu-devel/2011-08/msg02243.html
    
    More work will be needed to make bridge filtering work correctly
    with the memory API.
    
    Signed-off-by: Wen Congyang <wency at cn.fujitsu.com>
    Signed-off-by: Michael S. Tsirkin <mst at redhat.com>

diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c
index 464d897..e0b339e 100644
--- a/hw/pci_bridge.c
+++ b/hw/pci_bridge.c
@@ -246,6 +246,9 @@ int pci_bridge_initfn(PCIDevice *dev)
                         br->bus_name);
     sec_bus->parent_dev = dev;
     sec_bus->map_irq = br->map_irq;
+    /* TODO: use memory API to perform memory filtering. */
+    sec_bus->address_space_mem = parent->address_space_mem;
+    sec_bus->address_space_io = parent->address_space_io;
 
     QLIST_INIT(&sec_bus->child);
     QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling);
commit a92eb87a4463230620e14e4f1b19a740be4058c3
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Mon Sep 12 15:17:53 2011 +0200

    pci: Remove unused mem_base from PCIBus
    
    Obsoleted by f64e02b6cc.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Michael S. Tsirkin <mst at redhat.com>

diff --git a/hw/pci_internals.h b/hw/pci_internals.h
index c7fd23d..10b4adf 100644
--- a/hw/pci_internals.h
+++ b/hw/pci_internals.h
@@ -24,7 +24,6 @@ struct PCIBus {
     void *irq_opaque;
     PCIDevice *devices[PCI_SLOT_MAX * PCI_FUNC_MAX];
     PCIDevice *parent_dev;
-    target_phys_addr_t mem_base;
     MemoryRegion *address_space_mem;
     MemoryRegion *address_space_io;
 
commit 817e0b6fe8324de8dbd4bec9184c207754618365
Author: Michael S. Tsirkin <mst at redhat.com>
Date:   Sun Sep 11 13:40:23 2011 +0300

    pci: interrupt pin documentation update
    
    Fix up some erroneous comments in code:
    interrupt pins are named A-D, the
    interrupt pin register is always readonly
    and isn't zeroed out on reset.
    
    Signed-off-by: Michael S. Tsirkin <mst at redhat.com>

diff --git a/hw/ac97.c b/hw/ac97.c
index 541d9a4..bc69d4e 100644
--- a/hw/ac97.c
+++ b/hw/ac97.c
@@ -1311,7 +1311,6 @@ static int ac97_initfn (PCIDevice *dev)
     c[PCI_SUBSYSTEM_ID + 1] = 0x00;
 
     c[PCI_INTERRUPT_LINE] = 0x00;      /* intr_ln interrupt line rw */
-    /* TODO: RST# value should be 0. */
     c[PCI_INTERRUPT_PIN] = 0x01;      /* intr_pn interrupt pin ro */
 
     memory_region_init_io (&s->io_nam, &ac97_io_nam_ops, s, "ac97-nam", 1024);
diff --git a/hw/e1000.c b/hw/e1000.c
index a6d12c5..6a3a941 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -1156,8 +1156,7 @@ static int pci_e1000_init(PCIDevice *pci_dev)
     /* TODO: RST# value should be 0, PCI spec 6.2.4 */
     pci_conf[PCI_CACHE_LINE_SIZE] = 0x10;
 
-    /* TODO: RST# value should be 0 if programmable, PCI spec 6.2.4 */
-    pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0
+    pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
 
     e1000_mmio_setup(d);
 
diff --git a/hw/es1370.c b/hw/es1370.c
index a9387d1..2daadde 100644
--- a/hw/es1370.c
+++ b/hw/es1370.c
@@ -1003,7 +1003,6 @@ static int es1370_initfn (PCIDevice *dev)
     c[0xdc] = 0x00;
 #endif
 
-    /* TODO: RST# value should be 0. */
     c[PCI_INTERRUPT_PIN] = 1;
     c[PCI_MIN_GNT] = 0x0c;
     c[PCI_MAX_LAT] = 0x80;
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index dbb3bdf..75a03a7 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -2106,8 +2106,7 @@ static int lsi_scsi_init(PCIDevice *dev)
 
     /* PCI latency timer = 255 */
     pci_conf[PCI_LATENCY_TIMER] = 0xff;
-    /* TODO: RST# value should be 0 */
-    /* Interrupt pin 1 */
+    /* Interrupt pin A */
     pci_conf[PCI_INTERRUPT_PIN] = 0x01;
 
     memory_region_init_io(&s->mmio_io, &lsi_mmio_ops, s, "lsi-mmio", 0x400);
diff --git a/hw/ne2000.c b/hw/ne2000.c
index a035a85..62e082f 100644
--- a/hw/ne2000.c
+++ b/hw/ne2000.c
@@ -749,8 +749,7 @@ static int pci_ne2000_init(PCIDevice *pci_dev)
     uint8_t *pci_conf;
 
     pci_conf = d->dev.config;
-    /* TODO: RST# value should be 0. PCI spec 6.2.4 */
-    pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0
+    pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
 
     s = &d->ne2000;
     ne2000_setup_io(s, 0x100);
diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c
index 51e1320..fb2a00c 100644
--- a/hw/pcnet-pci.c
+++ b/hw/pcnet-pci.c
@@ -285,7 +285,7 @@ static int pci_pcnet_init(PCIDevice *pci_dev)
     pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, 0x0);
     pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0);
 
-    pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0
+    pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
     pci_conf[PCI_MIN_GNT] = 0x06;
     pci_conf[PCI_MAX_LAT] = 0xff;
 
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index c5de5b4..3753950 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -3464,7 +3464,7 @@ static int pci_rtl8139_init(PCIDevice *dev)
     uint8_t *pci_conf;
 
     pci_conf = s->dev.config;
-    pci_conf[PCI_INTERRUPT_PIN] = 1;    /* interrupt pin 0 */
+    pci_conf[PCI_INTERRUPT_PIN] = 1;    /* interrupt pin A */
     /* TODO: start of capability list, but no capability
      * list bit in status register, and offset 0xdc seems unused. */
     pci_conf[PCI_CAPABILITY_LIST] = 0xdc;
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index e9e0789..27376a2 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -2291,7 +2291,7 @@ static int usb_ehci_initfn(PCIDevice *dev)
     pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x00);
     //pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x50);
 
-    pci_set_byte(&pci_conf[PCI_INTERRUPT_PIN], 4); // interrupt pin 3
+    pci_set_byte(&pci_conf[PCI_INTERRUPT_PIN], 4); /* interrupt pin D */
     pci_set_byte(&pci_conf[PCI_MIN_GNT], 0);
     pci_set_byte(&pci_conf[PCI_MAX_LAT], 0);
 
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index 503ca2d..c3be65a 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -1780,8 +1780,7 @@ static int usb_ohci_initfn_pci(struct PCIDevice *dev)
     OHCIPCIState *ohci = DO_UPCAST(OHCIPCIState, pci_dev, dev);
 
     ohci->pci_dev.config[PCI_CLASS_PROG] = 0x10; /* OHCI */
-    /* TODO: RST# value should be 0. */
-    ohci->pci_dev.config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin 1 */
+    ohci->pci_dev.config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
 
     if (usb_ohci_init(&ohci->state, &dev->qdev, ohci->num_ports, 0,
                       ohci->masterbus, ohci->firstport) != 0) {
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index 64f7b36..17992cf 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -1131,7 +1131,7 @@ static int usb_uhci_common_initfn(PCIDevice *dev)
 
     pci_conf[PCI_CLASS_PROG] = 0x00;
     /* TODO: reset value should be 0. */
-    pci_conf[PCI_INTERRUPT_PIN] = 4; // interrupt pin 3
+    pci_conf[PCI_INTERRUPT_PIN] = 4; /* interrupt pin D */
     pci_conf[USB_SBRN] = USB_RELEASE_1; // release number
 
     if (s->masterbus) {
commit ab346bb23f4ba6f78392b1e55e01a9e58b993887
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Thu Sep 8 12:44:47 2011 +0200

    pci: Remove unused pci_reserve_capability
    
    eepro100 was the last user. Now pci_add_capability is powerful enough.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Michael S. Tsirkin <mst at redhat.com>

diff --git a/hw/pci.c b/hw/pci.c
index af74003..0765963 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -2016,12 +2016,6 @@ void pci_del_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)
         pdev->config[PCI_STATUS] &= ~PCI_STATUS_CAP_LIST;
 }
 
-/* Reserve space for capability at a known offset (to call after load). */
-void pci_reserve_capability(PCIDevice *pdev, uint8_t offset, uint8_t size)
-{
-    memset(pdev->used + offset, 0xff, size);
-}
-
 uint8_t pci_find_capability(PCIDevice *pdev, uint8_t cap_id)
 {
     return pci_find_capability_list(pdev, cap_id, NULL);
diff --git a/hw/pci.h b/hw/pci.h
index c04b169..ce317bf 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -209,8 +209,6 @@ int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
 
 void pci_del_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size);
 
-void pci_reserve_capability(PCIDevice *pci_dev, uint8_t offset, uint8_t size);
-
 uint8_t pci_find_capability(PCIDevice *pci_dev, uint8_t cap_id);
 
 
commit bbca72c6215c3e1df72b80bb3f54fe3b2b05212b
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Fri Sep 16 16:40:00 2011 +0200

    dma-helpers: rename is_write to to_dev
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/dma-helpers.c b/dma-helpers.c
index 4610ea0..717e384 100644
--- a/dma-helpers.c
+++ b/dma-helpers.c
@@ -42,7 +42,7 @@ typedef struct {
     BlockDriverAIOCB *acb;
     QEMUSGList *sg;
     uint64_t sector_num;
-    int is_write;
+    bool to_dev;
     int sg_cur_index;
     target_phys_addr_t sg_cur_byte;
     QEMUIOVector iov;
@@ -75,7 +75,7 @@ static void dma_bdrv_unmap(DMAAIOCB *dbs)
 
     for (i = 0; i < dbs->iov.niov; ++i) {
         cpu_physical_memory_unmap(dbs->iov.iov[i].iov_base,
-                                  dbs->iov.iov[i].iov_len, !dbs->is_write,
+                                  dbs->iov.iov[i].iov_len, !dbs->to_dev,
                                   dbs->iov.iov[i].iov_len);
     }
 }
@@ -101,7 +101,7 @@ static void dma_bdrv_cb(void *opaque, int ret)
     while (dbs->sg_cur_index < dbs->sg->nsg) {
         cur_addr = dbs->sg->sg[dbs->sg_cur_index].base + dbs->sg_cur_byte;
         cur_len = dbs->sg->sg[dbs->sg_cur_index].len - dbs->sg_cur_byte;
-        mem = cpu_physical_memory_map(cur_addr, &cur_len, !dbs->is_write);
+        mem = cpu_physical_memory_map(cur_addr, &cur_len, !dbs->to_dev);
         if (!mem)
             break;
         qemu_iovec_add(&dbs->iov, mem, cur_len);
@@ -143,7 +143,7 @@ static AIOPool dma_aio_pool = {
 BlockDriverAIOCB *dma_bdrv_io(
     BlockDriverState *bs, QEMUSGList *sg, uint64_t sector_num,
     DMAIOFunc *io_func, BlockDriverCompletionFunc *cb,
-    void *opaque, int is_write)
+    void *opaque, bool to_dev)
 {
     DMAAIOCB *dbs = qemu_aio_get(&dma_aio_pool, bs, cb, opaque);
 
@@ -153,7 +153,7 @@ BlockDriverAIOCB *dma_bdrv_io(
     dbs->sector_num = sector_num;
     dbs->sg_cur_index = 0;
     dbs->sg_cur_byte = 0;
-    dbs->is_write = is_write;
+    dbs->to_dev = to_dev;
     dbs->io_func = io_func;
     dbs->bh = NULL;
     qemu_iovec_init(&dbs->iov, sg->nsg);
@@ -170,12 +170,12 @@ BlockDriverAIOCB *dma_bdrv_read(BlockDriverState *bs,
                                 QEMUSGList *sg, uint64_t sector,
                                 void (*cb)(void *opaque, int ret), void *opaque)
 {
-    return dma_bdrv_io(bs, sg, sector, bdrv_aio_readv, cb, opaque, 0);
+    return dma_bdrv_io(bs, sg, sector, bdrv_aio_readv, cb, opaque, false);
 }
 
 BlockDriverAIOCB *dma_bdrv_write(BlockDriverState *bs,
                                  QEMUSGList *sg, uint64_t sector,
                                  void (*cb)(void *opaque, int ret), void *opaque)
 {
-    return dma_bdrv_io(bs, sg, sector, bdrv_aio_writev, cb, opaque, 1);
+    return dma_bdrv_io(bs, sg, sector, bdrv_aio_writev, cb, opaque, true);
 }
diff --git a/dma.h b/dma.h
index a6db5ba..b222346 100644
--- a/dma.h
+++ b/dma.h
@@ -39,7 +39,7 @@ typedef BlockDriverAIOCB *DMAIOFunc(BlockDriverState *bs, int64_t sector_num,
 BlockDriverAIOCB *dma_bdrv_io(BlockDriverState *bs,
                               QEMUSGList *sg, uint64_t sector_num,
                               DMAIOFunc *io_func, BlockDriverCompletionFunc *cb,
-                              void *opaque, int is_write);
+                              void *opaque, bool to_dev);
 BlockDriverAIOCB *dma_bdrv_read(BlockDriverState *bs,
                                 QEMUSGList *sg, uint64_t sector,
                                 BlockDriverCompletionFunc *cb, void *opaque);
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 9297b9e..f424347 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -603,7 +603,7 @@ handle_rw_error:
         break;
     case IDE_DMA_TRIM:
         s->bus->dma->aiocb = dma_bdrv_io(s->bs, &s->sg, sector_num,
-                                         ide_issue_trim, ide_dma_cb, s, 1);
+                                         ide_issue_trim, ide_dma_cb, s, true);
         break;
     }
 
diff --git a/hw/ide/macio.c b/hw/ide/macio.c
index c1844cb..37b8239 100644
--- a/hw/ide/macio.c
+++ b/hw/ide/macio.c
@@ -156,7 +156,7 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
         break;
     case IDE_DMA_TRIM:
         m->aiocb = dma_bdrv_io(s->bs, &s->sg, sector_num,
-                               ide_issue_trim, pmac_ide_transfer_cb, s, 1);
+                               ide_issue_trim, pmac_ide_transfer_cb, s, true);
         break;
     }
 
commit 1b8f8a6f9190996c617a177acc3b8fd7dff87e24
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Wed Sep 14 15:25:56 2011 +0200

    scsi-generic: do not disable FUA
    
    I found no rationale for this in the logs, and it is quite bad because
    it will make scsi-generic unsafe WRT power failures.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Reviewed-by: Christoph Hellwig <hch at lst.de>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 5ce01af..8f6b70d 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -244,12 +244,6 @@ static uint8_t *scsi_get_buf(SCSIRequest *req)
 static void scsi_req_fixup(SCSIRequest *req)
 {
     switch(req->cmd.buf[0]) {
-    case WRITE_10:
-        req->cmd.buf[1] &= ~0x08;	/* disable FUA */
-        break;
-    case READ_10:
-        req->cmd.buf[1] &= ~0x08;	/* disable FUA */
-        break;
     case REWIND:
     case START_STOP:
         if (req->dev->type == TYPE_TAPE) {
commit 074abad3264bf2bb7cfd279b7457416b318716ca
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Wed Sep 14 11:22:26 2011 +0200

    raw-posix: Fix bdrv_flush error return values
    
    bdrv_flush is supposed to use 0/-errno return values
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/raw-posix.c b/block/raw-posix.c
index a624f56..305998d 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -839,7 +839,14 @@ static int raw_create(const char *filename, QEMUOptionParameter *options)
 static int raw_flush(BlockDriverState *bs)
 {
     BDRVRawState *s = bs->opaque;
-    return qemu_fdatasync(s->fd);
+    int ret;
+
+    ret = qemu_fdatasync(s->fd);
+    if (ret < 0) {
+        return -errno;
+    }
+
+    return 0;
 }
 
 #ifdef CONFIG_XFS
commit 973b3d0a7b2823f510e948283284f103ede43c49
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Sep 8 17:24:56 2011 +0200

    nbd: support NBD_SET_FLAGS ioctl
    
    The nbd kernel module cannot enable DISCARD requests unless it is
    informed about it.  The flags field in the header is used for this,
    and this patch adds support for it.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/nbd.c b/nbd.c
index d32a19e..595f4d8 100644
--- a/nbd.c
+++ b/nbd.c
@@ -378,6 +378,14 @@ int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
         }
     }
 
+    if (ioctl(fd, NBD_SET_FLAGS, flags) < 0
+        && errno != ENOTTY) {
+        int serrno = errno;
+        LOG("Failed setting flags");
+        errno = serrno;
+        return -1;
+    }
+
     TRACE("Clearing NBD socket");
 
     if (ioctl(fd, NBD_CLEAR_SOCK) == -1) {
commit bbb74edd405bee8cf29957ef781294f40f02d4c6
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Sep 8 17:24:55 2011 +0200

    nbd: sync API definitions with upstream
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/nbd.c b/nbd.c
index 47ecb22..d32a19e 100644
--- a/nbd.c
+++ b/nbd.c
@@ -67,6 +67,8 @@
 #define NBD_PRINT_DEBUG         _IO(0xab, 6)
 #define NBD_SET_SIZE_BLOCKS     _IO(0xab, 7)
 #define NBD_DISCONNECT          _IO(0xab, 8)
+#define NBD_SET_TIMEOUT         _IO(0xab, 9)
+#define NBD_SET_FLAGS           _IO(0xab, 10)
 
 #define NBD_OPT_EXPORT_NAME     (1 << 0)
 
diff --git a/nbd.h b/nbd.h
index b9c3b39..61553f4 100644
--- a/nbd.h
+++ b/nbd.h
@@ -39,11 +39,20 @@ struct nbd_reply {
 
 #define NBD_FLAG_HAS_FLAGS      (1 << 0)        /* Flags are there */
 #define NBD_FLAG_READ_ONLY      (1 << 1)        /* Device is read-only */
+#define NBD_FLAG_SEND_FLUSH     (1 << 2)        /* Send FLUSH */
+#define NBD_FLAG_SEND_FUA       (1 << 3)        /* Send FUA (Force Unit Access) */
+#define NBD_FLAG_ROTATIONAL     (1 << 4)        /* Use elevator algorithm - rotational media */
+#define NBD_FLAG_SEND_TRIM      (1 << 5)        /* Send TRIM (discard) */
+
+#define NBD_CMD_MASK_COMMAND	0x0000ffff
+#define NBD_CMD_FLAG_FUA	(1 << 16)
 
 enum {
     NBD_CMD_READ = 0,
     NBD_CMD_WRITE = 1,
-    NBD_CMD_DISC = 2
+    NBD_CMD_DISC = 2,
+    NBD_CMD_FLUSH = 3,
+    NBD_CMD_TRIM = 4
 };
 
 #define NBD_DEFAULT_PORT	10809
commit b90fb4b8f5cd01dfcf0e3b45c93977a2e3bdcc71
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Thu Sep 8 17:24:54 2011 +0200

    nbd: support feature negotiation
    
    nbd supports writing flags in bytes 24...27 of the header,
    and uses that for the read-only flag.  Add support for it
    in qemu-nbd.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/nbd.c b/block/nbd.c
index 70edd81..76f04d8 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -48,6 +48,7 @@
 
 typedef struct BDRVNBDState {
     int sock;
+    uint32_t nbdflags;
     off_t size;
     size_t blocksize;
     char *export_name; /* An NBD server may export several devices */
@@ -111,7 +112,6 @@ static int nbd_establish_connection(BlockDriverState *bs)
     int ret;
     off_t size;
     size_t blocksize;
-    uint32_t nbdflags;
 
     if (s->host_spec[0] == '/') {
         sock = unix_socket_outgoing(s->host_spec);
@@ -126,7 +126,7 @@ static int nbd_establish_connection(BlockDriverState *bs)
     }
 
     /* NBD handshake */
-    ret = nbd_receive_negotiate(sock, s->export_name, &nbdflags, &size,
+    ret = nbd_receive_negotiate(sock, s->export_name, &s->nbdflags, &size,
                                 &blocksize);
     if (ret == -1) {
         logout("Failed to negotiate with the NBD server\n");
diff --git a/nbd.c b/nbd.c
index 6d81cfb..47ecb22 100644
--- a/nbd.c
+++ b/nbd.c
@@ -30,6 +30,10 @@
 #include <ctype.h>
 #include <inttypes.h>
 
+#ifdef __linux__
+#include <linux/fs.h>
+#endif
+
 #include "qemu_socket.h"
 
 //#define DEBUG_NBD
@@ -172,7 +176,7 @@ int unix_socket_outgoing(const char *path)
                   Request (type == 2)
 */
 
-int nbd_negotiate(int csock, off_t size)
+int nbd_negotiate(int csock, off_t size, uint32_t flags)
 {
     char buf[8 + 8 + 8 + 128];
 
@@ -180,14 +184,16 @@ int nbd_negotiate(int csock, off_t size)
         [ 0 ..   7]   passwd   ("NBDMAGIC")
         [ 8 ..  15]   magic    (0x00420281861253)
         [16 ..  23]   size
-        [24 .. 151]   reserved (0)
+        [24 ..  27]   flags
+        [28 .. 151]   reserved (0)
      */
 
     TRACE("Beginning negotiation.");
     memcpy(buf, "NBDMAGIC", 8);
     cpu_to_be64w((uint64_t*)(buf + 8), 0x00420281861253LL);
     cpu_to_be64w((uint64_t*)(buf + 16), size);
-    memset(buf + 24, 0, 128);
+    cpu_to_be32w((uint32_t*)(buf + 24), flags | NBD_FLAG_HAS_FLAGS);
+    memset(buf + 28, 0, 124);
 
     if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
         LOG("write failed");
@@ -337,8 +343,8 @@ int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
         return 0;
 }
 
-#ifndef _WIN32
-int nbd_init(int fd, int csock, off_t size, size_t blocksize)
+#ifdef __linux__
+int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
 {
     TRACE("Setting block size to %lu", (unsigned long)blocksize);
 
@@ -358,6 +364,18 @@ int nbd_init(int fd, int csock, off_t size, size_t blocksize)
         return -1;
     }
 
+    if (flags & NBD_FLAG_READ_ONLY) {
+        int read_only = 1;
+        TRACE("Setting readonly attribute");
+
+        if (ioctl(fd, BLKROSET, (unsigned long) &read_only) < 0) {
+            int serrno = errno;
+            LOG("Failed setting read-only attribute");
+            errno = serrno;
+            return -1;
+        }
+    }
+
     TRACE("Clearing NBD socket");
 
     if (ioctl(fd, NBD_CLEAR_SOCK) == -1) {
@@ -548,7 +566,7 @@ static int nbd_send_reply(int csock, struct nbd_reply *reply)
 }
 
 int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset,
-             off_t *offset, bool readonly, uint8_t *data, int data_size)
+             off_t *offset, uint32_t nbdflags, uint8_t *data, int data_size)
 {
     struct nbd_request request;
     struct nbd_reply reply;
@@ -632,7 +650,7 @@ int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset,
             return -1;
         }
 
-        if (readonly) {
+        if (nbdflags & NBD_FLAG_READ_ONLY) {
             TRACE("Server is read-only, return error");
             reply.error = 1;
         } else {
diff --git a/nbd.h b/nbd.h
index df7b7af..b9c3b39 100644
--- a/nbd.h
+++ b/nbd.h
@@ -37,6 +37,9 @@ struct nbd_reply {
     uint64_t handle;
 } QEMU_PACKED;
 
+#define NBD_FLAG_HAS_FLAGS      (1 << 0)        /* Flags are there */
+#define NBD_FLAG_READ_ONLY      (1 << 1)        /* Device is read-only */
+
 enum {
     NBD_CMD_READ = 0,
     NBD_CMD_WRITE = 1,
@@ -53,14 +56,14 @@ int tcp_socket_incoming_spec(const char *address_and_port);
 int unix_socket_outgoing(const char *path);
 int unix_socket_incoming(const char *path);
 
-int nbd_negotiate(int csock, off_t size);
+int nbd_negotiate(int csock, off_t size, uint32_t flags);
 int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
                           off_t *size, size_t *blocksize);
-int nbd_init(int fd, int csock, off_t size, size_t blocksize);
+int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize);
 int nbd_send_request(int csock, struct nbd_request *request);
 int nbd_receive_reply(int csock, struct nbd_reply *reply);
 int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset,
-             off_t *offset, bool readonly, uint8_t *data, int data_size);
+             off_t *offset, uint32_t nbdflags, uint8_t *data, int data_size);
 int nbd_client(int fd);
 int nbd_disconnect(int fd);
 
diff --git a/qemu-nbd.c b/qemu-nbd.c
index 3a39145..d8d3e15 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -185,7 +185,7 @@ int main(int argc, char **argv)
     BlockDriverState *bs;
     off_t dev_offset = 0;
     off_t offset = 0;
-    bool readonly = false;
+    uint32_t nbdflags = 0;
     bool disconnect = false;
     const char *bindto = "0.0.0.0";
     int port = NBD_DEFAULT_PORT;
@@ -230,7 +230,6 @@ int main(int argc, char **argv)
     int nb_fds = 0;
     int max_fd;
     int persistent = 0;
-    uint32_t nbdflags;
 
     while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
         switch (ch) {
@@ -263,7 +262,7 @@ int main(int argc, char **argv)
             }
             break;
         case 'r':
-            readonly = true;
+            nbdflags |= NBD_FLAG_READ_ONLY;
             flags &= ~BDRV_O_RDWR;
             break;
         case 'P':
@@ -398,13 +397,13 @@ int main(int argc, char **argv)
             }
 
             ret = nbd_receive_negotiate(sock, NULL, &nbdflags,
-					&size, &blocksize);
+                                        &size, &blocksize);
             if (ret == -1) {
                 ret = 1;
                 goto out;
             }
 
-            ret = nbd_init(fd, sock, size, blocksize);
+            ret = nbd_init(fd, sock, nbdflags, size, blocksize);
             if (ret == -1) {
                 ret = 1;
                 goto out;
@@ -463,7 +462,7 @@ int main(int argc, char **argv)
         for (i = 1; i < nb_fds && ret; i++) {
             if (FD_ISSET(sharing_fds[i], &fds)) {
                 if (nbd_trip(bs, sharing_fds[i], fd_size, dev_offset,
-                    &offset, readonly, data, NBD_BUFFER_SIZE) != 0) {
+                    &offset, nbdflags, data, NBD_BUFFER_SIZE) != 0) {
                     close(sharing_fds[i]);
                     nb_fds--;
                     sharing_fds[i] = sharing_fds[nb_fds];
@@ -479,7 +478,7 @@ int main(int argc, char **argv)
                                              (struct sockaddr *)&addr,
                                              &addr_len);
                 if (sharing_fds[nb_fds] != -1 &&
-                    nbd_negotiate(sharing_fds[nb_fds], fd_size) != -1) {
+                    nbd_negotiate(sharing_fds[nb_fds], fd_size, nbdflags) != -1) {
                         if (sharing_fds[nb_fds] > max_fd)
                             max_fd = sharing_fds[nb_fds];
                         nb_fds++;
commit 19b4a424d86f50131d68b9b2c28383bfc0566d31
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 22:50:06 2011 +0300

    musicpal: convert to memory API
    
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/musicpal.c b/hw/musicpal.c
index ade5a91..9b1f380 100644
--- a/hw/musicpal.c
+++ b/hw/musicpal.c
@@ -19,6 +19,7 @@
 #include "console.h"
 #include "i2c.h"
 #include "blockdev.h"
+#include "exec-memory.h"
 
 #define MP_MISC_BASE            0x80002000
 #define MP_MISC_SIZE            0x00001000
@@ -142,6 +143,7 @@ typedef struct mv88w8618_rx_desc {
 
 typedef struct mv88w8618_eth_state {
     SysBusDevice busdev;
+    MemoryRegion iomem;
     qemu_irq irq;
     uint32_t smir;
     uint32_t icr;
@@ -260,7 +262,8 @@ static void eth_send(mv88w8618_eth_state *s, int queue_index)
     } while (desc_addr != s->tx_queue[queue_index]);
 }
 
-static uint32_t mv88w8618_eth_read(void *opaque, target_phys_addr_t offset)
+static uint64_t mv88w8618_eth_read(void *opaque, target_phys_addr_t offset,
+                                   unsigned size)
 {
     mv88w8618_eth_state *s = opaque;
 
@@ -302,7 +305,7 @@ static uint32_t mv88w8618_eth_read(void *opaque, target_phys_addr_t offset)
 }
 
 static void mv88w8618_eth_write(void *opaque, target_phys_addr_t offset,
-                                uint32_t value)
+                                uint64_t value, unsigned size)
 {
     mv88w8618_eth_state *s = opaque;
 
@@ -353,16 +356,10 @@ static void mv88w8618_eth_write(void *opaque, target_phys_addr_t offset,
     }
 }
 
-static CPUReadMemoryFunc * const mv88w8618_eth_readfn[] = {
-    mv88w8618_eth_read,
-    mv88w8618_eth_read,
-    mv88w8618_eth_read
-};
-
-static CPUWriteMemoryFunc * const mv88w8618_eth_writefn[] = {
-    mv88w8618_eth_write,
-    mv88w8618_eth_write,
-    mv88w8618_eth_write
+static const MemoryRegionOps mv88w8618_eth_ops = {
+    .read = mv88w8618_eth_read,
+    .write = mv88w8618_eth_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void eth_cleanup(VLANClientState *nc)
@@ -387,10 +384,9 @@ static int mv88w8618_eth_init(SysBusDevice *dev)
     sysbus_init_irq(dev, &s->irq);
     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,
-                                           DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, MP_ETH_SIZE, s->mmio_index);
+    memory_region_init_io(&s->iomem, &mv88w8618_eth_ops, s, "mv88w8618-eth",
+                          MP_ETH_SIZE);
+    sysbus_init_mmio_region(dev, &s->iomem);
     return 0;
 }
 
@@ -444,6 +440,7 @@ static SysBusDeviceInfo mv88w8618_eth_info = {
 
 typedef struct musicpal_lcd_state {
     SysBusDevice busdev;
+    MemoryRegion iomem;
     uint32_t brightness;
     uint32_t mode;
     uint32_t irqctrl;
@@ -528,7 +525,8 @@ static void musicpal_lcd_gpio_brigthness_in(void *opaque, int irq, int level)
     s->brightness |= level << irq;
 }
 
-static uint32_t musicpal_lcd_read(void *opaque, target_phys_addr_t offset)
+static uint64_t musicpal_lcd_read(void *opaque, target_phys_addr_t offset,
+                                  unsigned size)
 {
     musicpal_lcd_state *s = opaque;
 
@@ -542,7 +540,7 @@ static uint32_t musicpal_lcd_read(void *opaque, target_phys_addr_t offset)
 }
 
 static void musicpal_lcd_write(void *opaque, target_phys_addr_t offset,
-                               uint32_t value)
+                               uint64_t value, unsigned size)
 {
     musicpal_lcd_state *s = opaque;
 
@@ -581,29 +579,21 @@ static void musicpal_lcd_write(void *opaque, target_phys_addr_t offset,
     }
 }
 
-static CPUReadMemoryFunc * const musicpal_lcd_readfn[] = {
-    musicpal_lcd_read,
-    musicpal_lcd_read,
-    musicpal_lcd_read
-};
-
-static CPUWriteMemoryFunc * const musicpal_lcd_writefn[] = {
-    musicpal_lcd_write,
-    musicpal_lcd_write,
-    musicpal_lcd_write
+static const MemoryRegionOps musicpal_lcd_ops = {
+    .read = musicpal_lcd_read,
+    .write = musicpal_lcd_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static int musicpal_lcd_init(SysBusDevice *dev)
 {
     musicpal_lcd_state *s = FROM_SYSBUS(musicpal_lcd_state, dev);
-    int iomemtype;
 
     s->brightness = 7;
 
-    iomemtype = cpu_register_io_memory(musicpal_lcd_readfn,
-                                       musicpal_lcd_writefn, s,
-                                       DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, MP_LCD_SIZE, iomemtype);
+    memory_region_init_io(&s->iomem, &musicpal_lcd_ops, s,
+                          "musicpal-lcd", MP_LCD_SIZE);
+    sysbus_init_mmio_region(dev, &s->iomem);
 
     s->ds = graphic_console_init(lcd_refresh, lcd_invalidate,
                                  NULL, NULL, s);
@@ -645,6 +635,7 @@ static SysBusDeviceInfo musicpal_lcd_info = {
 typedef struct mv88w8618_pic_state
 {
     SysBusDevice busdev;
+    MemoryRegion iomem;
     uint32_t level;
     uint32_t enabled;
     qemu_irq parent_irq;
@@ -667,7 +658,8 @@ static void mv88w8618_pic_set_irq(void *opaque, int irq, int level)
     mv88w8618_pic_update(s);
 }
 
-static uint32_t mv88w8618_pic_read(void *opaque, target_phys_addr_t offset)
+static uint64_t mv88w8618_pic_read(void *opaque, target_phys_addr_t offset,
+                                   unsigned size)
 {
     mv88w8618_pic_state *s = opaque;
 
@@ -681,7 +673,7 @@ static uint32_t mv88w8618_pic_read(void *opaque, target_phys_addr_t offset)
 }
 
 static void mv88w8618_pic_write(void *opaque, target_phys_addr_t offset,
-                                uint32_t value)
+                                uint64_t value, unsigned size)
 {
     mv88w8618_pic_state *s = opaque;
 
@@ -707,29 +699,21 @@ static void mv88w8618_pic_reset(DeviceState *d)
     s->enabled = 0;
 }
 
-static CPUReadMemoryFunc * const mv88w8618_pic_readfn[] = {
-    mv88w8618_pic_read,
-    mv88w8618_pic_read,
-    mv88w8618_pic_read
-};
-
-static CPUWriteMemoryFunc * const mv88w8618_pic_writefn[] = {
-    mv88w8618_pic_write,
-    mv88w8618_pic_write,
-    mv88w8618_pic_write
+static const MemoryRegionOps mv88w8618_pic_ops = {
+    .read = mv88w8618_pic_read,
+    .write = mv88w8618_pic_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static int mv88w8618_pic_init(SysBusDevice *dev)
 {
     mv88w8618_pic_state *s = FROM_SYSBUS(mv88w8618_pic_state, dev);
-    int iomemtype;
 
     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,
-                                       DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, MP_PIC_SIZE, iomemtype);
+    memory_region_init_io(&s->iomem, &mv88w8618_pic_ops, s,
+                          "musicpal-pic", MP_PIC_SIZE);
+    sysbus_init_mmio_region(dev, &s->iomem);
     return 0;
 }
 
@@ -775,6 +759,7 @@ typedef struct mv88w8618_timer_state {
 
 typedef struct mv88w8618_pit_state {
     SysBusDevice busdev;
+    MemoryRegion iomem;
     mv88w8618_timer_state timer[4];
 } mv88w8618_pit_state;
 
@@ -797,7 +782,8 @@ static void mv88w8618_timer_init(SysBusDevice *dev, mv88w8618_timer_state *s,
     s->ptimer = ptimer_init(bh);
 }
 
-static uint32_t mv88w8618_pit_read(void *opaque, target_phys_addr_t offset)
+static uint64_t mv88w8618_pit_read(void *opaque, target_phys_addr_t offset,
+                                   unsigned size)
 {
     mv88w8618_pit_state *s = opaque;
     mv88w8618_timer_state *t;
@@ -813,7 +799,7 @@ static uint32_t mv88w8618_pit_read(void *opaque, target_phys_addr_t offset)
 }
 
 static void mv88w8618_pit_write(void *opaque, target_phys_addr_t offset,
-                                uint32_t value)
+                                uint64_t value, unsigned size)
 {
     mv88w8618_pit_state *s = opaque;
     mv88w8618_timer_state *t;
@@ -864,21 +850,14 @@ static void mv88w8618_pit_reset(DeviceState *d)
     }
 }
 
-static CPUReadMemoryFunc * const mv88w8618_pit_readfn[] = {
-    mv88w8618_pit_read,
-    mv88w8618_pit_read,
-    mv88w8618_pit_read
-};
-
-static CPUWriteMemoryFunc * const mv88w8618_pit_writefn[] = {
-    mv88w8618_pit_write,
-    mv88w8618_pit_write,
-    mv88w8618_pit_write
+static const MemoryRegionOps mv88w8618_pit_ops = {
+    .read = mv88w8618_pit_read,
+    .write = mv88w8618_pit_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static int mv88w8618_pit_init(SysBusDevice *dev)
 {
-    int iomemtype;
     mv88w8618_pit_state *s = FROM_SYSBUS(mv88w8618_pit_state, dev);
     int i;
 
@@ -888,10 +867,9 @@ static int mv88w8618_pit_init(SysBusDevice *dev)
         mv88w8618_timer_init(dev, &s->timer[i], 1000000);
     }
 
-    iomemtype = cpu_register_io_memory(mv88w8618_pit_readfn,
-                                       mv88w8618_pit_writefn, s,
-                                       DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, MP_PIT_SIZE, iomemtype);
+    memory_region_init_io(&s->iomem, &mv88w8618_pit_ops, s,
+                          "musicpal-pit", MP_PIT_SIZE);
+    sysbus_init_mmio_region(dev, &s->iomem);
     return 0;
 }
 
@@ -932,11 +910,13 @@ static SysBusDeviceInfo mv88w8618_pit_info = {
 
 typedef struct mv88w8618_flashcfg_state {
     SysBusDevice busdev;
+    MemoryRegion iomem;
     uint32_t cfgr0;
 } mv88w8618_flashcfg_state;
 
-static uint32_t mv88w8618_flashcfg_read(void *opaque,
-                                        target_phys_addr_t offset)
+static uint64_t mv88w8618_flashcfg_read(void *opaque,
+                                        target_phys_addr_t offset,
+                                        unsigned size)
 {
     mv88w8618_flashcfg_state *s = opaque;
 
@@ -950,7 +930,7 @@ static uint32_t mv88w8618_flashcfg_read(void *opaque,
 }
 
 static void mv88w8618_flashcfg_write(void *opaque, target_phys_addr_t offset,
-                                     uint32_t value)
+                                     uint64_t value, unsigned size)
 {
     mv88w8618_flashcfg_state *s = opaque;
 
@@ -961,28 +941,20 @@ static void mv88w8618_flashcfg_write(void *opaque, target_phys_addr_t offset,
     }
 }
 
-static CPUReadMemoryFunc * const mv88w8618_flashcfg_readfn[] = {
-    mv88w8618_flashcfg_read,
-    mv88w8618_flashcfg_read,
-    mv88w8618_flashcfg_read
-};
-
-static CPUWriteMemoryFunc * const mv88w8618_flashcfg_writefn[] = {
-    mv88w8618_flashcfg_write,
-    mv88w8618_flashcfg_write,
-    mv88w8618_flashcfg_write
+static const MemoryRegionOps mv88w8618_flashcfg_ops = {
+    .read = mv88w8618_flashcfg_read,
+    .write = mv88w8618_flashcfg_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static int mv88w8618_flashcfg_init(SysBusDevice *dev)
 {
-    int iomemtype;
     mv88w8618_flashcfg_state *s = FROM_SYSBUS(mv88w8618_flashcfg_state, 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,
-                                       DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, MP_FLASHCFG_SIZE, iomemtype);
+    memory_region_init_io(&s->iomem, &mv88w8618_flashcfg_ops, s,
+                          "musicpal-flashcfg", MP_FLASHCFG_SIZE);
+    sysbus_init_mmio_region(dev, &s->iomem);
     return 0;
 }
 
@@ -1009,7 +981,8 @@ static SysBusDeviceInfo mv88w8618_flashcfg_info = {
 
 #define MP_BOARD_REVISION       0x31
 
-static uint32_t musicpal_misc_read(void *opaque, target_phys_addr_t offset)
+static uint64_t musicpal_misc_read(void *opaque, target_phys_addr_t offset,
+                                   unsigned size)
 {
     switch (offset) {
     case MP_MISC_BOARD_REVISION:
@@ -1021,37 +994,31 @@ static uint32_t musicpal_misc_read(void *opaque, target_phys_addr_t offset)
 }
 
 static void musicpal_misc_write(void *opaque, target_phys_addr_t offset,
-                                uint32_t value)
+                                uint64_t value, unsigned size)
 {
 }
 
-static CPUReadMemoryFunc * const musicpal_misc_readfn[] = {
-    musicpal_misc_read,
-    musicpal_misc_read,
-    musicpal_misc_read,
-};
-
-static CPUWriteMemoryFunc * const musicpal_misc_writefn[] = {
-    musicpal_misc_write,
-    musicpal_misc_write,
-    musicpal_misc_write,
+static const MemoryRegionOps musicpal_misc_ops = {
+    .read = musicpal_misc_read,
+    .write = musicpal_misc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static void musicpal_misc_init(void)
+static void musicpal_misc_init(SysBusDevice *dev)
 {
-    int iomemtype;
+    MemoryRegion *iomem = g_new(MemoryRegion, 1);
 
-    iomemtype = cpu_register_io_memory(musicpal_misc_readfn,
-                                       musicpal_misc_writefn, NULL,
-                                       DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(MP_MISC_BASE, MP_MISC_SIZE, iomemtype);
+    memory_region_init_io(iomem, &musicpal_misc_ops, NULL,
+                          "musicpal-misc", MP_MISC_SIZE);
+    sysbus_add_memory(dev, MP_MISC_BASE, iomem);
 }
 
 /* WLAN register offsets */
 #define MP_WLAN_MAGIC1          0x11c
 #define MP_WLAN_MAGIC2          0x124
 
-static uint32_t mv88w8618_wlan_read(void *opaque, target_phys_addr_t offset)
+static uint64_t mv88w8618_wlan_read(void *opaque, target_phys_addr_t offset,
+                                    unsigned size)
 {
     switch (offset) {
     /* Workaround to allow loading the binary-only wlandrv.ko crap
@@ -1067,30 +1034,23 @@ static uint32_t mv88w8618_wlan_read(void *opaque, target_phys_addr_t offset)
 }
 
 static void mv88w8618_wlan_write(void *opaque, target_phys_addr_t offset,
-                                 uint32_t value)
+                                 uint64_t value, unsigned size)
 {
 }
 
-static CPUReadMemoryFunc * const mv88w8618_wlan_readfn[] = {
-    mv88w8618_wlan_read,
-    mv88w8618_wlan_read,
-    mv88w8618_wlan_read,
-};
-
-static CPUWriteMemoryFunc * const mv88w8618_wlan_writefn[] = {
-    mv88w8618_wlan_write,
-    mv88w8618_wlan_write,
-    mv88w8618_wlan_write,
+static const MemoryRegionOps mv88w8618_wlan_ops = {
+    .read = mv88w8618_wlan_read,
+    .write =mv88w8618_wlan_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static int mv88w8618_wlan_init(SysBusDevice *dev)
 {
-    int iomemtype;
+    MemoryRegion *iomem = g_new(MemoryRegion, 1);
 
-    iomemtype = cpu_register_io_memory(mv88w8618_wlan_readfn,
-                                       mv88w8618_wlan_writefn, NULL,
-                                       DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, MP_WLAN_SIZE, iomemtype);
+    memory_region_init_io(iomem, &mv88w8618_wlan_ops, NULL,
+                          "musicpal-wlan", MP_WLAN_SIZE);
+    sysbus_init_mmio_region(dev, iomem);
     return 0;
 }
 
@@ -1118,6 +1078,7 @@ static int mv88w8618_wlan_init(SysBusDevice *dev)
 
 typedef struct musicpal_gpio_state {
     SysBusDevice busdev;
+    MemoryRegion iomem;
     uint32_t lcd_brightness;
     uint32_t out_state;
     uint32_t in_state;
@@ -1190,7 +1151,8 @@ static void musicpal_gpio_pin_event(void *opaque, int pin, int level)
     }
 }
 
-static uint32_t musicpal_gpio_read(void *opaque, target_phys_addr_t offset)
+static uint64_t musicpal_gpio_read(void *opaque, target_phys_addr_t offset,
+                                   unsigned size)
 {
     musicpal_gpio_state *s = opaque;
 
@@ -1229,7 +1191,7 @@ static uint32_t musicpal_gpio_read(void *opaque, target_phys_addr_t offset)
 }
 
 static void musicpal_gpio_write(void *opaque, target_phys_addr_t offset,
-                                uint32_t value)
+                                uint64_t value, unsigned size)
 {
     musicpal_gpio_state *s = opaque;
     switch (offset) {
@@ -1267,16 +1229,10 @@ static void musicpal_gpio_write(void *opaque, target_phys_addr_t offset,
     }
 }
 
-static CPUReadMemoryFunc * const musicpal_gpio_readfn[] = {
-    musicpal_gpio_read,
-    musicpal_gpio_read,
-    musicpal_gpio_read,
-};
-
-static CPUWriteMemoryFunc * const musicpal_gpio_writefn[] = {
-    musicpal_gpio_write,
-    musicpal_gpio_write,
-    musicpal_gpio_write,
+static const MemoryRegionOps musicpal_gpio_ops = {
+    .read = musicpal_gpio_read,
+    .write = musicpal_gpio_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void musicpal_gpio_reset(DeviceState *d)
@@ -1295,14 +1251,12 @@ static void musicpal_gpio_reset(DeviceState *d)
 static int musicpal_gpio_init(SysBusDevice *dev)
 {
     musicpal_gpio_state *s = FROM_SYSBUS(musicpal_gpio_state, dev);
-    int iomemtype;
 
     sysbus_init_irq(dev, &s->irq);
 
-    iomemtype = cpu_register_io_memory(musicpal_gpio_readfn,
-                                       musicpal_gpio_writefn, s,
-                                       DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, MP_GPIO_SIZE, iomemtype);
+    memory_region_init_io(&s->iomem, &musicpal_gpio_ops, s,
+                          "musicpal-gpio", MP_GPIO_SIZE);
+    sysbus_init_mmio_region(dev, &s->iomem);
 
     qdev_init_gpio_out(&dev->qdev, s->out, ARRAY_SIZE(s->out));
 
@@ -1501,7 +1455,9 @@ static void musicpal_init(ram_addr_t ram_size,
     int i;
     unsigned long flash_size;
     DriveInfo *dinfo;
-    ram_addr_t sram_off;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *sram = g_new(MemoryRegion, 1);
 
     if (!cpu_model) {
         cpu_model = "arm926";
@@ -1514,12 +1470,11 @@ static void musicpal_init(ram_addr_t ram_size,
     cpu_pic = arm_pic_init_cpu(env);
 
     /* For now we use a fixed - the original - RAM size */
-    cpu_register_physical_memory(0, MP_RAM_DEFAULT_SIZE,
-                                 qemu_ram_alloc(NULL, "musicpal.ram",
-                                                MP_RAM_DEFAULT_SIZE));
+    memory_region_init_ram(ram, NULL, "musicpal.ram", MP_RAM_DEFAULT_SIZE);
+    memory_region_add_subregion(address_space_mem, 0, ram);
 
-    sram_off = qemu_ram_alloc(NULL, "musicpal.sram", MP_SRAM_SIZE);
-    cpu_register_physical_memory(MP_SRAM_BASE, MP_SRAM_SIZE, sram_off);
+    memory_region_init_ram(sram, NULL, "musicpal.sram", MP_SRAM_SIZE);
+    memory_region_add_subregion(address_space_mem, MP_SRAM_BASE, sram);
 
     dev = sysbus_create_simple("mv88w8618_pic", MP_PIC_BASE,
                                cpu_pic[ARM_PIC_CPU_IRQ]);
@@ -1594,7 +1549,7 @@ static void musicpal_init(ram_addr_t ram_size,
 
     sysbus_create_simple("mv88w8618_wlan", MP_WLAN_BASE, NULL);
 
-    musicpal_misc_init();
+    musicpal_misc_init(sysbus_from_qdev(dev));
 
     dev = sysbus_create_simple("musicpal_gpio", MP_GPIO_BASE, pic[MP_GPIO_IRQ]);
     i2c_dev = sysbus_create_simple("gpio_i2c", -1, NULL);
commit 0ae164504e0dcea14a756669917027e897a376fa
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 22:22:38 2011 +0300

    mips_r4k: convert to memory API
    
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c
index 5d002c5..805d02a 100644
--- a/hw/mips_r4k.c
+++ b/hw/mips_r4k.c
@@ -42,8 +42,8 @@ static struct _loaderparams {
     const char *initrd_filename;
 } loaderparams;
 
-static void mips_qemu_writel (void *opaque, target_phys_addr_t addr,
-			      uint32_t val)
+static void mips_qemu_write (void *opaque, target_phys_addr_t addr,
+                             uint64_t val, unsigned size)
 {
     if ((addr & 0xffff) == 0 && val == 42)
         qemu_system_reset_request ();
@@ -51,25 +51,18 @@ static void mips_qemu_writel (void *opaque, target_phys_addr_t addr,
         qemu_system_shutdown_request ();
 }
 
-static uint32_t mips_qemu_readl (void *opaque, target_phys_addr_t addr)
+static uint64_t mips_qemu_read (void *opaque, target_phys_addr_t addr,
+                                unsigned size)
 {
     return 0;
 }
 
-static CPUWriteMemoryFunc * const mips_qemu_write[] = {
-    &mips_qemu_writel,
-    &mips_qemu_writel,
-    &mips_qemu_writel,
+static const MemoryRegionOps mips_qemu_ops = {
+    .read = mips_qemu_read,
+    .write = mips_qemu_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUReadMemoryFunc * const mips_qemu_read[] = {
-    &mips_qemu_readl,
-    &mips_qemu_readl,
-    &mips_qemu_readl,
-};
-
-static int mips_qemu_iomemtype = 0;
-
 typedef struct ResetData {
     CPUState *env;
     uint64_t vector;
@@ -163,8 +156,10 @@ void mips_r4k_init (ram_addr_t ram_size,
                     const char *initrd_filename, const char *cpu_model)
 {
     char *filename;
-    ram_addr_t ram_offset;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
     MemoryRegion *bios;
+    MemoryRegion *iomem = g_new(MemoryRegion, 1);
     int bios_size;
     CPUState *env;
     ResetData *reset_info;
@@ -199,16 +194,12 @@ void mips_r4k_init (ram_addr_t ram_size,
                 ((unsigned int)ram_size / (1 << 20)));
         exit(1);
     }
-    ram_offset = qemu_ram_alloc(NULL, "mips_r4k.ram", ram_size);
+    memory_region_init_ram(ram, NULL, "mips_r4k.ram", ram_size);
 
-    cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
+    memory_region_add_subregion(address_space_mem, 0, ram);
 
-    if (!mips_qemu_iomemtype) {
-        mips_qemu_iomemtype = cpu_register_io_memory(mips_qemu_read,
-                                                     mips_qemu_write, NULL,
-                                                     DEVICE_NATIVE_ENDIAN);
-    }
-    cpu_register_physical_memory(0x1fbf0000, 0x10000, mips_qemu_iomemtype);
+    memory_region_init_io(iomem, &mips_qemu_ops, NULL, "mips-qemu", 0x10000);
+    memory_region_add_subregion(address_space_mem, 0x1fbf0000, iomem);
 
     /* Try to load a BIOS image. If this fails, we continue regardless,
        but initialize the hardware ourselves. When a kernel gets
commit 23ebf23dd1f8a558caf472b5a73dd599d48b29fe
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 22:17:28 2011 +0300

    mips_mipssim: convert to memory API
    
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c
index ac65555..7407158 100644
--- a/hw/mips_mipssim.c
+++ b/hw/mips_mipssim.c
@@ -137,8 +137,9 @@ mips_mipssim_init (ram_addr_t ram_size,
                    const char *initrd_filename, const char *cpu_model)
 {
     char *filename;
-    ram_addr_t ram_offset;
-    ram_addr_t bios_offset;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *bios = g_new(MemoryRegion, 1);
     CPUState *env;
     ResetData *reset_info;
     int bios_size;
@@ -162,14 +163,14 @@ mips_mipssim_init (ram_addr_t ram_size,
     qemu_register_reset(main_cpu_reset, reset_info);
 
     /* Allocate RAM. */
-    ram_offset = qemu_ram_alloc(NULL, "mips_mipssim.ram", ram_size);
-    bios_offset = qemu_ram_alloc(NULL, "mips_mipssim.bios", BIOS_SIZE);
+    memory_region_init_ram(ram, NULL, "mips_mipssim.ram", ram_size);
+    memory_region_init_ram(bios, NULL, "mips_mipssim.bios", BIOS_SIZE);
+    memory_region_set_readonly(bios, true);
 
-    cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
+    memory_region_add_subregion(address_space_mem, 0, ram);
 
     /* Map the BIOS / boot exception handler. */
-    cpu_register_physical_memory(0x1fc00000LL,
-                                 BIOS_SIZE, bios_offset | IO_MEM_ROM);
+    memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
     /* Load a BIOS / boot exception handler image. */
     if (bios_name == NULL)
         bios_name = BIOS_FILENAME;
commit ea85df72b600f0b7c93b4138209ccee4b354ee91
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 22:14:25 2011 +0300

    mips_malta: convert to memory API
    
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index e7cdf20..0110daa 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -57,6 +57,9 @@
 #define MAX_IDE_BUS 2
 
 typedef struct {
+    MemoryRegion iomem;
+    MemoryRegion iomem_lo; /* 0 - 0x900 */
+    MemoryRegion iomem_hi; /* 0xa00 - 0x100000 */
     uint32_t leds;
     uint32_t brk;
     uint32_t gpout;
@@ -215,7 +218,8 @@ static void eeprom24c0x_write(int scl, int sda)
     eeprom.sda = sda;
 }
 
-static uint32_t malta_fpga_readl(void *opaque, target_phys_addr_t addr)
+static uint64_t malta_fpga_read(void *opaque, target_phys_addr_t addr,
+                                unsigned size)
 {
     MaltaFPGAState *s = opaque;
     uint32_t val = 0;
@@ -302,8 +306,8 @@ static uint32_t malta_fpga_readl(void *opaque, target_phys_addr_t addr)
     return val;
 }
 
-static void malta_fpga_writel(void *opaque, target_phys_addr_t addr,
-                              uint32_t val)
+static void malta_fpga_write(void *opaque, target_phys_addr_t addr,
+                             uint64_t val, unsigned size)
 {
     MaltaFPGAState *s = opaque;
     uint32_t saddr;
@@ -328,7 +332,7 @@ static void malta_fpga_writel(void *opaque, target_phys_addr_t addr,
 
     /* ASCIIWORD Register */
     case 0x00410:
-        snprintf(s->display_text, 9, "%08X", val);
+        snprintf(s->display_text, 9, "%08X", (uint32_t)val);
         malta_fpga_update_display(s);
         break;
 
@@ -388,16 +392,10 @@ static void malta_fpga_writel(void *opaque, target_phys_addr_t addr,
     }
 }
 
-static CPUReadMemoryFunc * const malta_fpga_read[] = {
-   malta_fpga_readl,
-   malta_fpga_readl,
-   malta_fpga_readl
-};
-
-static CPUWriteMemoryFunc * const malta_fpga_write[] = {
-   malta_fpga_writel,
-   malta_fpga_writel,
-   malta_fpga_writel
+static const MemoryRegionOps malta_fpga_ops = {
+    .read = malta_fpga_read,
+    .write = malta_fpga_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static void malta_fpga_reset(void *opaque)
@@ -429,20 +427,22 @@ static void malta_fpga_led_init(CharDriverState *chr)
     qemu_chr_fe_printf(chr, "+--------+\r\n");
 }
 
-static MaltaFPGAState *malta_fpga_init(target_phys_addr_t base, qemu_irq uart_irq, CharDriverState *uart_chr)
+static MaltaFPGAState *malta_fpga_init(MemoryRegion *address_space,
+         target_phys_addr_t base, qemu_irq uart_irq, CharDriverState *uart_chr)
 {
     MaltaFPGAState *s;
-    int malta;
 
     s = (MaltaFPGAState *)g_malloc0(sizeof(MaltaFPGAState));
 
-    malta = cpu_register_io_memory(malta_fpga_read,
-                                   malta_fpga_write, s,
-                                   DEVICE_NATIVE_ENDIAN);
+    memory_region_init_io(&s->iomem, &malta_fpga_ops, s,
+                          "malta-fpga", 0x100000);
+    memory_region_init_alias(&s->iomem_lo, "malta-fpga",
+                             &s->iomem, 0, 0x900);
+    memory_region_init_alias(&s->iomem_hi, "malta-fpga",
+                             &s->iomem, 0xa00, 0x10000-0xa00);
 
-    cpu_register_physical_memory(base, 0x900, malta);
-    /* 0xa00 is less than a page, so will still get the right offsets.  */
-    cpu_register_physical_memory(base + 0xa00, 0x100000 - 0xa00, malta);
+    memory_region_add_subregion(address_space, base, &s->iomem_lo);
+    memory_region_add_subregion(address_space, base + 0xa00, &s->iomem_hi);
 
     s->display = qemu_chr_new("fpga", "vc:320x200", malta_fpga_led_init);
 
@@ -771,8 +771,8 @@ void mips_malta_init (ram_addr_t ram_size,
 {
     char *filename;
     pflash_t *fl;
-    ram_addr_t ram_offset;
     MemoryRegion *system_memory = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
     MemoryRegion *bios, *bios_alias = g_new(MemoryRegion, 1);
     target_long bios_size;
     int64_t kernel_entry;
@@ -828,9 +828,8 @@ void mips_malta_init (ram_addr_t ram_size,
                 ((unsigned int)ram_size / (1 << 20)));
         exit(1);
     }
-    ram_offset = qemu_ram_alloc(NULL, "mips_malta.ram", ram_size);
-
-    cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
+    memory_region_init_ram(ram, NULL, "mips_malta.ram", ram_size);
+    memory_region_add_subregion(system_memory, 0, ram);
 
 #ifdef TARGET_WORDS_BIGENDIAN
     be = 1;
@@ -838,7 +837,7 @@ void mips_malta_init (ram_addr_t ram_size,
     be = 0;
 #endif
     /* FPGA */
-    malta_fpga_init(0x1f000000LL, env->irq[2], serial_hds[2]);
+    malta_fpga_init(system_memory, 0x1f000000LL, env->irq[2], serial_hds[2]);
 
     /* Load firmware in flash / BIOS unless we boot directly into a kernel. */
     if (kernel_filename) {
commit 60581b3777ee23d0b2b7fe127ed57dfb885e285e
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 21:59:19 2011 +0300

    mips_jazz: convert to memory API
    
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c
index f3c9f93..7cac5da 100644
--- a/hw/mips_jazz.c
+++ b/hw/mips_jazz.c
@@ -52,44 +52,42 @@ static void main_cpu_reset(void *opaque)
     cpu_reset(env);
 }
 
-static uint32_t rtc_readb(void *opaque, target_phys_addr_t addr)
+static uint64_t rtc_read(void *opaque, target_phys_addr_t addr, unsigned size)
 {
     return cpu_inw(0x71);
 }
 
-static void rtc_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+static void rtc_write(void *opaque, target_phys_addr_t addr,
+                      uint64_t val, unsigned size)
 {
     cpu_outw(0x71, val & 0xff);
 }
 
-static CPUReadMemoryFunc * const rtc_read[3] = {
-    rtc_readb,
-    rtc_readb,
-    rtc_readb,
+static const MemoryRegionOps rtc_ops = {
+    .read = rtc_read,
+    .write = rtc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const rtc_write[3] = {
-    rtc_writeb,
-    rtc_writeb,
-    rtc_writeb,
-};
-
-static void dma_dummy_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+static uint64_t dma_dummy_read(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
 {
     /* Nothing to do. That is only to ensure that
      * the current DMA acknowledge cycle is completed. */
+    return 0xff;
 }
 
-static CPUReadMemoryFunc * const dma_dummy_read[3] = {
-    NULL,
-    NULL,
-    NULL,
-};
+static void dma_dummy_write(void *opaque, target_phys_addr_t addr,
+                            uint64_t val, unsigned size)
+{
+    /* Nothing to do. That is only to ensure that
+     * the current DMA acknowledge cycle is completed. */
+}
 
-static CPUWriteMemoryFunc * const dma_dummy_write[3] = {
-    dma_dummy_writeb,
-    dma_dummy_writeb,
-    dma_dummy_writeb,
+static const MemoryRegionOps dma_dummy_ops = {
+    .read = dma_dummy_read,
+    .write = dma_dummy_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 #define MAGNUM_BIOS_SIZE_MAX 0x7e000
@@ -105,7 +103,7 @@ static void cpu_request_exit(void *opaque, int irq, int level)
 }
 
 static
-void mips_jazz_init (ram_addr_t ram_size,
+void mips_jazz_init (MemoryRegion *address_space, ram_addr_t ram_size,
                      const char *cpu_model,
                      enum jazz_model_e jazz_model)
 {
@@ -115,7 +113,8 @@ void mips_jazz_init (ram_addr_t ram_size,
     qemu_irq *rc4030, *i8259;
     rc4030_dma *dmas;
     void* rc4030_opaque;
-    int s_rtc, s_dma_dummy;
+    MemoryRegion *rtc = g_new(MemoryRegion, 1);
+    MemoryRegion *dma_dummy = g_new(MemoryRegion, 1);
     NICInfo *nd;
     DeviceState *dev;
     SysBusDevice *sysbus;
@@ -123,8 +122,9 @@ void mips_jazz_init (ram_addr_t ram_size,
     DriveInfo *fds[MAX_FD];
     qemu_irq esp_reset, dma_enable;
     qemu_irq *cpu_exit_irq;
-    ram_addr_t ram_offset;
-    ram_addr_t bios_offset;
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *bios = g_new(MemoryRegion, 1);
+    MemoryRegion *bios2 = g_new(MemoryRegion, 1);
 
     /* init CPUs */
     if (cpu_model == NULL) {
@@ -143,14 +143,15 @@ void mips_jazz_init (ram_addr_t ram_size,
     qemu_register_reset(main_cpu_reset, env);
 
     /* allocate RAM */
-    ram_offset = qemu_ram_alloc(NULL, "mips_jazz.ram", ram_size);
-    cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
+    memory_region_init_ram(ram, NULL, "mips_jazz.ram", ram_size);
+    memory_region_add_subregion(address_space, 0, ram);
 
-    bios_offset = qemu_ram_alloc(NULL, "mips_jazz.bios", MAGNUM_BIOS_SIZE);
-    cpu_register_physical_memory(0x1fc00000LL,
-                                 MAGNUM_BIOS_SIZE, bios_offset | IO_MEM_ROM);
-    cpu_register_physical_memory(0xfff00000LL,
-                                 MAGNUM_BIOS_SIZE, bios_offset | IO_MEM_ROM);
+    memory_region_init_ram(bios, NULL, "mips_jazz.bios", MAGNUM_BIOS_SIZE);
+    memory_region_set_readonly(bios, true);
+    memory_region_init_alias(bios2, "mips_jazz.bios", bios,
+                             0, MAGNUM_BIOS_SIZE);
+    memory_region_add_subregion(address_space, 0x1fc00000LL, bios);
+    memory_region_add_subregion(address_space, 0xfff00000LL, bios2);
 
     /* load the BIOS image. */
     if (bios_name == NULL)
@@ -175,9 +176,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,
-                                         DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(0x8000d000, 0x00001000, s_dma_dummy);
+    memory_region_init_io(dma_dummy, &dma_dummy_ops, NULL, "dummy_dma", 0x1000);
+    memory_region_add_subregion(address_space, 0x8000d000, dma_dummy);
 
     /* ISA devices */
     i8259 = i8259_init(env->irq[4]);
@@ -203,10 +203,11 @@ void mips_jazz_init (ram_addr_t ram_size,
         sysbus_connect_irq(sysbus, 0, rc4030[3]);
         {
             /* Simple ROM, so user doesn't have to provide one */
-            ram_addr_t rom_offset = qemu_ram_alloc(NULL, "g364fb.rom", 0x80000);
-            uint8_t *rom = qemu_get_ram_ptr(rom_offset);
-            cpu_register_physical_memory(0x60000000, 0x80000,
-                                         rom_offset | IO_MEM_ROM);
+            MemoryRegion *rom_mr = g_new(MemoryRegion, 1);
+            memory_region_init_ram(rom_mr, NULL, "g364fb.rom", 0x80000);
+            memory_region_set_readonly(rom_mr, true);
+            uint8_t *rom = memory_region_get_ram_ptr(rom_mr);
+            memory_region_add_subregion(address_space, 0x60000000, rom_mr);
             rom[0] = 0x10; /* Mips G364 */
         }
         break;
@@ -252,9 +253,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,
-                                   DEVICE_NATIVE_ENDIAN);
-    cpu_register_physical_memory(0x80004000, 0x00001000, s_rtc);
+    memory_region_init_io(rtc, &rtc_ops, NULL, "rtc", 0x1000);
+    memory_region_add_subregion(address_space, 0x80004000, rtc);
 
     /* Keyboard (i8042) */
     i8042_mm_init(rc4030[6], rc4030[7], 0x80005000, 0x1000, 0x1);
@@ -299,7 +299,7 @@ void mips_magnum_init (ram_addr_t ram_size,
                        const char *kernel_filename, const char *kernel_cmdline,
                        const char *initrd_filename, const char *cpu_model)
 {
-    mips_jazz_init(ram_size, cpu_model, JAZZ_MAGNUM);
+    mips_jazz_init(get_system_memory(), ram_size, cpu_model, JAZZ_MAGNUM);
 }
 
 static
@@ -308,7 +308,7 @@ void mips_pica61_init (ram_addr_t ram_size,
                        const char *kernel_filename, const char *kernel_cmdline,
                        const char *initrd_filename, const char *cpu_model)
 {
-    mips_jazz_init(ram_size, cpu_model, JAZZ_PICA61);
+    mips_jazz_init(get_system_memory(), ram_size, cpu_model, JAZZ_PICA61);
 }
 
 static QEMUMachine mips_magnum_machine = {
commit 530889ff95659d8fea81eb556e5706387fdddfa7
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sat Sep 17 19:16:57 2011 +0000

    sun4u: don't set up isa_mem_base
    
    Since we use memory API in sun4u.c, after
    71579cae30b53c910cd6c47ab4e683f647d36519, setting up isa_mem_base
    puts vga.chain4 outside of the physical address space.
    
    Fix by removing obsolete isa_mem_base set up.
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/sun4u.c b/hw/sun4u.c
index 32e6ab9..6afb0e7 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -763,7 +763,6 @@ static void sun4uv_init(ram_addr_t RAM_size,
     irq = qemu_allocate_irqs(cpu_set_irq, env, MAX_PILS);
     pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, irq, &pci_bus2,
                            &pci_bus3);
-    isa_mem_base = APB_PCI_IO_BASE;
     pci_vga_init(pci_bus);
 
     // XXX Should be pci_bus3
commit 860329b2513cf754c5f7d5400f7bcf5dd1a44489
Author: Michael Walle <michael at walle.cc>
Date:   Thu Sep 15 23:16:49 2011 +0200

    memory: fix subregion collision warning
    
    Instead of the offset property use the proper addr property to calculate
    the offsets.
    
    Additionally, be a little more verbose on the warning and print the
    subregion name.
    
    Signed-off-by: Michael Walle <michael at walle.cc>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/memory.c b/memory.c
index 101b67c..ba74435 100644
--- a/memory.c
+++ b/memory.c
@@ -1190,16 +1190,19 @@ static void memory_region_add_subregion_common(MemoryRegion *mr,
         if (subregion->may_overlap || other->may_overlap) {
             continue;
         }
-        if (offset >= other->offset + other->size
-            || offset + subregion->size <= other->offset) {
+        if (offset >= other->addr + other->size
+            || offset + subregion->size <= other->addr) {
             continue;
         }
 #if 0
-        printf("warning: subregion collision %llx/%llx vs %llx/%llx\n",
+        printf("warning: subregion collision %llx/%llx (%s) "
+               "vs %llx/%llx (%s)\n",
                (unsigned long long)offset,
                (unsigned long long)subregion->size,
-               (unsigned long long)other->offset,
-               (unsigned long long)other->size);
+               subregion->name,
+               (unsigned long long)other->addr,
+               (unsigned long long)other->size,
+               other->name);
 #endif
     }
     QTAILQ_FOREACH(other, &mr->subregions, subregions_link) {
commit be9c4183c44fcde64730446eb76bd68083dfa0db
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Mon Sep 5 11:07:02 2011 +0200

    tcg/ppc64: Only one call output register needed for 64 bit hosts
    
    The second register is only needed for 32 bit hosts.
    
    Cc: Vassili Karpov <av1474 at comtv.ru>
    Fine-with-me'd-by: Vassili Karpov <av1474 at comtv.ru>
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/tcg/ppc64/tcg-target.c b/tcg/ppc64/tcg-target.c
index e3c63ad..3d24cd4 100644
--- a/tcg/ppc64/tcg-target.c
+++ b/tcg/ppc64/tcg-target.c
@@ -130,7 +130,7 @@ static const int tcg_target_call_iarg_regs[] = {
     TCG_REG_R10
 };
 
-static const int tcg_target_call_oarg_regs[2] = {
+static const int tcg_target_call_oarg_regs[] = {
     TCG_REG_R3
 };
 
commit 26a74ae377c01f6e1980b4918027b9eec767bdc7
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Mon Sep 5 11:07:01 2011 +0200

    tcg/sparc: Only one call output register needed for 64 bit hosts
    
    The second register is only needed for 32 bit hosts.
    
    Cc: Blue Swirl <blauwirbel at gmail.com>
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c
index ac76e11..fc3fd7f 100644
--- a/tcg/sparc/tcg-target.c
+++ b/tcg/sparc/tcg-target.c
@@ -84,9 +84,11 @@ static const int tcg_target_call_iarg_regs[6] = {
     TCG_REG_O5,
 };
 
-static const int tcg_target_call_oarg_regs[2] = {
+static const int tcg_target_call_oarg_regs[] = {
     TCG_REG_O0,
-    TCG_REG_O1,
+#if TCG_TARGET_REG_BITS == 32
+    TCG_REG_O1
+#endif
 };
 
 static inline int check_fit_tl(tcg_target_long val, unsigned int bits)
commit 5ddd17b4034077abd206ffbfd1d348ebeb804959
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Mon Sep 5 11:07:00 2011 +0200

    tcg/s390: Only one call output register needed for 64 bit hosts
    
    The second register is only needed for 32 bit hosts.
    
    Cc: Alexander Graf <agraf at suse.de>
    Acked-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c
index 2fc5646..b58df71 100644
--- a/tcg/s390/tcg-target.c
+++ b/tcg/s390/tcg-target.c
@@ -252,7 +252,9 @@ static const int tcg_target_call_iarg_regs[] = {
 
 static const int tcg_target_call_oarg_regs[] = {
     TCG_REG_R2,
-    TCG_REG_R3,
+#if TCG_TARGET_REG_BITS == 32
+    TCG_REG_R3
+#endif
 };
 
 #define S390_CC_EQ      8
commit af15a62309f767ce457e0ac8e3e4b1c5838c4432
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Mon Sep 5 11:06:59 2011 +0200

    tcg/ia64: Only one call output register needed for 64 bit hosts
    
    The second register is never used for ia64 hosts.
    
    Cc: Aurelien Jarno <aurelien at aurel32.net>
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c
index 9db205d..3803ab6 100644
--- a/tcg/ia64/tcg-target.c
+++ b/tcg/ia64/tcg-target.c
@@ -172,9 +172,8 @@ static const int tcg_target_call_iarg_regs[8] = {
     TCG_REG_R63,
 };
 
-static const int tcg_target_call_oarg_regs[2] = {
-    TCG_REG_R8,
-    TCG_REG_R9
+static const int tcg_target_call_oarg_regs[] = {
+    TCG_REG_R8
 };
 
 /* maximum number of register used for input function arguments */
commit 68af23af694b4aa9f8e32b11ab4cc05933178b57
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Mon Sep 5 11:06:58 2011 +0200

    tcg/i386: Only one call output register needed for 64 bit hosts
    
    The second register is only needed for 32 bit hosts.
    
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c
index 7529677..281f87d 100644
--- a/tcg/i386/tcg-target.c
+++ b/tcg/i386/tcg-target.c
@@ -76,9 +76,11 @@ static const int tcg_target_call_iarg_regs[] = {
 #endif
 };
 
-static const int tcg_target_call_oarg_regs[2] = {
+static const int tcg_target_call_oarg_regs[] = {
     TCG_REG_EAX,
+#if TCG_TARGET_REG_BITS == 32
     TCG_REG_EDX
+#endif
 };
 
 static uint8_t *tb_ret_addr;
commit 5c6562c204699616766b0d50c9d8a84d4a029b77
Author: Max Reitz <max at tyndur.org>
Date:   Fri Sep 16 17:29:04 2011 +0200

    target-i386: Fix several SSE3 instructions.
    
    haddp[sd], hsubp[sd] and addsubp[sd] operate on floats, thus it is
    necessary to use the appropriate floating point calculation functions.
    If this is not done, those functions operate merely on integers, which
    is not correct.
    
    Signed-off-by: Max Reitz <max at tyndur.org>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-i386/ops_sse.h b/target-i386/ops_sse.h
index 703be99..aa41d25 100644
--- a/target-i386/ops_sse.h
+++ b/target-i386/ops_sse.h
@@ -859,51 +859,51 @@ void helper_insertq_i(XMMReg *d, int index, int length)
 void helper_haddps(XMMReg *d, XMMReg *s)
 {
     XMMReg r;
-    r.XMM_S(0) = d->XMM_S(0) + d->XMM_S(1);
-    r.XMM_S(1) = d->XMM_S(2) + d->XMM_S(3);
-    r.XMM_S(2) = s->XMM_S(0) + s->XMM_S(1);
-    r.XMM_S(3) = s->XMM_S(2) + s->XMM_S(3);
+    r.XMM_S(0) = float32_add(d->XMM_S(0), d->XMM_S(1), &env->sse_status);
+    r.XMM_S(1) = float32_add(d->XMM_S(2), d->XMM_S(3), &env->sse_status);
+    r.XMM_S(2) = float32_add(s->XMM_S(0), s->XMM_S(1), &env->sse_status);
+    r.XMM_S(3) = float32_add(s->XMM_S(2), s->XMM_S(3), &env->sse_status);
     *d = r;
 }
 
 void helper_haddpd(XMMReg *d, XMMReg *s)
 {
     XMMReg r;
-    r.XMM_D(0) = d->XMM_D(0) + d->XMM_D(1);
-    r.XMM_D(1) = s->XMM_D(0) + s->XMM_D(1);
+    r.XMM_D(0) = float64_add(d->XMM_D(0), d->XMM_D(1), &env->sse_status);
+    r.XMM_D(1) = float64_add(s->XMM_D(0), s->XMM_D(1), &env->sse_status);
     *d = r;
 }
 
 void helper_hsubps(XMMReg *d, XMMReg *s)
 {
     XMMReg r;
-    r.XMM_S(0) = d->XMM_S(0) - d->XMM_S(1);
-    r.XMM_S(1) = d->XMM_S(2) - d->XMM_S(3);
-    r.XMM_S(2) = s->XMM_S(0) - s->XMM_S(1);
-    r.XMM_S(3) = s->XMM_S(2) - s->XMM_S(3);
+    r.XMM_S(0) = float32_sub(d->XMM_S(0), d->XMM_S(1), &env->sse_status);
+    r.XMM_S(1) = float32_sub(d->XMM_S(2), d->XMM_S(3), &env->sse_status);
+    r.XMM_S(2) = float32_sub(s->XMM_S(0), s->XMM_S(1), &env->sse_status);
+    r.XMM_S(3) = float32_sub(s->XMM_S(2), s->XMM_S(3), &env->sse_status);
     *d = r;
 }
 
 void helper_hsubpd(XMMReg *d, XMMReg *s)
 {
     XMMReg r;
-    r.XMM_D(0) = d->XMM_D(0) - d->XMM_D(1);
-    r.XMM_D(1) = s->XMM_D(0) - s->XMM_D(1);
+    r.XMM_D(0) = float64_sub(d->XMM_D(0), d->XMM_D(1), &env->sse_status);
+    r.XMM_D(1) = float64_sub(s->XMM_D(0), s->XMM_D(1), &env->sse_status);
     *d = r;
 }
 
 void helper_addsubps(XMMReg *d, XMMReg *s)
 {
-    d->XMM_S(0) = d->XMM_S(0) - s->XMM_S(0);
-    d->XMM_S(1) = d->XMM_S(1) + s->XMM_S(1);
-    d->XMM_S(2) = d->XMM_S(2) - s->XMM_S(2);
-    d->XMM_S(3) = d->XMM_S(3) + s->XMM_S(3);
+    d->XMM_S(0) = float32_sub(d->XMM_S(0), s->XMM_S(0), &env->sse_status);
+    d->XMM_S(1) = float32_add(d->XMM_S(1), s->XMM_S(1), &env->sse_status);
+    d->XMM_S(2) = float32_sub(d->XMM_S(2), s->XMM_S(2), &env->sse_status);
+    d->XMM_S(3) = float32_add(d->XMM_S(3), s->XMM_S(3), &env->sse_status);
 }
 
 void helper_addsubpd(XMMReg *d, XMMReg *s)
 {
-    d->XMM_D(0) = d->XMM_D(0) - s->XMM_D(0);
-    d->XMM_D(1) = d->XMM_D(1) + s->XMM_D(1);
+    d->XMM_D(0) = float64_sub(d->XMM_D(0), s->XMM_D(0), &env->sse_status);
+    d->XMM_D(1) = float64_add(d->XMM_D(1), s->XMM_D(1), &env->sse_status);
 }
 
 /* XXX: unordered */
commit 4e1837f855b88fdced2941b17509e13b0c8fa518
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Tue Sep 13 13:34:37 2011 +0100

    trace: add virtio_set_status() trace event
    
    The virtio device lifecycle can be observed by looking at the sequence
    of set status operations.  This is especially important for catching the
    reset operation (status value 0), which resets the device and all
    virtqueues.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/virtio.c b/hw/virtio.c
index 13aa0fa..946d911 100644
--- a/hw/virtio.c
+++ b/hw/virtio.c
@@ -498,6 +498,16 @@ void virtio_update_irq(VirtIODevice *vdev)
     virtio_notify_vector(vdev, VIRTIO_NO_VECTOR);
 }
 
+void virtio_set_status(VirtIODevice *vdev, uint8_t val)
+{
+    trace_virtio_set_status(vdev, val);
+
+    if (vdev->set_status) {
+        vdev->set_status(vdev, val);
+    }
+    vdev->status = val;
+}
+
 void virtio_reset(void *opaque)
 {
     VirtIODevice *vdev = opaque;
diff --git a/hw/virtio.h b/hw/virtio.h
index 4d20d9b..2d18209 100644
--- a/hw/virtio.h
+++ b/hw/virtio.h
@@ -135,14 +135,6 @@ struct VirtIODevice
     VMChangeStateEntry *vmstate;
 };
 
-static inline void virtio_set_status(VirtIODevice *vdev, uint8_t val)
-{
-    if (vdev->set_status) {
-        vdev->set_status(vdev, val);
-    }
-    vdev->status = val;
-}
-
 VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
                             void (*handle_output)(VirtIODevice *,
                                                   VirtQueue *));
@@ -190,6 +182,7 @@ int virtio_queue_get_num(VirtIODevice *vdev, int n);
 void virtio_queue_notify(VirtIODevice *vdev, int n);
 uint16_t virtio_queue_vector(VirtIODevice *vdev, int n);
 void virtio_queue_set_vector(VirtIODevice *vdev, int n, uint16_t vector);
+void virtio_set_status(VirtIODevice *vdev, uint8_t val);
 void virtio_reset(void *opaque);
 void virtio_update_irq(VirtIODevice *vdev);
 
diff --git a/trace-events b/trace-events
index 84b5a88..829dc92 100644
--- a/trace-events
+++ b/trace-events
@@ -42,6 +42,7 @@ virtqueue_pop(void *vq, void *elem, unsigned int in_num, unsigned int out_num) "
 virtio_queue_notify(void *vdev, int n, void *vq) "vdev %p n %d vq %p"
 virtio_irq(void *vq) "vq %p"
 virtio_notify(void *vdev, void *vq) "vdev %p vq %p"
+virtio_set_status(void *vdev, uint8_t val) "vdev %p val %u"
 
 # hw/virtio-serial-bus.c
 virtio_serial_send_control_event(unsigned int port, uint16_t event, uint16_t value) "port %u, event %u, value %u"
commit 689d7e2fadb27d696528eb1f86eb3e3e19e07761
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Tue Sep 13 13:34:36 2011 +0100

    trace: remove trailing double quotes after PRI*64
    
    Now that format strings can end in a PRI*64 macro, remove the
    workarounds from the trace-events file.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/trace-events b/trace-events
index 2448bce..84b5a88 100644
--- a/trace-events
+++ b/trace-events
@@ -88,8 +88,8 @@ balloon_event(void *opaque, unsigned long addr) "opaque %p addr %lu"
 # hw/apic.c
 apic_local_deliver(int vector, uint32_t lvt) "vector %d delivery mode %d"
 apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode, uint8_t vector_num, uint8_t trigger_mode) "dest %d dest_mode %d delivery_mode %d vector %d trigger_mode %d"
-cpu_set_apic_base(uint64_t val) "%016"PRIx64""
-cpu_get_apic_base(uint64_t val) "%016"PRIx64""
+cpu_set_apic_base(uint64_t val) "%016"PRIx64
+cpu_get_apic_base(uint64_t val) "%016"PRIx64
 apic_mem_readl(uint64_t addr, uint32_t val)  "%"PRIx64" = %08x"
 apic_mem_writel(uint64_t addr, uint32_t val) "%"PRIx64" = %08x"
 # coalescing
@@ -169,21 +169,21 @@ slavio_led_mem_readw(uint32_t ret) "Read diagnostic LED %04x"
 # hw/slavio_timer.c
 slavio_timer_get_out(uint64_t limit, uint32_t counthigh, uint32_t count) "limit %"PRIx64" count %x%08x"
 slavio_timer_irq(uint32_t counthigh, uint32_t count) "callback: count %x%08x"
-slavio_timer_mem_readl_invalid(uint64_t addr) "invalid read address %"PRIx64""
+slavio_timer_mem_readl_invalid(uint64_t addr) "invalid read address %"PRIx64
 slavio_timer_mem_readl(uint64_t addr, uint32_t ret) "read %"PRIx64" = %08x"
 slavio_timer_mem_writel(uint64_t addr, uint32_t val) "write %"PRIx64" = %08x"
-slavio_timer_mem_writel_limit(unsigned int timer_index, uint64_t count) "processor %d user timer set to %016"PRIx64""
+slavio_timer_mem_writel_limit(unsigned int timer_index, uint64_t count) "processor %d user timer set to %016"PRIx64
 slavio_timer_mem_writel_counter_invalid(void) "not user timer"
 slavio_timer_mem_writel_status_start(unsigned int timer_index) "processor %d user timer started"
 slavio_timer_mem_writel_status_stop(unsigned int timer_index) "processor %d user timer stopped"
 slavio_timer_mem_writel_mode_user(unsigned int timer_index) "processor %d changed from counter to user timer"
 slavio_timer_mem_writel_mode_counter(unsigned int timer_index) "processor %d changed from user timer to counter"
 slavio_timer_mem_writel_mode_invalid(void) "not system timer"
-slavio_timer_mem_writel_invalid(uint64_t addr) "invalid write address %"PRIx64""
+slavio_timer_mem_writel_invalid(uint64_t addr) "invalid write address %"PRIx64
 
 # hw/sparc32_dma.c
-ledma_memory_read(uint64_t addr) "DMA read addr 0x%"PRIx64""
-ledma_memory_write(uint64_t addr) "DMA write addr 0x%"PRIx64""
+ledma_memory_read(uint64_t addr) "DMA read addr 0x%"PRIx64
+ledma_memory_write(uint64_t addr) "DMA write addr 0x%"PRIx64
 sparc32_dma_set_irq_raise(void) "Raise IRQ"
 sparc32_dma_set_irq_lower(void) "Lower IRQ"
 espdma_memory_read(uint32_t addr) "DMA read addr 0x%08x"
@@ -202,12 +202,12 @@ sun4m_cpu_set_irq_lower(int level) "Lower CPU IRQ %d"
 # hw/sun4m_iommu.c
 sun4m_iommu_mem_readl(uint64_t addr, uint32_t ret) "read reg[%"PRIx64"] = %x"
 sun4m_iommu_mem_writel(uint64_t addr, uint32_t val) "write reg[%"PRIx64"] = %x"
-sun4m_iommu_mem_writel_ctrl(uint64_t iostart) "iostart = %"PRIx64""
+sun4m_iommu_mem_writel_ctrl(uint64_t iostart) "iostart = %"PRIx64
 sun4m_iommu_mem_writel_tlbflush(uint32_t val) "tlb flush %x"
 sun4m_iommu_mem_writel_pgflush(uint32_t val) "page flush %x"
 sun4m_iommu_page_get_flags(uint64_t pa, uint64_t iopte, uint32_t ret) "get flags addr %"PRIx64" => pte %"PRIx64", *pte = %x"
 sun4m_iommu_translate_pa(uint64_t addr, uint64_t pa, uint32_t iopte) "xlate dva %"PRIx64" => pa %"PRIx64" iopte = %x"
-sun4m_iommu_bad_addr(uint64_t addr) "bad addr %"PRIx64""
+sun4m_iommu_bad_addr(uint64_t addr) "bad addr %"PRIx64
 
 # hw/usb-bus.c
 usb_port_claim(int bus, const char *port) "bus %d, port %s"
@@ -278,7 +278,7 @@ scsi_req_data(int target, int lun, int tag, int len) "target %d lun %d tag %d le
 scsi_req_dequeue(int target, int lun, int tag) "target %d lun %d tag %d"
 scsi_req_continue(int target, int lun, int tag) "target %d lun %d tag %d"
 scsi_req_parsed(int target, int lun, int tag, int cmd, int mode, int xfer) "target %d lun %d tag %d command %d dir %d length %d"
-scsi_req_parsed_lba(int target, int lun, int tag, int cmd, uint64_t lba) "target %d lun %d tag %d command %d lba %"PRIu64""
+scsi_req_parsed_lba(int target, int lun, int tag, int cmd, uint64_t lba) "target %d lun %d tag %d command %d lba %"PRIu64
 scsi_req_parse_bad(int target, int lun, int tag, int cmd) "target %d lun %d tag %d command %d"
 scsi_req_build_sense(int target, int lun, int tag, int key, int asc, int ascq) "target %d lun %d tag %d key %#02x asc %#02x ascq %#02x"
 scsi_report_luns(int target, int lun, int tag) "target %d lun %d tag %d"
@@ -306,11 +306,11 @@ qed_start_need_check_timer(void *s) "s %p"
 qed_cancel_need_check_timer(void *s) "s %p"
 qed_aio_complete(void *s, void *acb, int ret) "s %p acb %p ret %d"
 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"
-qed_aio_next_io(void *s, void *acb, int ret, uint64_t cur_pos) "s %p acb %p ret %d cur_pos %"PRIu64""
+qed_aio_next_io(void *s, void *acb, int ret, uint64_t cur_pos) "s %p acb %p ret %d cur_pos %"PRIu64
 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"
 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"
-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""
-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""
+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
+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
 qed_aio_write_main(void *s, void *acb, int ret, uint64_t offset, size_t len) "s %p acb %p ret %d offset %"PRIu64" len %zu"
 
 # hw/g364fb.c
@@ -330,7 +330,7 @@ grlib_gptimer_writel(int id, uint64_t addr, uint32_t val) "timer:%d addr 0x%"PRI
 grlib_irqmp_check_irqs(uint32_t pend, uint32_t force, uint32_t mask, uint32_t lvl1, uint32_t lvl2) "pend:0x%04x force:0x%04x mask:0x%04x lvl1:0x%04x lvl0:0x%04x"
 grlib_irqmp_ack(int intno) "interrupt:%d"
 grlib_irqmp_set_irq(int irq) "Raise CPU IRQ %d"
-grlib_irqmp_readl_unknown(uint64_t addr) "addr 0x%"PRIx64""
+grlib_irqmp_readl_unknown(uint64_t addr) "addr 0x%"PRIx64
 grlib_irqmp_writel_unknown(uint64_t addr, uint32_t value) "addr 0x%"PRIx64" value 0x%x"
 
 # hw/grlib_apbuart.c
@@ -462,10 +462,10 @@ xen_ram_alloc(unsigned long ram_addr, unsigned long size) "requested: %#lx, size
 xen_client_set_memory(uint64_t start_addr, unsigned long size, unsigned long phys_offset, bool log_dirty) "%#"PRIx64" size %#lx, offset %#lx, log_dirty %i"
 
 # xen-mapcache.c
-xen_map_cache(uint64_t phys_addr) "want %#"PRIx64""
-xen_remap_bucket(uint64_t index) "index %#"PRIx64""
+xen_map_cache(uint64_t phys_addr) "want %#"PRIx64
+xen_remap_bucket(uint64_t index) "index %#"PRIx64
 xen_map_cache_return(void* ptr) "%p"
-xen_map_block(uint64_t phys_addr, uint64_t size) "%#"PRIx64", size %#"PRIx64""
+xen_map_block(uint64_t phys_addr, uint64_t size) "%#"PRIx64", size %#"PRIx64
 xen_unmap_block(void* addr, unsigned long size) "%p, size %#lx"
 
 # exec.c
commit 913540a376f01569227b9a6480a2e96ae9d1d406
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Tue Sep 13 13:34:35 2011 +0100

    trace: allow PRI*64 at beginning and ending of format string
    
    The tracetool parser only picks up PRI*64 and other format string macros
    when enclosed between double quoted strings.  Lift this restriction by
    extracting everything after the closing ')' as the format string:
    
      cpu_set_apic_base(uint64_t val) "%016"PRIx64
                                      ^^        ^^
    
    One trick here: it turns out that backslashes in the format string like
    "\n" were being interpreted by echo(1).  Fix this by using the POSIX
    printf(1) command instead.  Although it normally does not make sense to
    include backslashes in trace event format strings, an injected newline
    causes tracetool to emit a broken header file and I want to eliminate
    cases where broken output is emitted, even if the input was bad.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/docs/tracing.txt b/docs/tracing.txt
index 4b27ab0..d0171aa 100644
--- a/docs/tracing.txt
+++ b/docs/tracing.txt
@@ -80,10 +80,7 @@ Trace events should use types as follows:
 
 Format strings should reflect the types defined in the trace event.  Take
 special care to use PRId64 and PRIu64 for int64_t and uint64_t types,
-respectively.  This ensures portability between 32- and 64-bit platforms.  Note
-that format strings must begin and end with double quotes.  When using
-portability macros, ensure they are preceded and followed by double quotes:
-"value %"PRIx64"".
+respectively.  This ensures portability between 32- and 64-bit platforms.
 
 === Hints for adding new trace events ===
 
diff --git a/scripts/tracetool b/scripts/tracetool
index 743d246..4c9951d 100755
--- a/scripts/tracetool
+++ b/scripts/tracetool
@@ -40,6 +40,15 @@ EOF
     exit 1
 }
 
+# Print a line without interpreting backslash escapes
+#
+# The built-in echo command may interpret backslash escapes without an option
+# to disable this behavior.
+puts()
+{
+    printf "%s\n" "$1"
+}
+
 # Get the name of a trace event
 get_name()
 {
@@ -111,13 +120,10 @@ get_argc()
     echo $argc
 }
 
-# Get the format string for a trace event
+# Get the format string including double quotes for a trace event
 get_fmt()
 {
-    local fmt
-    fmt=${1#*\"}
-    fmt=${fmt%\"*}
-    echo "$fmt"
+    puts "${1#*)}"
 }
 
 linetoh_begin_nop()
@@ -266,7 +272,7 @@ linetoh_stderr()
 static inline void trace_$name($args)
 {
     if (trace_list[$stderr_event_num].state != 0) {
-        fprintf(stderr, "$name $fmt\n" $argnames);
+        fprintf(stderr, "$name " $fmt "\n" $argnames);
     }
 }
 EOF
@@ -366,7 +372,7 @@ DEFINE_TRACE(ust_$name);
 
 static void ust_${name}_probe($args)
 {
-    trace_mark(ust, $name, "$fmt"$argnames);
+    trace_mark(ust, $name, $fmt$argnames);
 }
 EOF
 
commit 2f4a725b94289250b7fd570f059117b4595d89e7
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date:   Tue Sep 13 13:34:34 2011 +0100

    trace: remove newline from grlib_irqmp_check_irqs format string
    
    There is no need to put a newline in trace event format strings.  The
    backend may use the format string within some context and takes care of
    how to display the event.  The stderr backend automatically appends "\n"
    whereas the ust backend does not want a newline at all.
    
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/trace-events b/trace-events
index 8bed3be..2448bce 100644
--- a/trace-events
+++ b/trace-events
@@ -327,7 +327,7 @@ grlib_gptimer_readl(int id, uint64_t addr, uint32_t val) "timer:%d addr 0x%"PRIx
 grlib_gptimer_writel(int id, uint64_t addr, uint32_t val) "timer:%d addr 0x%"PRIx64" 0x%x"
 
 # hw/grlib_irqmp.c
-grlib_irqmp_check_irqs(uint32_t pend, uint32_t force, uint32_t mask, uint32_t lvl1, uint32_t lvl2) "pend:0x%04x force:0x%04x mask:0x%04x lvl1:0x%04x lvl0:0x%04x\n"
+grlib_irqmp_check_irqs(uint32_t pend, uint32_t force, uint32_t mask, uint32_t lvl1, uint32_t lvl2) "pend:0x%04x force:0x%04x mask:0x%04x lvl1:0x%04x lvl0:0x%04x"
 grlib_irqmp_ack(int intno) "interrupt:%d"
 grlib_irqmp_set_irq(int irq) "Raise CPU IRQ %d"
 grlib_irqmp_readl_unknown(uint64_t addr) "addr 0x%"PRIx64""
commit 519e1693d4b4f3b0a1a24f3f092d54c38a6d8ad8
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Fri Sep 16 21:50:43 2011 +0200

    Makefile: Fix broken build
    
    make -C mybuilddir no longer works (regression caused by commit)
    388d475815c23901010a25c845eb078d47ee0740.
    
    PWD is the directory of the caller (not mybuilddir),
    so BUILD_DIR is set to the wrong value.
    
    GNU make sets CURDIR to the correct value.
    Use this macro instead of PWD.
    
    Cc: Lluís Vilanova <vilanova at ac.upc.edu>
    Cc: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/Makefile b/Makefile
index 57cc399..a211158 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 # Makefile for QEMU.
 
-# Always point to the root of the build tree
-BUILD_DIR=$(PWD)
+# Always point to the root of the build tree (needs GNU make).
+BUILD_DIR=$(CURDIR)
 
 GENERATED_HEADERS = config-host.h trace.h qemu-options.def
 ifeq ($(TRACE_BACKEND),dtrace)
commit a8467c7a0e8b024a18608ff7db31ca2f2297e641
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Sep 16 11:25:05 2011 +0200

    qdev: print bus properties too
    
    Make qdev_device_help print both device and bus properties.
    Helps libvirt to figure whenever bus properties such as
    PCI.multifunction are supported present or not.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/qdev.c b/hw/qdev.c
index c463c52..a223d41 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -207,6 +207,12 @@ int qdev_device_help(QemuOpts *opts)
         }
         error_printf("%s.%s=%s\n", info->name, prop->name, prop->info->name);
     }
+    for (prop = info->bus_info->props; prop && prop->name; prop++) {
+        if (!prop->info->parse) {
+            continue;           /* no way to set it, don't show */
+        }
+        error_printf("%s.%s=%s\n", info->name, prop->name, prop->info->name);
+    }
     return 1;
 }
 
commit 71579cae30b53c910cd6c47ab4e683f647d36519
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Thu Sep 15 11:26:56 2011 +0200

    vga: Respect isa_mem_base when registering chain4 alias
    
    This does not yet unbreak PPC (which has its own problems) but
    potentially other non-x86 systems where isa_mem_base is != 0.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/vga.c b/hw/vga.c
index 7be5141..f9a6014 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -181,6 +181,7 @@ static void vga_update_memory_access(VGACommonState *s)
             size = 0x8000;
             break;
         }
+        base += isa_mem_base;
         region = g_malloc(sizeof(*region));
         memory_region_init_alias(region, "vga.chain4", &s->vram, offset, size);
         memory_region_add_subregion_overlap(s->legacy_address_space, base,
commit df3f457b4b3a910de575b39bfa11d9a41330077c
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Mon Sep 12 15:43:31 2011 +0100

    hw/integratorcp: Fix bugs in writes to CM_CTRL system register
    
    Fix a number of bugs in the implementation of writes to the CM_CTRL
    system register:
     * write to cm_ctrl, not cm_init !
     * an '&' vs '^' typo meant we would write the inverse of the bits
     * handling the LED via printf() meant we spew lots of output
       to stdout when Linux uses the LED as a heartbeat indicator
     * we would hw_error() if a reset was requested rather than
       actually resetting
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/integratorcp.c b/hw/integratorcp.c
index 3c8982e..9a289b4 100644
--- a/hw/integratorcp.c
+++ b/hw/integratorcp.c
@@ -14,6 +14,7 @@
 #include "arm-misc.h"
 #include "net.h"
 #include "exec-memory.h"
+#include "sysemu.h"
 
 typedef struct {
     SysBusDevice busdev;
@@ -126,15 +127,20 @@ static void integratorcm_do_remap(integratorcm_state *s, int flash)
 static void integratorcm_set_ctrl(integratorcm_state *s, uint32_t value)
 {
     if (value & 8) {
-        hw_error("Board reset\n");
+        qemu_system_reset_request();
     }
-    if ((s->cm_init ^ value) & 4) {
+    if ((s->cm_ctrl ^ value) & 4) {
         integratorcm_do_remap(s, (value & 4) == 0);
     }
-    if ((s->cm_init ^ value) & 1) {
-        printf("Green LED %s\n", (value & 1) ? "on" : "off");
+    if ((s->cm_ctrl ^ value) & 1) {
+        /* (value & 1) != 0 means the green "MISC LED" is lit.
+         * We don't have any nice place to display LEDs. printf is a bad
+         * idea because Linux uses the LED as a heartbeat and the output
+         * will swamp anything else on the terminal.
+         */
     }
-    s->cm_init = (s->cm_init & ~ 5) | (value ^ 5);
+    /* Note that the RESET bit [3] always reads as zero */
+    s->cm_ctrl = (s->cm_ctrl & ~5) | (value & 5);
 }
 
 static void integratorcm_update(integratorcm_state *s)
commit f44cc4852a04c0423780e115b935e201aaf3384e
Author: Christoph Egger <Christoph.Egger at amd.com>
Date:   Tue Sep 13 15:12:06 2011 +0200

    bswap.h: build fix
    
    qemu build fails when CONFIG_MACHINE_BSWAP_H is defined
    because float32, float64, etc. are not defined.
    This makes qemu build.
    
    Signed-off-by: Christoph Egger <Christoph.Egger at amd.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/bswap.h b/bswap.h
index f41bebe..cc7f84d 100644
--- a/bswap.h
+++ b/bswap.h
@@ -4,6 +4,7 @@
 #include "config-host.h"
 
 #include <inttypes.h>
+#include "softfloat.h"
 
 #ifdef CONFIG_MACHINE_BSWAP_H
 #include <sys/endian.h>
@@ -11,8 +12,6 @@
 #include <machine/bswap.h>
 #else
 
-#include "softfloat.h"
-
 #ifdef CONFIG_BYTESWAP_H
 #include <byteswap.h>
 #else
commit f81bdefb63243e82d16ce49332f7cf74d10b8f27
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Fri Sep 16 00:48:07 2011 +0200

    console: Properly switch consoles for screen dumps
    
    Do not mess with active_console, use console_select instead. This fixes
    corrupt virtual monitor consoles after issuing the screendump command.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/console.c b/console.c
index 5c7a93b..6dfcc47 100644
--- a/console.c
+++ b/console.c
@@ -115,6 +115,7 @@ typedef enum {
 /* ??? This is mis-named.
    It is used for both text and graphical consoles.  */
 struct TextConsole {
+    int index;
     console_type_t console_type;
     DisplayState *ds;
     /* Graphic console state.  */
@@ -177,12 +178,15 @@ void vga_hw_screen_dump(const char *filename)
     TextConsole *previous_active_console;
 
     previous_active_console = active_console;
-    active_console = consoles[0];
+
     /* There is currently no way of specifying which screen we want to dump,
        so always dump the first one.  */
-    if (consoles[0] && consoles[0]->hw_screen_dump)
+    console_select(0);
+    if (consoles[0] && consoles[0]->hw_screen_dump) {
         consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
-    active_console = previous_active_console;
+    }
+
+    console_select(previous_active_console->index);
 }
 
 void vga_hw_text_update(console_ch_t *chardata)
@@ -1247,6 +1251,7 @@ static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
     s->ds = ds;
     s->console_type = console_type;
     if (console_type != GRAPHIC_CONSOLE) {
+        s->index = nb_consoles;
         consoles[nb_consoles++] = s;
     } else {
         /* HACK: Put graphical consoles before text consoles.  */
@@ -1254,7 +1259,9 @@ static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
             if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
                 break;
             consoles[i] = consoles[i - 1];
+            consoles[i]->index = i;
         }
+        s->index = i;
         consoles[i] = s;
         nb_consoles++;
     }
commit 2313e998d7bf55d02499ee162fb4558af4fbb3f5
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Fri Sep 16 00:47:55 2011 +0200

    vga: Fix text mode screendumps
    
    In text mode, even a full refresh of the screen takes multiple updates.
    As we reset the dump file pointer after the first call, we only wrote
    the first line.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/vga.c b/hw/vga.c
index 125fb29..7be5141 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -149,7 +149,7 @@ static uint16_t expand2[256];
 static uint8_t expand4to8[16];
 
 static void vga_screen_dump(void *opaque, const char *filename);
-static char *screen_dump_filename;
+static const char *screen_dump_filename;
 static DisplayChangeListener *screen_dump_dcl;
 
 static void vga_update_memory_access(VGACommonState *s)
@@ -2318,7 +2318,6 @@ static void vga_save_dpy_update(DisplayState *ds,
 {
     if (screen_dump_filename) {
         ppm_save(screen_dump_filename, ds->surface);
-        screen_dump_filename = NULL;
     }
 }
 
@@ -2396,8 +2395,8 @@ static void vga_screen_dump(void *opaque, const char *filename)
     if (!screen_dump_dcl)
         screen_dump_dcl = vga_screen_dump_init(s->ds);
 
-    screen_dump_filename = (char *)filename;
+    screen_dump_filename = filename;
     vga_invalidate_display(s);
     vga_hw_update();
+    screen_dump_filename = NULL;
 }
-
commit d9389b9664df561db796b18eb8309fffe58faf8b
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Wed Sep 14 15:38:40 2011 +0200

    Fix termination by signal with -no-shutdown
    
    On signals such as SIGTERM qemu should exit instead of just stopping the VM
    even with -no-shutdown.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/vl.c b/vl.c
index b773d2f..0c2fc3f 100644
--- a/vl.c
+++ b/vl.c
@@ -1296,6 +1296,7 @@ void qemu_system_killed(int signal, pid_t pid)
 {
     shutdown_signal = signal;
     shutdown_pid = pid;
+    no_shutdown = 0;
     qemu_system_shutdown_request();
 }
 
commit b2bedb214469af55179d907a60cd67fed6b0779e
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Mon Sep 12 22:33:01 2011 +0200

    Remove blanks before \n in output strings
    
    Those blanks violate the coding conventions, see
    scripts/checkpatch.pl.
    
    Blanks missing after colons in the changed lines were added.
    
    This patch does not try to fix tabs, long lines and other
    problems in the changed lines, therefore checkpatch.pl reports
    many violations.
    
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/block/vvfat.c b/block/vvfat.c
index 187ac96..f567c9a 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -1789,7 +1789,7 @@ DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)clu
 	for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
 	    int cluster_count = 0;
 
-DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i));
+DLOG(fprintf(stderr, "check direntry %d:\n", i); print_direntry(direntries + i));
 	    if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
 		    is_free(direntries + i))
 		continue;
diff --git a/darwin-user/machload.c b/darwin-user/machload.c
index 3bc3b65..0aa8282 100644
--- a/darwin-user/machload.c
+++ b/darwin-user/machload.c
@@ -865,11 +865,11 @@ unsigned long setup_arg_pages(void * mh, char ** argv, char ** env)
         page_set_flags((int)argv[i], (int)(argv[i]+strlen(argv[i])), PROT_READ | PAGE_VALID);
     }
 
-    DPRINTF("pushing argc %d \n", argc);
+    DPRINTF("pushing argc %d\n", argc);
     stl(stack, argc);
     stack--;
 
-    DPRINTF("pushing mh 0x%x \n", (int)mh);
+    DPRINTF("pushing mh 0x%x\n", (int)mh);
     stl(stack, (int) mh);
 
     /* Stack points on the mh */
diff --git a/hw/bonito.c b/hw/bonito.c
index 8708e95..fdb8198 100644
--- a/hw/bonito.c
+++ b/hw/bonito.c
@@ -241,7 +241,7 @@ static void bonito_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
 
     saddr = (addr - BONITO_REGBASE) >> 2;
 
-    DPRINTF("bonito_writel "TARGET_FMT_plx" val %x saddr %x \n", addr, val, saddr);
+    DPRINTF("bonito_writel "TARGET_FMT_plx" val %x saddr %x\n", addr, val, saddr);
     switch (saddr) {
     case BONITO_BONPONCFG:
     case BONITO_IODEVCFG:
@@ -287,10 +287,10 @@ static void bonito_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
         break;
     case BONITO_INTEN:
     case BONITO_INTISR:
-        DPRINTF("write to readonly bonito register %x \n", saddr);
+        DPRINTF("write to readonly bonito register %x\n", saddr);
         break;
     default:
-        DPRINTF("write to unknown bonito register %x \n", saddr);
+        DPRINTF("write to unknown bonito register %x\n", saddr);
         break;
     }
 }
@@ -302,7 +302,7 @@ static uint32_t bonito_readl(void *opaque, target_phys_addr_t addr)
 
     saddr = (addr - BONITO_REGBASE) >> 2;
 
-    DPRINTF("bonito_readl "TARGET_FMT_plx"  \n", addr);
+    DPRINTF("bonito_readl "TARGET_FMT_plx"\n", addr);
     switch (saddr) {
     case BONITO_INTISR:
         return s->regs[saddr];
@@ -328,7 +328,7 @@ static void bonito_pciconf_writel(void *opaque, target_phys_addr_t addr,
 {
     PCIBonitoState *s = opaque;
 
-    DPRINTF("bonito_pciconf_writel "TARGET_FMT_plx" val %x \n", addr, val);
+    DPRINTF("bonito_pciconf_writel "TARGET_FMT_plx" val %x\n", addr, val);
     s->dev.config_write(&s->dev, addr, val, 4);
 }
 
@@ -443,7 +443,7 @@ static uint32_t bonito_sbridge_pciaddr(void *opaque, target_phys_addr_t addr)
         exit(1);
     }
     pciaddr = PCI_ADDR(pci_bus_num(s->pcihost->bus), devno, funno, regno);
-    DPRINTF("cfgaddr %x pciaddr %x busno %x devno %d funno %d regno %d \n",
+    DPRINTF("cfgaddr %x pciaddr %x busno %x devno %d funno %d regno %d\n",
         cfgaddr, pciaddr, pci_bus_num(s->pcihost->bus), devno, funno, regno);
 
     return pciaddr;
@@ -456,7 +456,7 @@ static void bonito_spciconf_writeb(void *opaque, target_phys_addr_t addr,
     uint32_t pciaddr;
     uint16_t status;
 
-    DPRINTF("bonito_spciconf_writeb "TARGET_FMT_plx" val %x \n", addr, val);
+    DPRINTF("bonito_spciconf_writeb "TARGET_FMT_plx" val %x\n", addr, val);
     pciaddr = bonito_sbridge_pciaddr(s, addr);
 
     if (pciaddr == 0xffffffff) {
@@ -480,7 +480,7 @@ static void bonito_spciconf_writew(void *opaque, target_phys_addr_t addr,
     uint32_t pciaddr;
     uint16_t status;
 
-    DPRINTF("bonito_spciconf_writew "TARGET_FMT_plx" val %x \n", addr, val);
+    DPRINTF("bonito_spciconf_writew "TARGET_FMT_plx" val %x\n", addr, val);
     assert((addr&0x1)==0);
 
     pciaddr = bonito_sbridge_pciaddr(s, addr);
@@ -506,7 +506,7 @@ static void bonito_spciconf_writel(void *opaque, target_phys_addr_t addr,
     uint32_t pciaddr;
     uint16_t status;
 
-    DPRINTF("bonito_spciconf_writel "TARGET_FMT_plx" val %x \n", addr, val);
+    DPRINTF("bonito_spciconf_writel "TARGET_FMT_plx" val %x\n", addr, val);
     assert((addr&0x3)==0);
 
     pciaddr = bonito_sbridge_pciaddr(s, addr);
@@ -531,7 +531,7 @@ static uint32_t bonito_spciconf_readb(void *opaque, target_phys_addr_t addr)
     uint32_t pciaddr;
     uint16_t status;
 
-    DPRINTF("bonito_spciconf_readb "TARGET_FMT_plx"  \n", addr);
+    DPRINTF("bonito_spciconf_readb "TARGET_FMT_plx"\n", addr);
     pciaddr = bonito_sbridge_pciaddr(s, addr);
 
     if (pciaddr == 0xffffffff) {
@@ -555,7 +555,7 @@ static uint32_t bonito_spciconf_readw(void *opaque, target_phys_addr_t addr)
     uint32_t pciaddr;
     uint16_t status;
 
-    DPRINTF("bonito_spciconf_readw "TARGET_FMT_plx"  \n", addr);
+    DPRINTF("bonito_spciconf_readw "TARGET_FMT_plx"\n", addr);
     assert((addr&0x1)==0);
 
     pciaddr = bonito_sbridge_pciaddr(s, addr);
@@ -581,7 +581,7 @@ static uint32_t bonito_spciconf_readl(void *opaque, target_phys_addr_t addr)
     uint32_t pciaddr;
     uint16_t status;
 
-    DPRINTF("bonito_spciconf_readl "TARGET_FMT_plx"  \n", addr);
+    DPRINTF("bonito_spciconf_readl "TARGET_FMT_plx"\n", addr);
     assert((addr&0x3) == 0);
 
     pciaddr = bonito_sbridge_pciaddr(s, addr);
diff --git a/hw/fmopl.c b/hw/fmopl.c
index d8a0f36..5ad52ab 100644
--- a/hw/fmopl.c
+++ b/hw/fmopl.c
@@ -606,7 +606,7 @@ static void init_timetables( FM_OPL *OPL , int ARRATE , int DRRATE )
 	}
 #if 0
 	for (i = 0;i < 64 ;i++){	/* make for overflow area */
-		LOG(LOG_WAR,("rate %2d , ar %f ms , dr %f ms \n",i,
+		LOG(LOG_WAR, ("rate %2d , ar %f ms , dr %f ms\n", i,
 			((double)(EG_ENT<<ENV_BITS) / OPL->AR_TABLE[i]) * (1000.0 / OPL->rate),
 			((double)(EG_ENT<<ENV_BITS) / OPL->DR_TABLE[i]) * (1000.0 / OPL->rate) ));
 	}
diff --git a/hw/hpet.c b/hw/hpet.c
index 4eda33d..12bd64d 100644
--- a/hw/hpet.c
+++ b/hw/hpet.c
@@ -397,7 +397,7 @@ static uint32_t hpet_ram_readl(void *opaque, target_phys_addr_t addr)
         case HPET_CFG:
             return s->config;
         case HPET_CFG + 4:
-            DPRINTF("qemu: invalid HPET_CFG + 4 hpet_ram_readl \n");
+            DPRINTF("qemu: invalid HPET_CFG + 4 hpet_ram_readl\n");
             return 0;
         case HPET_COUNTER:
             if (hpet_enabled(s)) {
@@ -458,7 +458,7 @@ static void hpet_ram_writel(void *opaque, target_phys_addr_t addr,
         uint8_t timer_id = (addr - 0x100) / 0x20;
         HPETTimer *timer = &s->timer[timer_id];
 
-        DPRINTF("qemu: hpet_ram_writel timer_id = %#x \n", timer_id);
+        DPRINTF("qemu: hpet_ram_writel timer_id = %#x\n", timer_id);
         if (timer_id > s->num_timers) {
             DPRINTF("qemu: timer id out of range\n");
             return;
@@ -485,7 +485,7 @@ static void hpet_ram_writel(void *opaque, target_phys_addr_t addr,
             DPRINTF("qemu: invalid HPET_TN_CFG+4 write\n");
             break;
         case HPET_TN_CMP: // comparator register
-            DPRINTF("qemu: hpet_ram_writel HPET_TN_CMP \n");
+            DPRINTF("qemu: hpet_ram_writel HPET_TN_CMP\n");
             if (timer->config & HPET_TN_32BIT) {
                 new_val = (uint32_t)new_val;
             }
@@ -570,7 +570,7 @@ static void hpet_ram_writel(void *opaque, target_phys_addr_t addr,
             }
             break;
         case HPET_CFG + 4:
-            DPRINTF("qemu: invalid HPET_CFG+4 write \n");
+            DPRINTF("qemu: invalid HPET_CFG+4 write\n");
             break;
         case HPET_STATUS:
             val = new_val & s->isr;
diff --git a/hw/loader.c b/hw/loader.c
index 8efb146..5676c18 100644
--- a/hw/loader.c
+++ b/hw/loader.c
@@ -779,13 +779,13 @@ void do_info_roms(Monitor *mon)
     QTAILQ_FOREACH(rom, &roms, next) {
         if (!rom->fw_file) {
             monitor_printf(mon, "addr=" TARGET_FMT_plx
-                           " size=0x%06zx mem=%s name=\"%s\" \n",
+                           " size=0x%06zx mem=%s name=\"%s\"\n",
                            rom->addr, rom->romsize,
                            rom->isrom ? "rom" : "ram",
                            rom->name);
         } else {
             monitor_printf(mon, "fw=%s/%s"
-                           " size=0x%06zx name=\"%s\" \n",
+                           " size=0x%06zx name=\"%s\"\n",
                            rom->fw_dir,
                            rom->fw_file,
                            rom->romsize,
diff --git a/hw/mips_fulong2e.c b/hw/mips_fulong2e.c
index abe3056..f52b8c5 100644
--- a/hw/mips_fulong2e.c
+++ b/hw/mips_fulong2e.c
@@ -343,7 +343,7 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device,
 
     via_devfn = vt82c686b_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 0));
     if (via_devfn < 0) {
-        fprintf(stderr, "vt82c686b_init error \n");
+        fprintf(stderr, "vt82c686b_init error\n");
         exit(1);
     }
 
diff --git a/hw/mst_fpga.c b/hw/mst_fpga.c
index 4e47574..7bcd5d7 100644
--- a/hw/mst_fpga.c
+++ b/hw/mst_fpga.c
@@ -118,7 +118,7 @@ mst_fpga_readb(void *opaque, target_phys_addr_t addr)
 		return s->pcmcia1;
 	default:
 		printf("Mainstone - mst_fpga_readb: Bad register offset "
-			"0x" TARGET_FMT_plx " \n", addr);
+			"0x" TARGET_FMT_plx "\n", addr);
 	}
 	return 0;
 }
@@ -171,7 +171,7 @@ mst_fpga_writeb(void *opaque, target_phys_addr_t addr, uint32_t value)
 		break;
 	default:
 		printf("Mainstone - mst_fpga_writeb: Bad register offset "
-			"0x" TARGET_FMT_plx " \n", addr);
+			"0x" TARGET_FMT_plx "\n", addr);
 	}
 }
 
diff --git a/hw/vt82c686.c b/hw/vt82c686.c
index 5c973ed..b9fcc0e 100644
--- a/hw/vt82c686.c
+++ b/hw/vt82c686.c
@@ -49,7 +49,7 @@ static void superio_ioport_writeb(void *opaque, uint32_t addr, uint32_t data)
     int can_write;
     SuperIOConfig *superio_conf = opaque;
 
-    DPRINTF("superio_ioport_writeb  address 0x%x  val 0x%x  \n", addr, data);
+    DPRINTF("superio_ioport_writeb  address 0x%x  val 0x%x\n", addr, data);
     if (addr == 0x3f0) {
         superio_conf->index = data & 0xff;
     } else {
@@ -73,12 +73,12 @@ static void superio_ioport_writeb(void *opaque, uint32_t addr, uint32_t data)
                 switch (superio_conf->index) {
                 case 0xe7:
                     if ((data & 0xff) != 0xfe) {
-                        DPRINTF("chage uart 1 base. unsupported yet \n");
+                        DPRINTF("chage uart 1 base. unsupported yet\n");
                     }
                     break;
                 case 0xe8:
                     if ((data & 0xff) != 0xbe) {
-                        DPRINTF("chage uart 2 base. unsupported yet \n");
+                        DPRINTF("chage uart 2 base. unsupported yet\n");
                     }
                     break;
 
@@ -95,7 +95,7 @@ static uint32_t superio_ioport_readb(void *opaque, uint32_t addr)
 {
     SuperIOConfig *superio_conf = opaque;
 
-    DPRINTF("superio_ioport_readb  address 0x%x   \n", addr);
+    DPRINTF("superio_ioport_readb  address 0x%x\n", addr);
     return (superio_conf->config[superio_conf->index]);
 }
 
@@ -133,7 +133,7 @@ static void vt82c686b_write_config(PCIDevice * d, uint32_t address,
 {
     VT82C686BState *vt686 = DO_UPCAST(VT82C686BState, dev, d);
 
-    DPRINTF("vt82c686b_write_config  address 0x%x  val 0x%x len 0x%x \n",
+    DPRINTF("vt82c686b_write_config  address 0x%x  val 0x%x len 0x%x\n",
            address, val, len);
 
     pci_default_write_config(d, address, val, len);
@@ -285,7 +285,7 @@ static void pm_io_space_update(VT686PMState *s)
 static void pm_write_config(PCIDevice *d,
                             uint32_t address, uint32_t val, int len)
 {
-    DPRINTF("pm_write_config  address 0x%x  val 0x%x len 0x%x \n",
+    DPRINTF("pm_write_config  address 0x%x  val 0x%x len 0x%x\n",
            address, val, len);
     pci_default_write_config(d, address, val, len);
 }
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index e87e174..6b73769 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -1504,7 +1504,7 @@ static abi_long do_setsockopt(int sockfd, int level, int optname,
         break;
     default:
     unimplemented:
-        gemu_log("Unsupported setsockopt level=%d optname=%d \n", level, optname);
+        gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
         ret = -TARGET_ENOPROTOOPT;
     }
     return ret;
diff --git a/mips-dis.c b/mips-dis.c
index 4d8e85b..e3a6e0b 100644
--- a/mips-dis.c
+++ b/mips-dis.c
@@ -4841,7 +4841,7 @@ with the -M switch (multiple options should be separated by commas):\n"));
                            Default: based on binary being disassembled.\n"));
 
   fprintf (stream, _("\n\
-  hwr-names=ARCH           Print HWR names according to specified \n\
+  hwr-names=ARCH           Print HWR names according to specified\n\
 			   architecture.\n\
                            Default: based on binary being disassembled.\n"));
 
diff --git a/qemu-io.c b/qemu-io.c
index 5e46213..e91af37 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -880,7 +880,7 @@ static void multiwrite_help(void)
 " in a batch of requests that may be merged by qemu\n"
 "\n"
 " Example:\n"
-" 'multiwrite 512 1k 1k ; 4k 1k' \n"
+" 'multiwrite 512 1k 1k ; 4k 1k'\n"
 "  writes 2 kB at 512 bytes and 1 kB at 4 kB into the open file\n"
 "\n"
 " Writes into a segment of the currently open file, using a buffer\n"
diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c
index c1214c0..8bbd70c 100644
--- a/slirp/tcp_input.c
+++ b/slirp/tcp_input.c
@@ -231,7 +231,7 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso)
     Slirp *slirp;
 
 	DEBUG_CALL("tcp_input");
-	DEBUG_ARGS((dfd," m = %8lx  iphlen = %2d  inso = %lx\n",
+	DEBUG_ARGS((dfd, " m = %8lx  iphlen = %2d  inso = %lx\n",
 		    (long )m, iphlen, (long )inso ));
 
 	/*
@@ -580,7 +580,7 @@ findso:
 
 	  if((tcp_fconnect(so) == -1) && (errno != EINPROGRESS) && (errno != EWOULDBLOCK)) {
 	    u_char code=ICMP_UNREACH_NET;
-	    DEBUG_MISC((dfd," tcp fconnect errno = %d-%s\n",
+	    DEBUG_MISC((dfd, " tcp fconnect errno = %d-%s\n",
 			errno,strerror(errno)));
 	    if(errno == ECONNREFUSED) {
 	      /* ACK the SYN, send RST to refuse the connection */
@@ -910,7 +910,7 @@ trimthenstep6:
 
 		if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) {
 			if (ti->ti_len == 0 && tiwin == tp->snd_wnd) {
-			  DEBUG_MISC((dfd," dup ack  m = %lx  so = %lx \n",
+			  DEBUG_MISC((dfd, " dup ack  m = %lx  so = %lx\n",
 				      (long )m, (long )so));
 				/*
 				 * If we have outstanding data (other than
@@ -1293,7 +1293,7 @@ tcp_dooptions(struct tcpcb *tp, u_char *cp, int cnt, struct tcpiphdr *ti)
 	int opt, optlen;
 
 	DEBUG_CALL("tcp_dooptions");
-	DEBUG_ARGS((dfd," tp = %lx  cnt=%i \n", (long )tp, cnt));
+	DEBUG_ARGS((dfd, " tp = %lx  cnt=%i\n", (long)tp, cnt));
 
 	for (; cnt > 0; cnt -= optlen, cp += optlen) {
 		opt = cp[0];
diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c
index 61079b1..143a238 100644
--- a/slirp/tcp_subr.c
+++ b/slirp/tcp_subr.c
@@ -902,7 +902,7 @@ int tcp_ctl(struct socket *so)
                     return 1;
                 }
                 do_pty = ex_ptr->ex_pty;
-                DEBUG_MISC((dfd, " executing %s \n",ex_ptr->ex_exec));
+                DEBUG_MISC((dfd, " executing %s\n", ex_ptr->ex_exec));
                 return fork_exec(so, ex_ptr->ex_exec, do_pty);
             }
         }
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 5ec83f2..96ea464 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -553,7 +553,7 @@ static inline int get_bat(CPUState *env, mmu_ctx_t *ctx, target_ulong virtual,
                 BEPIl = *BATu & 0x0FFE0000;
                 bl = (*BATu & 0x00001FFC) << 15;
                 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
-                         " BATl " TARGET_FMT_lx " \n\t" TARGET_FMT_lx " "
+                         " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
                          TARGET_FMT_lx " " TARGET_FMT_lx "\n",
                          __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
                          *BATu, *BATl, BEPIu, BEPIl, bl);
diff --git a/tests/test-i386.c b/tests/test-i386.c
index 9cb5b51..8e64bba 100644
--- a/tests/test-i386.c
+++ b/tests/test-i386.c
@@ -802,7 +802,7 @@ void test_fcmp(double a, double b)
         "fstsw %%ax\n"
         : "=a" (fpus)
         : "t" (a), "u" (b));
-    printf("fcom(%f %f)=%04lx \n",
+    printf("fcom(%f %f)=%04lx\n",
            a, b, fpus & (0x4500 | FPUS_EMASK));
     fpu_clear_exceptions();
     asm("fucom %2\n"
commit 937b1258b7748fe9dc2234b6006f216856179636
Author: Lluís Vilanova <vilanova at ac.upc.edu>
Date:   Thu Sep 15 22:45:42 2011 +0200

    build: Move tracing objects into libuser on usermode emulation targets
    
    This will apply libuser-specific compilation flags (like the ones added by
    --enable-user-pie), but keep softmmu emulation targets "as-is".
    
    Signed-off-by: Lluís Vilanova <vilanova at ac.upc.edu>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/Makefile.objs b/Makefile.objs
index 62020d7..1c65087 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -177,6 +177,7 @@ user-obj-y =
 user-obj-y += envlist.o path.o
 user-obj-y += tcg-runtime.o host-utils.o
 user-obj-y += cutils.o cache-utils.o
+user-obj-y += $(trace-obj-y)
 
 ######################################################################
 # libhw
@@ -340,12 +341,12 @@ trace.h: trace.h-timestamp trace-dtrace.h
 else
 trace.h: trace.h-timestamp
 endif
-trace.h-timestamp: $(SRC_PATH)/trace-events config-host.mak
+trace.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
 	$(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -h < $< > $@,"  GEN   trace.h")
 	@cmp -s $@ trace.h || cp $@ trace.h
 
 trace.c: trace.c-timestamp
-trace.c-timestamp: $(SRC_PATH)/trace-events config-host.mak
+trace.c-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
 	$(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -c < $< > $@,"  GEN   trace.c")
 	@cmp -s $@ trace.c || cp $@ trace.c
 
@@ -358,7 +359,7 @@ trace-dtrace.h: trace-dtrace.dtrace
 # but that gets picked up by QEMU's Makefile as an external dependency
 # rule file. So we use '.dtrace' instead
 trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp
-trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events config-host.mak
+trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
 	$(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -d < $< > $@,"  GEN   trace-dtrace.dtrace")
 	@cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace
 
diff --git a/Makefile.target b/Makefile.target
index f708453..88d2f1f 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -383,6 +383,7 @@ obj-y += $(addprefix ../, $(common-obj-y))
 obj-y += $(addprefix ../libdis/, $(libdis-y))
 obj-y += $(libobj-y)
 obj-y += $(addprefix $(HWDIR)/, $(hw-obj-y))
+obj-y += $(addprefix ../, $(trace-obj-y))
 
 endif # CONFIG_SOFTMMU
 
@@ -394,7 +395,6 @@ obj-$(CONFIG_SMARTCARD_NSS) += $(addprefix ../libcacard/, $(libcacard-y))
 endif # CONFIG_BSD_USER
 endif # CONFIG_LINUX_USER
 
-obj-y += $(addprefix ../, $(trace-obj-y))
 obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o
 
 $(QEMU_PROG): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y)
diff --git a/Makefile.user b/Makefile.user
index 024b773..2b1e4d1 100644
--- a/Makefile.user
+++ b/Makefile.user
@@ -17,7 +17,9 @@ all: $(user-obj-y)
 	@true
 
 clean:
-	rm -f *.o *.d *.a *~
+	for d in . trace; do \
+	rm -f $$d/*.o $$d/*.d $$d/*.a $$d/*~; \
+	done
 
 # Include automatically generated dependency files
 -include $(wildcard *.d */*.d)
diff --git a/configure b/configure
index 0875f95..ad924c4 100755
--- a/configure
+++ b/configure
@@ -3669,6 +3669,7 @@ fi
 
 d=libuser
 mkdir -p $d
+mkdir -p $d/trace
 symlink $source_path/Makefile.user $d/Makefile
 if test "$static" = "no" -a "$user_pie" = "yes" ; then
   echo "QEMU_CFLAGS+=-fpie" > $d/config.mak
commit 388d475815c23901010a25c845eb078d47ee0740
Author: Lluís Vilanova <vilanova at ac.upc.edu>
Date:   Thu Sep 15 22:45:35 2011 +0200

    build: Always have 'BUILD_DIR' variable pointing to the root of the build tree
    
    Signed-off-by: Lluís Vilanova <vilanova at ac.upc.edu>
    Signed-off-by: Lluís Vilanova <vilanova at ac.upc.edu>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/Makefile b/Makefile
index 7e9382f..57cc399 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,8 @@
 # Makefile for QEMU.
 
+# Always point to the root of the build tree
+BUILD_DIR=$(PWD)
+
 GENERATED_HEADERS = config-host.h trace.h qemu-options.def
 ifeq ($(TRACE_BACKEND),dtrace)
 GENERATED_HEADERS += trace-dtrace.h
@@ -37,7 +40,7 @@ else
 DOCS=
 endif
 
-SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory)
+SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory) BUILD_DIR=$(BUILD_DIR)
 SUBDIR_DEVICES_MAK=$(patsubst %, %/config-devices.mak, $(TARGET_DIRS))
 SUBDIR_DEVICES_MAK_DEP=$(patsubst %, %/config-devices.mak.d, $(TARGET_DIRS))
 
commit 144d192d33f031bced40012a114a15b6041c751e
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Fri Sep 16 00:10:50 2011 +0200

    slirp: Fill TCP/IP header template after SYN reception
    
    This ensures we can cleanly signal the drop in case the connection timer
    fires. So far we sent those frames to nowhere (target IP 0.0.0.0).
    
    Found by the new assertion on invalid IPs in arp_table_search.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>

diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c
index c1214c0..5a79c68 100644
--- a/slirp/tcp_input.c
+++ b/slirp/tcp_input.c
@@ -610,6 +610,7 @@ findso:
 	    so->so_ti = ti;
 	    tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
 	    tp->t_state = TCPS_SYN_RECEIVED;
+	    tcp_template(tp);
 	  }
 	  return;
 
commit 6e0ca8820dddd04056c43327f3b3699f572d03d4
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Tue Aug 9 14:44:25 2011 -0300

    HMP: info status: Print the VM state
    
    Today our printf format for the "info status" command is:
    
      VM status: %s
    
    Where the string can be "running", "running (single step mode)" or
    "paused".
    
    This commit extends it to:
    
     VM status: %s (%s)
    
    The second string corresponds to the "status" field as returned
    by the query-status QMP command and it's only printed if "status"
    is not "running" or "paused".
    
    Example:
    
     VM status: paused (shutdown)
    
    PS: libvirt uses "info status" when using HMP, but the new format
        should not break it.
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/monitor.c b/monitor.c
index ab71d2d..8ec2c5e 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2618,6 +2618,7 @@ static int do_inject_nmi(Monitor *mon, const QDict *qdict, QObject **ret_data)
 static void do_info_status_print(Monitor *mon, const QObject *data)
 {
     QDict *qdict;
+    const char *status;
 
     qdict = qobject_to_qdict(data);
 
@@ -2631,6 +2632,11 @@ static void do_info_status_print(Monitor *mon, const QObject *data)
         monitor_printf(mon, "paused");
     }
 
+    status = qdict_get_str(qdict, "status");
+    if (strcmp(status, "paused") && strcmp(status, "running")) {
+        monitor_printf(mon, " (%s)", status);
+    }
+
     monitor_printf(mon, "\n");
 }
 
commit 9e37b9dc5bf037453e062ee515014875cd05068d
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Mon Aug 29 16:02:57 2011 -0300

    QMP: query-status: Introduce 'status' key
    
    This new key reports the current VM status to clients. Please, check
    the documentation being added in this commit for more details.
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/monitor.c b/monitor.c
index ac68edf..ab71d2d 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2636,8 +2636,7 @@ static void do_info_status_print(Monitor *mon, const QObject *data)
 
 static void do_info_status(Monitor *mon, QObject **ret_data)
 {
-    *ret_data = qobject_from_jsonf("{ 'running': %i, 'singlestep': %i }",
-                                    runstate_is_running(), singlestep);
+    *ret_data = qobject_from_jsonf("{ 'running': %i, 'singlestep': %i, 'status': %s }", runstate_is_running(), singlestep, runstate_as_string());
 }
 
 static qemu_acl *find_acl(Monitor *mon, const char *name)
diff --git a/qmp-commands.hx b/qmp-commands.hx
index d1c2c59..d83bce5 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1573,11 +1573,28 @@ Return a json-object with the following information:
 - "running": true if the VM is running, or false if it is paused (json-bool)
 - "singlestep": true if the VM is in single step mode,
                 false otherwise (json-bool)
+- "status": one of the following values (json-string)
+    "debug" - QEMU is running on a debugger
+    "inmigrate" - guest is paused waiting for an incoming migration
+    "internal-error" - An internal error that prevents further guest
+    execution has occurred
+    "io-error" - the last IOP has failed and the device is configured
+    to pause on I/O errors
+    "paused" - guest has been paused via the 'stop' command
+    "postmigrate" - guest is paused following a successful 'migrate'
+    "prelaunch" - QEMU was started with -S and guest has not started
+    "finish-migrate" - guest is paused to finish the migration process
+    "restore-vm" - guest is paused to restore VM state
+    "running" - guest is actively running
+    "save-vm" - guest is paused to save the VM state
+    "shutdown" - guest is shut down (and -no-shutdown is in use)
+    "watchdog" - the watchdog action is configured to pause and
+     has been triggered
 
 Example:
 
 -> { "execute": "query-status" }
-<- { "return": { "running": true, "singlestep": false } }
+<- { "return": { "running": true, "singlestep": false, "status": "running" } }
 
 EQMP
 
diff --git a/sysemu.h b/sysemu.h
index 9a2c531..43ff546 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -39,6 +39,7 @@ void runstate_init(void);
 bool runstate_check(RunState state);
 void runstate_set(RunState new_state);
 int runstate_is_running(void);
+const char *runstate_as_string(void);
 typedef struct vm_change_state_entry VMChangeStateEntry;
 typedef void VMChangeStateHandler(void *opaque, int running, RunState state);
 
diff --git a/vl.c b/vl.c
index 686e491..08591c3 100644
--- a/vl.c
+++ b/vl.c
@@ -378,6 +378,22 @@ static const RunStateTransition runstate_transitions_def[] = {
 
 static bool runstate_valid_transitions[RSTATE_MAX][RSTATE_MAX];
 
+static const char *const runstate_name_tbl[RSTATE_MAX] = {
+    [RSTATE_DEBUG] = "debug",
+    [RSTATE_IN_MIGRATE] = "incoming-migration",
+    [RSTATE_PANICKED] = "internal-error",
+    [RSTATE_IO_ERROR] = "io-error",
+    [RSTATE_PAUSED] = "paused",
+    [RSTATE_POST_MIGRATE] = "post-migrate",
+    [RSTATE_PRE_LAUNCH] = "prelaunch",
+    [RSTATE_PRE_MIGRATE] = "finish-migrate",
+    [RSTATE_RESTORE] = "restore-vm",
+    [RSTATE_RUNNING] = "running",
+    [RSTATE_SAVEVM] = "save-vm",
+    [RSTATE_SHUTDOWN] = "shutdown",
+    [RSTATE_WATCHDOG] = "watchdog",
+};
+
 bool runstate_check(RunState state)
 {
     return current_run_state == state;
@@ -406,6 +422,13 @@ void runstate_set(RunState new_state)
     current_run_state = new_state;
 }
 
+const char *runstate_as_string(void)
+{
+    assert(current_run_state > RSTATE_NO_STATE &&
+           current_run_state < RSTATE_MAX);
+    return runstate_name_tbl[current_run_state];
+}
+
 int runstate_is_running(void)
 {
     return runstate_check(RSTATE_RUNNING);
commit 6667b23f300ff08a47a73821ce2fb7f773754969
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Fri Jul 29 15:57:54 2011 -0300

    Monitor/QMP: Don't allow cont on bad VM state
    
    We have two states where issuing cont before system_reset can
    cause problems: RSTATE_SHUTDOWN (when -no-shutdown is used) and
    RSTATE_PANICKED (which only happens with kvm).
    
    This commit fixes that by doing the following when state is
    RSTATE_SHUTDOWN or RSTATE_PANICKED:
    
     1. returning an error to the user/client if cont is issued
     2. automatically transition to RSTATE_PAUSED during system_reset
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/monitor.c b/monitor.c
index 442b4cf..ac68edf 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1314,7 +1314,12 @@ static int do_cont(Monitor *mon, const QDict *qdict, QObject **ret_data)
     if (runstate_check(RSTATE_IN_MIGRATE)) {
         qerror_report(QERR_MIGRATION_EXPECTED);
         return -1;
+    } else if (runstate_check(RSTATE_PANICKED) ||
+               runstate_check(RSTATE_SHUTDOWN)) {
+        qerror_report(QERR_RESET_REQUIRED);
+        return -1;
     }
+
     bdrv_iterate(encrypted_bdrv_it, &context);
     /* only resume the vm if all keys are set and valid */
     if (!context.err) {
diff --git a/qerror.c b/qerror.c
index 3d64b80..c591a54 100644
--- a/qerror.c
+++ b/qerror.c
@@ -194,6 +194,10 @@ static const QErrorStringTable qerror_table[] = {
         .desc      = "QMP input object member '%(member)' is unexpected",
     },
     {
+        .error_fmt = QERR_RESET_REQUIRED,
+        .desc      = "Resetting the Virtual Machine is required",
+    },
+    {
         .error_fmt = QERR_SET_PASSWD_FAILED,
         .desc      = "Could not set password",
     },
diff --git a/qerror.h b/qerror.h
index 8058456..d407001 100644
--- a/qerror.h
+++ b/qerror.h
@@ -163,6 +163,9 @@ QError *qobject_to_qerror(const QObject *obj);
 #define QERR_QMP_EXTRA_MEMBER \
     "{ 'class': 'QMPExtraInputObjectMember', 'data': { 'member': %s } }"
 
+#define QERR_RESET_REQUIRED \
+    "{ 'class': 'ResetRequired', 'data': {} }"
+
 #define QERR_SET_PASSWD_FAILED \
     "{ 'class': 'SetPasswdFailed', 'data': {} }"
 
diff --git a/vl.c b/vl.c
index 9128d48..686e491 100644
--- a/vl.c
+++ b/vl.c
@@ -1573,6 +1573,10 @@ static void main_loop(void)
             cpu_synchronize_all_states();
             qemu_system_reset(VMRESET_REPORT);
             resume_all_vcpus();
+            if (runstate_check(RSTATE_PANICKED) ||
+                runstate_check(RSTATE_SHUTDOWN)) {
+                runstate_set(RSTATE_PAUSED);
+            }
         }
         if (qemu_powerdown_requested()) {
             monitor_protocol_event(QEVENT_POWERDOWN, NULL);
commit 1354869c380cf4560fa3f0520e914cb5ee380ac8
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Fri Jul 29 15:36:43 2011 -0300

    Drop the vm_running global variable
    
    Use runstate_is_running() instead, which is introduced by this commit.
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/cpus.c b/cpus.c
index 3444bc0..883c27a 100644
--- a/cpus.c
+++ b/cpus.c
@@ -115,14 +115,13 @@ void cpu_synchronize_all_post_init(void)
 
 int cpu_is_stopped(CPUState *env)
 {
-    return !vm_running || env->stopped;
+    return !runstate_is_running() || env->stopped;
 }
 
 static void do_vm_stop(RunState state)
 {
-    if (vm_running) {
+    if (runstate_is_running()) {
         cpu_disable_ticks();
-        vm_running = 0;
         pause_all_vcpus();
         runstate_set(state);
         vm_state_notify(0, state);
@@ -137,7 +136,7 @@ static int cpu_can_run(CPUState *env)
     if (env->stop) {
         return 0;
     }
-    if (env->stopped || !vm_running) {
+    if (env->stopped || !runstate_is_running()) {
         return 0;
     }
     return 1;
@@ -148,7 +147,7 @@ static bool cpu_thread_is_idle(CPUState *env)
     if (env->stop || env->queued_work_first) {
         return false;
     }
-    if (env->stopped || !vm_running) {
+    if (env->stopped || !runstate_is_running()) {
         return true;
     }
     if (!env->halted || qemu_cpu_has_work(env) ||
diff --git a/gdbstub.c b/gdbstub.c
index 75b52e2..12dd100 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -2534,7 +2534,7 @@ static void gdb_read_byte(GDBState *s, int ch)
         if (ch != '$')
             return;
     }
-    if (vm_running) {
+    if (runstate_is_running()) {
         /* when the CPU is running, we cannot do anything except stop
            it when receiving a char */
         vm_stop(RSTATE_PAUSED);
@@ -2839,7 +2839,7 @@ static int gdb_monitor_write(CharDriverState *chr, const uint8_t *buf, int len)
 #ifndef _WIN32
 static void gdb_sigterm_handler(int signal)
 {
-    if (vm_running) {
+    if (runstate_is_running()) {
         vm_stop(RSTATE_PAUSED);
     }
 }
diff --git a/hw/etraxfs_dma.c b/hw/etraxfs_dma.c
index e8ad9e6..d3082ac 100644
--- a/hw/etraxfs_dma.c
+++ b/hw/etraxfs_dma.c
@@ -732,7 +732,7 @@ static void DMA_run(void *opaque)
     struct fs_dma_ctrl *etraxfs_dmac = opaque;
     int p = 1;
 
-    if (vm_running)
+    if (runstate_is_running())
         p = etraxfs_dmac_run(etraxfs_dmac);
 
     if (p)
diff --git a/hw/kvmclock.c b/hw/kvmclock.c
index 88961be..5388bc4 100644
--- a/hw/kvmclock.c
+++ b/hw/kvmclock.c
@@ -46,7 +46,7 @@ static void kvmclock_pre_save(void *opaque)
      * it on next vmsave (which would return a different value). Will be reset
      * when the VM is continued.
      */
-    s->clock_valid = !vm_running;
+    s->clock_valid = !runstate_is_running();
 }
 
 static int kvmclock_post_load(void *opaque, int version_id)
diff --git a/hw/virtio.c b/hw/virtio.c
index 74ab79e..c577bbe 100644
--- a/hw/virtio.c
+++ b/hw/virtio.c
@@ -870,7 +870,7 @@ VirtIODevice *virtio_common_init(const char *name, uint16_t device_id,
     vdev->queue_sel = 0;
     vdev->config_vector = VIRTIO_NO_VECTOR;
     vdev->vq = g_malloc0(sizeof(VirtQueue) * VIRTIO_PCI_QUEUE_MAX);
-    vdev->vm_running = vm_running;
+    vdev->vm_running = runstate_is_running();
     for(i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
         vdev->vq[i].vector = VIRTIO_NO_VECTOR;
         vdev->vq[i].vdev = vdev;
diff --git a/migration.c b/migration.c
index a63e2a2..7dd8f4e 100644
--- a/migration.c
+++ b/migration.c
@@ -372,7 +372,7 @@ void migrate_fd_put_ready(void *opaque)
     DPRINTF("iterate\n");
     if (qemu_savevm_state_iterate(s->mon, s->file) == 1) {
         int state;
-        int old_vm_running = vm_running;
+        int old_vm_running = runstate_is_running();
 
         DPRINTF("done iterating\n");
         vm_stop(RSTATE_PRE_MIGRATE);
diff --git a/monitor.c b/monitor.c
index 68956a5..442b4cf 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2632,7 +2632,7 @@ static void do_info_status_print(Monitor *mon, const QObject *data)
 static void do_info_status(Monitor *mon, QObject **ret_data)
 {
     *ret_data = qobject_from_jsonf("{ 'running': %i, 'singlestep': %i }",
-                                    vm_running, singlestep);
+                                    runstate_is_running(), singlestep);
 }
 
 static qemu_acl *find_acl(Monitor *mon, const char *name)
@@ -2825,7 +2825,7 @@ static int do_closefd(Monitor *mon, const QDict *qdict, QObject **ret_data)
 
 static void do_loadvm(Monitor *mon, const QDict *qdict)
 {
-    int saved_vm_running  = vm_running;
+    int saved_vm_running  = runstate_is_running();
     const char *name = qdict_get_str(qdict, "name");
 
     vm_stop(RSTATE_RESTORE);
diff --git a/qemu-timer.c b/qemu-timer.c
index b582786..ad1fc8b 100644
--- a/qemu-timer.c
+++ b/qemu-timer.c
@@ -230,7 +230,7 @@ static void icount_adjust(void)
     int64_t delta;
     static int64_t last_delta;
     /* If the VM is not running, then do nothing.  */
-    if (!vm_running)
+    if (!runstate_is_running())
         return;
 
     cur_time = cpu_get_clock();
@@ -388,7 +388,7 @@ static void icount_warp_rt(void *opaque)
         return;
     }
 
-    if (vm_running) {
+    if (runstate_is_running()) {
         int64_t clock = qemu_get_clock_ns(rt_clock);
         int64_t warp_delta = clock - vm_clock_warp_start;
         if (use_icount == 1) {
@@ -710,7 +710,7 @@ void qemu_run_all_timers(void)
     }
 
     /* vm time timers */
-    if (vm_running) {
+    if (runstate_is_running()) {
         qemu_run_timers(vm_clock);
     }
 
diff --git a/savevm.c b/savevm.c
index f1f7735..46f2447 100644
--- a/savevm.c
+++ b/savevm.c
@@ -1602,7 +1602,7 @@ static int qemu_savevm_state(Monitor *mon, QEMUFile *f)
     int saved_vm_running;
     int ret;
 
-    saved_vm_running = vm_running;
+    saved_vm_running = runstate_is_running();
     vm_stop(RSTATE_SAVEVM);
 
     if (qemu_savevm_state_blocked(mon)) {
@@ -1931,7 +1931,7 @@ void do_savevm(Monitor *mon, const QDict *qdict)
         return;
     }
 
-    saved_vm_running = vm_running;
+    saved_vm_running = runstate_is_running();
     vm_stop(RSTATE_SAVEVM);
 
     memset(sn, 0, sizeof(*sn));
diff --git a/sysemu.h b/sysemu.h
index a01ddac..9a2c531 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -30,7 +30,6 @@ typedef enum {
 
 extern const char *bios_name;
 
-extern int vm_running;
 extern const char *qemu_name;
 extern uint8_t qemu_uuid[];
 int qemu_uuid_parse(const char *str, uint8_t *uuid);
@@ -39,6 +38,7 @@ int qemu_uuid_parse(const char *str, uint8_t *uuid);
 void runstate_init(void);
 bool runstate_check(RunState state);
 void runstate_set(RunState new_state);
+int runstate_is_running(void);
 typedef struct vm_change_state_entry VMChangeStateEntry;
 typedef void VMChangeStateHandler(void *opaque, int running, RunState state);
 
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index ead34ea..b6eef04 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -1130,7 +1130,7 @@ static int kvm_get_msrs(CPUState *env)
 
     if (!env->tsc_valid) {
         msrs[n++].index = MSR_IA32_TSC;
-        env->tsc_valid = !vm_running;
+        env->tsc_valid = !runstate_is_running();
     }
 
 #ifdef TARGET_X86_64
diff --git a/ui/sdl.c b/ui/sdl.c
index c7aaedf..8cafc44 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -409,7 +409,7 @@ static void sdl_update_caption(void)
     char icon_title[1024];
     const char *status = "";
 
-    if (!vm_running)
+    if (!runstate_is_running())
         status = " [Stopped]";
     else if (gui_grab) {
         if (alt_grab)
@@ -853,8 +853,8 @@ static void sdl_refresh(DisplayState *ds)
 {
     SDL_Event ev1, *ev = &ev1;
 
-    if (last_vm_running != vm_running) {
-        last_vm_running = vm_running;
+    if (last_vm_running != runstate_is_running()) {
+        last_vm_running = runstate_is_running();
         sdl_update_caption();
     }
 
diff --git a/vl.c b/vl.c
index 2fb09f5..9128d48 100644
--- a/vl.c
+++ b/vl.c
@@ -185,7 +185,6 @@ int mem_prealloc = 0; /* force preallocation of physical target memory */
 #endif
 int nb_nics;
 NICInfo nd_table[MAX_NICS];
-int vm_running;
 int autostart;
 static int rtc_utc = 1;
 static int rtc_date_offset = -1; /* -1 means no change */
@@ -407,6 +406,11 @@ void runstate_set(RunState new_state)
     current_run_state = new_state;
 }
 
+int runstate_is_running(void)
+{
+    return runstate_check(RSTATE_RUNNING);
+}
+
 /***********************************************************/
 /* real time host monotonic timer */
 
@@ -1243,9 +1247,8 @@ void vm_state_notify(int running, RunState state)
 
 void vm_start(void)
 {
-    if (!vm_running) {
+    if (!runstate_is_running()) {
         cpu_enable_ticks();
-        vm_running = 1;
         runstate_set(RSTATE_RUNNING);
         vm_state_notify(1, RSTATE_RUNNING);
         resume_all_vcpus();
diff --git a/xen-all.c b/xen-all.c
index b119817..b5e28ab 100644
--- a/xen-all.c
+++ b/xen-all.c
@@ -736,7 +736,7 @@ static void cpu_handle_ioreq(void *opaque)
          * guest resumes and does a hlt with interrupts disabled which
          * causes Xen to powerdown the domain.
          */
-        if (vm_running) {
+        if (runstate_is_running()) {
             if (qemu_shutdown_requested_get()) {
                 destroy_hvm_domain();
             }
commit 1bcef683bf840a928d633755031ac572d5fdb851
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Fri Jul 29 15:15:00 2011 -0300

    Drop the incoming_expected global variable
    
    Test against RSTATE_IN_MIGRATE instead.
    
    Please, note that the RSTATE_IN_MIGRATE state is only set when all the
    initial VM setup is done, while 'incoming_expected' was set right in
    the beginning when parsing command-line options. Shouldn't be a problem
    as far as I could check.
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/migration.c b/migration.c
index f2499cf..a63e2a2 100644
--- a/migration.c
+++ b/migration.c
@@ -70,8 +70,6 @@ void process_incoming_migration(QEMUFile *f)
     qemu_announce_self();
     DPRINTF("successfully loaded vm state\n");
 
-    incoming_expected = false;
-
     if (autostart) {
         vm_start();
     } else {
diff --git a/monitor.c b/monitor.c
index b98b8bd..68956a5 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1311,7 +1311,7 @@ static int do_cont(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     struct bdrv_iterate_context context = { mon, 0 };
 
-    if (incoming_expected) {
+    if (runstate_check(RSTATE_IN_MIGRATE)) {
         qerror_report(QERR_MIGRATION_EXPECTED);
         return -1;
     }
diff --git a/vl.c b/vl.c
index cc68fb3..2fb09f5 100644
--- a/vl.c
+++ b/vl.c
@@ -187,7 +187,6 @@ int nb_nics;
 NICInfo nd_table[MAX_NICS];
 int vm_running;
 int autostart;
-int incoming_expected; /* Started with -incoming and waiting for incoming */
 static int rtc_utc = 1;
 static int rtc_date_offset = -1; /* -1 means no change */
 QEMUClock *rtc_clock;
@@ -3041,7 +3040,6 @@ int main(int argc, char **argv, char **envp)
                 break;
             case QEMU_OPTION_incoming:
                 incoming = optarg;
-                incoming_expected = true;
                 break;
             case QEMU_OPTION_nodefaults:
                 default_serial = 0;
commit 5db9d4d18612bd5852bf663a40cf7bcf1ddc1b03
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Mon Sep 5 16:36:31 2011 -0300

    runstate_set(): Check for valid transitions
    
    This commit could have been folded with the previous one, however
    doing it separately will allow for easy bisect and revert if needed.
    
    Checking and testing all valid transitions wasn't trivial, chances
    are this will need broader testing to become more stable.
    
    This is a transition table as suggested by Lluís Vilanova.
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/sysemu.h b/sysemu.h
index 19088aa..a01ddac 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -36,6 +36,7 @@ extern uint8_t qemu_uuid[];
 int qemu_uuid_parse(const char *str, uint8_t *uuid);
 #define UUID_FMT "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
 
+void runstate_init(void);
 bool runstate_check(RunState state);
 void runstate_set(RunState new_state);
 typedef struct vm_change_state_entry VMChangeStateEntry;
diff --git a/vl.c b/vl.c
index 059e727..cc68fb3 100644
--- a/vl.c
+++ b/vl.c
@@ -327,14 +327,84 @@ static int default_driver_check(QemuOpts *opts, void *opaque)
 
 static RunState current_run_state = RSTATE_NO_STATE;
 
+typedef struct {
+    RunState from;
+    RunState to;
+} RunStateTransition;
+
+static const RunStateTransition runstate_transitions_def[] = {
+    /*     from      ->     to      */
+    { RSTATE_NO_STATE, RSTATE_RUNNING },
+    { RSTATE_NO_STATE, RSTATE_IN_MIGRATE },
+    { RSTATE_NO_STATE, RSTATE_PRE_LAUNCH },
+
+    { RSTATE_DEBUG, RSTATE_RUNNING },
+
+    { RSTATE_IN_MIGRATE, RSTATE_RUNNING },
+    { RSTATE_IN_MIGRATE, RSTATE_PRE_LAUNCH },
+
+    { RSTATE_PANICKED, RSTATE_PAUSED },
+
+    { RSTATE_IO_ERROR, RSTATE_RUNNING },
+
+    { RSTATE_PAUSED, RSTATE_RUNNING },
+
+    { RSTATE_POST_MIGRATE, RSTATE_RUNNING },
+
+    { RSTATE_PRE_LAUNCH, RSTATE_RUNNING },
+    { RSTATE_PRE_LAUNCH, RSTATE_POST_MIGRATE },
+
+    { RSTATE_PRE_MIGRATE, RSTATE_RUNNING },
+    { RSTATE_PRE_MIGRATE, RSTATE_POST_MIGRATE },
+
+    { RSTATE_RESTORE, RSTATE_RUNNING },
+
+    { RSTATE_RUNNING, RSTATE_DEBUG },
+    { RSTATE_RUNNING, RSTATE_PANICKED },
+    { RSTATE_RUNNING, RSTATE_IO_ERROR },
+    { RSTATE_RUNNING, RSTATE_PAUSED },
+    { RSTATE_RUNNING, RSTATE_PRE_MIGRATE },
+    { RSTATE_RUNNING, RSTATE_RESTORE },
+    { RSTATE_RUNNING, RSTATE_SAVEVM },
+    { RSTATE_RUNNING, RSTATE_SHUTDOWN },
+    { RSTATE_RUNNING, RSTATE_WATCHDOG },
+
+    { RSTATE_SAVEVM, RSTATE_RUNNING },
+
+    { RSTATE_SHUTDOWN, RSTATE_PAUSED },
+
+    { RSTATE_WATCHDOG, RSTATE_RUNNING },
+
+    { RSTATE_MAX, RSTATE_MAX },
+};
+
+static bool runstate_valid_transitions[RSTATE_MAX][RSTATE_MAX];
+
 bool runstate_check(RunState state)
 {
     return current_run_state == state;
 }
 
+void runstate_init(void)
+{
+    const RunStateTransition *p;
+
+    memset(&runstate_valid_transitions, 0, sizeof(runstate_valid_transitions));
+
+    for (p = &runstate_transitions_def[0]; p->from != RSTATE_MAX; p++) {
+        runstate_valid_transitions[p->from][p->to] = true;
+    }
+}
+
+/* This function will abort() on invalid state transitions */
 void runstate_set(RunState new_state)
 {
-    assert(new_state < RSTATE_MAX);
+    if (new_state >= RSTATE_MAX ||
+        !runstate_valid_transitions[current_run_state][new_state]) {
+        fprintf(stderr, "invalid runstate transition\n");
+        abort();
+    }
+
     current_run_state = new_state;
 }
 
@@ -2219,6 +2289,8 @@ int main(int argc, char **argv, char **envp)
     g_mem_set_vtable(&mem_trace);
     g_thread_init(NULL);
 
+    runstate_init();
+
     init_clocks();
 
     qemu_cache_utils_init(envp);
commit f5bbfba1ebe8c877ebfe846fc1e73e90da423884
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Fri Jul 29 15:04:45 2011 -0300

    RunState: Add additional states
    
    Currently, only vm_start() and vm_stop() change the VM state.
    That's, the state is only changed when starting or stopping the VM.
    
    This commit adds the runstate_set() function, which makes it possible
    to also do state transitions when the VM is stopped or running.
    
    Additional states are also added and the current state is stored.
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/cpus.c b/cpus.c
index 76a79ac..3444bc0 100644
--- a/cpus.c
+++ b/cpus.c
@@ -124,6 +124,7 @@ static void do_vm_stop(RunState state)
         cpu_disable_ticks();
         vm_running = 0;
         pause_all_vcpus();
+        runstate_set(state);
         vm_state_notify(0, state);
         qemu_aio_flush();
         bdrv_flush_all();
diff --git a/migration.c b/migration.c
index 29f1a76..f2499cf 100644
--- a/migration.c
+++ b/migration.c
@@ -72,8 +72,11 @@ void process_incoming_migration(QEMUFile *f)
 
     incoming_expected = false;
 
-    if (autostart)
+    if (autostart) {
         vm_start();
+    } else {
+        runstate_set(RSTATE_PRE_LAUNCH);
+    }
 }
 
 int do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
@@ -390,6 +393,9 @@ void migrate_fd_put_ready(void *opaque)
             }
             state = MIG_STATE_ERROR;
         }
+        if (state == MIG_STATE_COMPLETED) {
+            runstate_set(RSTATE_POST_MIGRATE);
+        }
         s->state = state;
         notifier_list_notify(&migration_state_notifiers, NULL);
     }
diff --git a/sysemu.h b/sysemu.h
index be3448b..19088aa 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -13,15 +13,19 @@
 typedef enum {
     RSTATE_NO_STATE,
     RSTATE_DEBUG,          /* qemu is running under gdb */
+    RSTATE_IN_MIGRATE,     /* paused waiting for an incoming migration */
     RSTATE_PANICKED,       /* paused due to an internal error */
     RSTATE_IO_ERROR,       /* paused due to an I/O error */
     RSTATE_PAUSED,         /* paused by the user (ie. the 'stop' command) */
+    RSTATE_POST_MIGRATE,   /* paused following a successful migration */
+    RSTATE_PRE_LAUNCH,     /* qemu was started with -S and haven't started */
     RSTATE_PRE_MIGRATE,    /* paused preparing to finish migrate */
     RSTATE_RESTORE,        /* paused restoring the VM state */
     RSTATE_RUNNING,        /* qemu is running */
     RSTATE_SAVEVM,         /* paused saving VM state */
     RSTATE_SHUTDOWN,       /* guest shut down and -no-shutdown is in use */
-    RSTATE_WATCHDOG        /* watchdog fired and qemu is configured to pause */
+    RSTATE_WATCHDOG,       /* watchdog fired and qemu is configured to pause */
+    RSTATE_MAX
 } RunState;
 
 extern const char *bios_name;
@@ -32,6 +36,8 @@ extern uint8_t qemu_uuid[];
 int qemu_uuid_parse(const char *str, uint8_t *uuid);
 #define UUID_FMT "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
 
+bool runstate_check(RunState state);
+void runstate_set(RunState new_state);
 typedef struct vm_change_state_entry VMChangeStateEntry;
 typedef void VMChangeStateHandler(void *opaque, int running, RunState state);
 
diff --git a/vl.c b/vl.c
index 304a499..059e727 100644
--- a/vl.c
+++ b/vl.c
@@ -323,6 +323,22 @@ static int default_driver_check(QemuOpts *opts, void *opaque)
 }
 
 /***********************************************************/
+/* QEMU state */
+
+static RunState current_run_state = RSTATE_NO_STATE;
+
+bool runstate_check(RunState state)
+{
+    return current_run_state == state;
+}
+
+void runstate_set(RunState new_state)
+{
+    assert(new_state < RSTATE_MAX);
+    current_run_state = new_state;
+}
+
+/***********************************************************/
 /* real time host monotonic timer */
 
 /***********************************************************/
@@ -1161,6 +1177,7 @@ void vm_start(void)
     if (!vm_running) {
         cpu_enable_ticks();
         vm_running = 1;
+        runstate_set(RSTATE_RUNNING);
         vm_state_notify(1, RSTATE_RUNNING);
         resume_all_vcpus();
         monitor_protocol_event(QEVENT_RESUME, NULL);
@@ -3438,6 +3455,7 @@ int main(int argc, char **argv, char **envp)
     }
 
     if (incoming) {
+        runstate_set(RSTATE_IN_MIGRATE);
         int ret = qemu_start_incoming_migration(incoming);
         if (ret < 0) {
             fprintf(stderr, "Migration failed. Exit code %s(%d), exiting.\n",
@@ -3446,6 +3464,8 @@ int main(int argc, char **argv, char **envp)
         }
     } else if (autostart) {
         vm_start();
+    } else {
+        runstate_set(RSTATE_PRE_LAUNCH);
     }
 
     os_setup_post();
commit 1dfb4dd993f7122353fb2894f09dfcba894cd7d5
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Fri Jul 29 14:26:33 2011 -0300

    Replace the VMSTOP macros with a proper state type
    
    Today, when notifying a VM state change with vm_state_notify(),
    we pass a VMSTOP macro as the 'reason' argument. This is not ideal
    because the VMSTOP macros tell why qemu stopped and not exactly
    what the current VM state is.
    
    One example to demonstrate this problem is that vm_start() calls
    vm_state_notify() with reason=0, which turns out to be VMSTOP_USER.
    
    This commit fixes that by replacing the VMSTOP macros with a proper
    state type called RunState.
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/audio/audio.c b/audio/audio.c
index 5649075..50d0d71 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -1743,7 +1743,7 @@ static int audio_driver_init (AudioState *s, struct audio_driver *drv)
 }
 
 static void audio_vm_change_state_handler (void *opaque, int running,
-                                           int reason)
+                                           RunState state)
 {
     AudioState *s = opaque;
     HWVoiceOut *hwo = NULL;
diff --git a/cpus.c b/cpus.c
index 54c188c..76a79ac 100644
--- a/cpus.c
+++ b/cpus.c
@@ -118,13 +118,13 @@ int cpu_is_stopped(CPUState *env)
     return !vm_running || env->stopped;
 }
 
-static void do_vm_stop(int reason)
+static void do_vm_stop(RunState state)
 {
     if (vm_running) {
         cpu_disable_ticks();
         vm_running = 0;
         pause_all_vcpus();
-        vm_state_notify(0, reason);
+        vm_state_notify(0, state);
         qemu_aio_flush();
         bdrv_flush_all();
         monitor_protocol_event(QEVENT_STOP, NULL);
@@ -878,10 +878,10 @@ void cpu_stop_current(void)
     }
 }
 
-void vm_stop(int reason)
+void vm_stop(RunState state)
 {
     if (!qemu_thread_is_self(&io_thread)) {
-        qemu_system_vmstop_request(reason);
+        qemu_system_vmstop_request(state);
         /*
          * FIXME: should not return to device code in case
          * vm_stop() has been requested.
@@ -889,7 +889,7 @@ void vm_stop(int reason)
         cpu_stop_current();
         return;
     }
-    do_vm_stop(reason);
+    do_vm_stop(state);
 }
 
 static int tcg_cpu_exec(CPUState *env)
diff --git a/gdbstub.c b/gdbstub.c
index 90683a4..75b52e2 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -2373,7 +2373,7 @@ void gdb_set_stop_cpu(CPUState *env)
 }
 
 #ifndef CONFIG_USER_ONLY
-static void gdb_vm_state_change(void *opaque, int running, int reason)
+static void gdb_vm_state_change(void *opaque, int running, RunState state)
 {
     GDBState *s = gdbserver_state;
     CPUState *env = s->c_cpu;
@@ -2384,8 +2384,8 @@ static void gdb_vm_state_change(void *opaque, int running, int reason)
     if (running || s->state == RS_INACTIVE || s->state == RS_SYSCALL) {
         return;
     }
-    switch (reason) {
-    case VMSTOP_DEBUG:
+    switch (state) {
+    case RSTATE_DEBUG:
         if (env->watchpoint_hit) {
             switch (env->watchpoint_hit->flags & BP_MEM_ACCESS) {
             case BP_MEM_READ:
@@ -2408,25 +2408,25 @@ static void gdb_vm_state_change(void *opaque, int running, int reason)
         tb_flush(env);
         ret = GDB_SIGNAL_TRAP;
         break;
-    case VMSTOP_USER:
+    case RSTATE_PAUSED:
         ret = GDB_SIGNAL_INT;
         break;
-    case VMSTOP_SHUTDOWN:
+    case RSTATE_SHUTDOWN:
         ret = GDB_SIGNAL_QUIT;
         break;
-    case VMSTOP_DISKFULL:
+    case RSTATE_IO_ERROR:
         ret = GDB_SIGNAL_IO;
         break;
-    case VMSTOP_WATCHDOG:
+    case RSTATE_WATCHDOG:
         ret = GDB_SIGNAL_ALRM;
         break;
-    case VMSTOP_PANIC:
+    case RSTATE_PANICKED:
         ret = GDB_SIGNAL_ABRT;
         break;
-    case VMSTOP_SAVEVM:
-    case VMSTOP_LOADVM:
+    case RSTATE_SAVEVM:
+    case RSTATE_RESTORE:
         return;
-    case VMSTOP_MIGRATE:
+    case RSTATE_PRE_MIGRATE:
         ret = GDB_SIGNAL_XCPU;
         break;
     default:
@@ -2463,7 +2463,7 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...)
     gdb_current_syscall_cb = cb;
     s->state = RS_SYSCALL;
 #ifndef CONFIG_USER_ONLY
-    vm_stop(VMSTOP_DEBUG);
+    vm_stop(RSTATE_DEBUG);
 #endif
     s->state = RS_IDLE;
     va_start(va, fmt);
@@ -2537,7 +2537,7 @@ static void gdb_read_byte(GDBState *s, int ch)
     if (vm_running) {
         /* when the CPU is running, we cannot do anything except stop
            it when receiving a char */
-        vm_stop(VMSTOP_USER);
+        vm_stop(RSTATE_PAUSED);
     } else
 #endif
     {
@@ -2799,7 +2799,7 @@ static void gdb_chr_event(void *opaque, int event)
 {
     switch (event) {
     case CHR_EVENT_OPENED:
-        vm_stop(VMSTOP_USER);
+        vm_stop(RSTATE_PAUSED);
         gdb_has_xml = 0;
         break;
     default:
@@ -2840,7 +2840,7 @@ static int gdb_monitor_write(CharDriverState *chr, const uint8_t *buf, int len)
 static void gdb_sigterm_handler(int signal)
 {
     if (vm_running) {
-        vm_stop(VMSTOP_USER);
+        vm_stop(RSTATE_PAUSED);
     }
 }
 #endif
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index a8659cf..b813236 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -1103,7 +1103,7 @@ static void ahci_irq_set(void *opaque, int n, int level)
 {
 }
 
-static void ahci_dma_restart_cb(void *opaque, int running, int reason)
+static void ahci_dma_restart_cb(void *opaque, int running, RunState state)
 {
 }
 
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 9297b9e..4d5a076 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -527,7 +527,7 @@ static int ide_handle_rw_error(IDEState *s, int error, int op)
         s->bus->dma->ops->set_unit(s->bus->dma, s->unit);
         s->bus->error_status = op;
         bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read);
-        vm_stop(VMSTOP_DISKFULL);
+        vm_stop(RSTATE_IO_ERROR);
     } else {
         if (op & BM_STATUS_DMA_RETRY) {
             dma_buf_commit(s, 0);
@@ -1910,7 +1910,7 @@ static int ide_nop_int(IDEDMA *dma, int x)
     return 0;
 }
 
-static void ide_nop_restart(void *opaque, int x, int y)
+static void ide_nop_restart(void *opaque, int x, RunState y)
 {
 }
 
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index 233915c..9046e96 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -9,6 +9,7 @@
 #include <hw/ide.h>
 #include "iorange.h"
 #include "dma.h"
+#include "sysemu.h"
 
 /* debug IDE devices */
 //#define DEBUG_IDE
@@ -387,7 +388,7 @@ 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);
+typedef void DMARestartFunc(void *, int, RunState);
 
 struct unreported_events {
     bool eject_request;
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index 9fded02..f133c42 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -222,7 +222,7 @@ static void bmdma_restart_bh(void *opaque)
     }
 }
 
-static void bmdma_restart_cb(void *opaque, int running, int reason)
+static void bmdma_restart_cb(void *opaque, int running, RunState state)
 {
     IDEDMA *dma = opaque;
     BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
diff --git a/hw/kvmclock.c b/hw/kvmclock.c
index b73aec4..88961be 100644
--- a/hw/kvmclock.c
+++ b/hw/kvmclock.c
@@ -59,7 +59,8 @@ static int kvmclock_post_load(void *opaque, int version_id)
     return kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &data);
 }
 
-static void kvmclock_vm_state_change(void *opaque, int running, int reason)
+static void kvmclock_vm_state_change(void *opaque, int running,
+                                     RunState state)
 {
     KVMClockState *s = opaque;
 
diff --git a/hw/qxl.c b/hw/qxl.c
index a282d23..6db2f1a 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -1453,10 +1453,11 @@ static void qxl_hw_text_update(void *opaque, console_ch_t *chardata)
     }
 }
 
-static void qxl_vm_change_state_handler(void *opaque, int running, int reason)
+static void qxl_vm_change_state_handler(void *opaque, int running,
+                                        RunState state)
 {
     PCIQXLDevice *qxl = opaque;
-    qemu_spice_vm_change_state_handler(&qxl->ssd, running, reason);
+    qemu_spice_vm_change_state_handler(&qxl->ssd, running, state);
 
     if (running) {
         /*
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 4a60820..96c554f 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -217,7 +217,7 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type)
         r->status |= SCSI_REQ_STATUS_RETRY | type;
 
         bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read);
-        vm_stop(VMSTOP_DISKFULL);
+        vm_stop(RSTATE_IO_ERROR);
     } else {
         switch (error) {
         case ENOMEM:
@@ -338,7 +338,7 @@ static void scsi_dma_restart_bh(void *opaque)
     }
 }
 
-static void scsi_dma_restart_cb(void *opaque, int running, int reason)
+static void scsi_dma_restart_cb(void *opaque, int running, RunState state)
 {
     SCSIDiskState *s = opaque;
 
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index c2ee000..daa8e42 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -77,7 +77,7 @@ static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
         req->next = s->rq;
         s->rq = req;
         bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read);
-        vm_stop(VMSTOP_DISKFULL);
+        vm_stop(RSTATE_IO_ERROR);
     } else {
         virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
         bdrv_acct_done(s->bs, &req->acct);
@@ -439,7 +439,8 @@ static void virtio_blk_dma_restart_bh(void *opaque)
     virtio_submit_multiwrite(s->bs, &mrb);
 }
 
-static void virtio_blk_dma_restart_cb(void *opaque, int running, int reason)
+static void virtio_blk_dma_restart_cb(void *opaque, int running,
+                                      RunState state)
 {
     VirtIOBlock *s = opaque;
 
diff --git a/hw/virtio.c b/hw/virtio.c
index 13aa0fa..74ab79e 100644
--- a/hw/virtio.c
+++ b/hw/virtio.c
@@ -837,7 +837,7 @@ void virtio_cleanup(VirtIODevice *vdev)
     g_free(vdev);
 }
 
-static void virtio_vmstate_change(void *opaque, int running, int reason)
+static void virtio_vmstate_change(void *opaque, int running, RunState state)
 {
     VirtIODevice *vdev = opaque;
     bool backend_run = running && (vdev->status & VIRTIO_CONFIG_S_DRIVER_OK);
diff --git a/hw/watchdog.c b/hw/watchdog.c
index 1c900a1..71c6c7d 100644
--- a/hw/watchdog.c
+++ b/hw/watchdog.c
@@ -132,7 +132,7 @@ void watchdog_perform_action(void)
 
     case WDT_PAUSE:             /* same as 'stop' command in monitor */
         watchdog_mon_event("pause");
-        vm_stop(VMSTOP_WATCHDOG);
+        vm_stop(RSTATE_WATCHDOG);
         break;
 
     case WDT_DEBUG:
diff --git a/kvm-all.c b/kvm-all.c
index fbb9ff3..228655b 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -1014,7 +1014,7 @@ int kvm_cpu_exec(CPUState *env)
 
     if (ret < 0) {
         cpu_dump_state(env, stderr, fprintf, CPU_DUMP_CODE);
-        vm_stop(VMSTOP_PANIC);
+        vm_stop(RSTATE_PANICKED);
     }
 
     env->exit_request = 0;
diff --git a/migration.c b/migration.c
index f5959b4..29f1a76 100644
--- a/migration.c
+++ b/migration.c
@@ -374,7 +374,7 @@ void migrate_fd_put_ready(void *opaque)
         int old_vm_running = vm_running;
 
         DPRINTF("done iterating\n");
-        vm_stop(VMSTOP_MIGRATE);
+        vm_stop(RSTATE_PRE_MIGRATE);
 
         if ((qemu_savevm_state_complete(s->mon, s->file)) < 0) {
             if (old_vm_running) {
diff --git a/monitor.c b/monitor.c
index 03ae997..b98b8bd 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1293,7 +1293,7 @@ static void do_singlestep(Monitor *mon, const QDict *qdict)
  */
 static int do_stop(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
-    vm_stop(VMSTOP_USER);
+    vm_stop(RSTATE_PAUSED);
     return 0;
 }
 
@@ -2828,7 +2828,7 @@ static void do_loadvm(Monitor *mon, const QDict *qdict)
     int saved_vm_running  = vm_running;
     const char *name = qdict_get_str(qdict, "name");
 
-    vm_stop(VMSTOP_LOADVM);
+    vm_stop(RSTATE_RESTORE);
 
     if (load_vmstate(name) == 0 && saved_vm_running) {
         vm_start();
diff --git a/qemu-timer.c b/qemu-timer.c
index 46dd483..b582786 100644
--- a/qemu-timer.c
+++ b/qemu-timer.c
@@ -1116,7 +1116,8 @@ static void win32_rearm_timer(struct qemu_alarm_timer *t)
 
 #endif /* _WIN32 */
 
-static void alarm_timer_on_change_state_rearm(void *opaque, int running, int reason)
+static void alarm_timer_on_change_state_rearm(void *opaque, int running,
+                                              RunState state)
 {
     if (running)
         qemu_rearm_alarm_timer((struct qemu_alarm_timer *) opaque);
diff --git a/savevm.c b/savevm.c
index 1feaa70..f1f7735 100644
--- a/savevm.c
+++ b/savevm.c
@@ -1603,7 +1603,7 @@ static int qemu_savevm_state(Monitor *mon, QEMUFile *f)
     int ret;
 
     saved_vm_running = vm_running;
-    vm_stop(VMSTOP_SAVEVM);
+    vm_stop(RSTATE_SAVEVM);
 
     if (qemu_savevm_state_blocked(mon)) {
         ret = -EINVAL;
@@ -1932,7 +1932,7 @@ void do_savevm(Monitor *mon, const QDict *qdict)
     }
 
     saved_vm_running = vm_running;
-    vm_stop(VMSTOP_SAVEVM);
+    vm_stop(RSTATE_SAVEVM);
 
     memset(sn, 0, sizeof(*sn));
 
diff --git a/sysemu.h b/sysemu.h
index eb66af5..be3448b 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -9,6 +9,21 @@
 #include "notify.h"
 
 /* vl.c */
+
+typedef enum {
+    RSTATE_NO_STATE,
+    RSTATE_DEBUG,          /* qemu is running under gdb */
+    RSTATE_PANICKED,       /* paused due to an internal error */
+    RSTATE_IO_ERROR,       /* paused due to an I/O error */
+    RSTATE_PAUSED,         /* paused by the user (ie. the 'stop' command) */
+    RSTATE_PRE_MIGRATE,    /* paused preparing to finish migrate */
+    RSTATE_RESTORE,        /* paused restoring the VM state */
+    RSTATE_RUNNING,        /* qemu is running */
+    RSTATE_SAVEVM,         /* paused saving VM state */
+    RSTATE_SHUTDOWN,       /* guest shut down and -no-shutdown is in use */
+    RSTATE_WATCHDOG        /* watchdog fired and qemu is configured to pause */
+} RunState;
+
 extern const char *bios_name;
 
 extern int vm_running;
@@ -18,34 +33,24 @@ int qemu_uuid_parse(const char *str, uint8_t *uuid);
 #define UUID_FMT "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
 
 typedef struct vm_change_state_entry VMChangeStateEntry;
-typedef void VMChangeStateHandler(void *opaque, int running, int reason);
+typedef void VMChangeStateHandler(void *opaque, int running, RunState state);
 
 VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb,
                                                      void *opaque);
 void qemu_del_vm_change_state_handler(VMChangeStateEntry *e);
-void vm_state_notify(int running, int reason);
-
-#define VMSTOP_USER      0
-#define VMSTOP_DEBUG     1
-#define VMSTOP_SHUTDOWN  2
-#define VMSTOP_DISKFULL  3
-#define VMSTOP_WATCHDOG  4
-#define VMSTOP_PANIC     5
-#define VMSTOP_SAVEVM    6
-#define VMSTOP_LOADVM    7
-#define VMSTOP_MIGRATE   8
+void vm_state_notify(int running, RunState state);
 
 #define VMRESET_SILENT   false
 #define VMRESET_REPORT   true
 
 void vm_start(void);
-void vm_stop(int reason);
+void vm_stop(RunState state);
 
 void qemu_system_reset_request(void);
 void qemu_system_shutdown_request(void);
 void qemu_system_powerdown_request(void);
 void qemu_system_debug_request(void);
-void qemu_system_vmstop_request(int reason);
+void qemu_system_vmstop_request(RunState reason);
 int qemu_shutdown_requested_get(void);
 int qemu_reset_requested_get(void);
 int qemu_shutdown_requested(void);
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 22b1dd0..ead34ea 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -334,7 +334,7 @@ static int kvm_inject_mce_oldstyle(CPUState *env)
     return 0;
 }
 
-static void cpu_update_state(void *opaque, int running, int reason)
+static void cpu_update_state(void *opaque, int running, RunState state)
 {
     CPUState *env = opaque;
 
diff --git a/ui/spice-display.c b/ui/spice-display.c
index e385361..3a92a12 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -255,7 +255,8 @@ void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd)
     qemu_spice_destroy_primary_surface(ssd, 0, QXL_SYNC);
 }
 
-void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason)
+void qemu_spice_vm_change_state_handler(void *opaque, int running,
+                                        RunState state)
 {
     SimpleSpiceDisplay *ssd = opaque;
 
diff --git a/ui/spice-display.h b/ui/spice-display.h
index 1388641..5e52df9 100644
--- a/ui/spice-display.h
+++ b/ui/spice-display.h
@@ -22,6 +22,7 @@
 #include "qemu-thread.h"
 #include "console.h"
 #include "pflib.h"
+#include "sysemu.h"
 
 #define NUM_MEMSLOTS 8
 #define MEMSLOT_GENERATION_BITS 8
@@ -88,7 +89,8 @@ void qemu_spice_destroy_update(SimpleSpiceDisplay *sdpy, SimpleSpiceUpdate *upda
 void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd);
 void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd);
 void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd);
-void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason);
+void qemu_spice_vm_change_state_handler(void *opaque, int running,
+                                        RunState state);
 void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd, DisplayState *ds);
 
 void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
diff --git a/vl.c b/vl.c
index b773d2f..304a499 100644
--- a/vl.c
+++ b/vl.c
@@ -1145,14 +1145,14 @@ void qemu_del_vm_change_state_handler(VMChangeStateEntry *e)
     g_free (e);
 }
 
-void vm_state_notify(int running, int reason)
+void vm_state_notify(int running, RunState state)
 {
     VMChangeStateEntry *e;
 
-    trace_vm_state_notify(running, reason);
+    trace_vm_state_notify(running, state);
 
     for (e = vm_change_state_head.lh_first; e; e = e->entries.le_next) {
-        e->cb(e->opaque, running, reason);
+        e->cb(e->opaque, running, state);
     }
 }
 
@@ -1161,7 +1161,7 @@ void vm_start(void)
     if (!vm_running) {
         cpu_enable_ticks();
         vm_running = 1;
-        vm_state_notify(1, 0);
+        vm_state_notify(1, RSTATE_RUNNING);
         resume_all_vcpus();
         monitor_protocol_event(QEVENT_RESUME, NULL);
     }
@@ -1182,7 +1182,7 @@ static int shutdown_requested, shutdown_signal = -1;
 static pid_t shutdown_pid;
 static int powerdown_requested;
 static int debug_requested;
-static int vmstop_requested;
+static RunState vmstop_requested = RSTATE_NO_STATE;
 
 int qemu_shutdown_requested_get(void)
 {
@@ -1238,11 +1238,11 @@ static int qemu_debug_requested(void)
     return r;
 }
 
-static int qemu_vmstop_requested(void)
+static RunState qemu_vmstop_requested(void)
 {
-    int r = vmstop_requested;
-    vmstop_requested = 0;
-    return r;
+    RunState s = vmstop_requested;
+    vmstop_requested = RSTATE_NO_STATE;
+    return s;
 }
 
 void qemu_register_reset(QEMUResetHandler *func, void *opaque)
@@ -1317,9 +1317,9 @@ void qemu_system_debug_request(void)
     qemu_notify_event();
 }
 
-void qemu_system_vmstop_request(int reason)
+void qemu_system_vmstop_request(RunState state)
 {
-    vmstop_requested = reason;
+    vmstop_requested = state;
     qemu_notify_event();
 }
 
@@ -1469,13 +1469,13 @@ static void main_loop(void)
 #endif
 
         if (qemu_debug_requested()) {
-            vm_stop(VMSTOP_DEBUG);
+            vm_stop(RSTATE_DEBUG);
         }
         if (qemu_shutdown_requested()) {
             qemu_kill_report();
             monitor_protocol_event(QEVENT_SHUTDOWN, NULL);
             if (no_shutdown) {
-                vm_stop(VMSTOP_SHUTDOWN);
+                vm_stop(RSTATE_SHUTDOWN);
             } else
                 break;
         }
diff --git a/xen-all.c b/xen-all.c
index 1bc2c3c..b119817 100644
--- a/xen-all.c
+++ b/xen-all.c
@@ -846,7 +846,8 @@ static void xen_main_loop_prepare(XenIOState *state)
 
 /* Initialise Xen */
 
-static void xen_change_state_handler(void *opaque, int running, int reason)
+static void xen_change_state_handler(void *opaque, int running,
+                                     RunState state)
 {
     if (running) {
         /* record state running */
@@ -854,11 +855,12 @@ static void xen_change_state_handler(void *opaque, int running, int reason)
     }
 }
 
-static void xen_hvm_change_state_handler(void *opaque, int running, int reason)
+static void xen_hvm_change_state_handler(void *opaque, int running,
+                                         RunState rstate)
 {
-    XenIOState *state = opaque;
+    XenIOState *xstate = opaque;
     if (running) {
-        xen_main_loop_prepare(state);
+        xen_main_loop_prepare(xstate);
     }
 }
 
commit bff046f86b4f8970c722c3bc3e32173b8000e716
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Fri Jul 29 13:37:55 2011 -0300

    Move vm_state_notify() prototype from cpus.h to sysemu.h
    
    It's where all the state handling functions prototypes are located.
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/cpus.h b/cpus.h
index f42b54e..5885885 100644
--- a/cpus.h
+++ b/cpus.h
@@ -15,7 +15,6 @@ void cpu_synchronize_all_post_init(void);
 /* vl.c */
 extern int smp_cores;
 extern int smp_threads;
-void vm_state_notify(int running, int reason);
 bool cpu_exec_all(void);
 void set_numa_modes(void);
 void set_cpu_log(const char *optarg);
diff --git a/sysemu.h b/sysemu.h
index 9090457..eb66af5 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -23,6 +23,7 @@ typedef void VMChangeStateHandler(void *opaque, int running, int reason);
 VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb,
                                                      void *opaque);
 void qemu_del_vm_change_state_handler(VMChangeStateEntry *e);
+void vm_state_notify(int running, int reason);
 
 #define VMSTOP_USER      0
 #define VMSTOP_DEBUG     1
commit ef4f97cba2a354656b00eb8659bf61ab2321fa4e
Merge: c7fbbdf... d296363...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Sep 15 13:33:03 2011 -0500

    Merge remote-tracking branch 'qemu-kvm-tmp/memory/core' into staging

commit c7fbbdf9c870a98b42a7f4dfae20e702a70f9b21
Merge: ee18e73... 7834cf7...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Sep 15 13:28:28 2011 -0500

    Merge remote-tracking branch 'aneesh/for-upstream-4' into staging

commit d2963631dd54ddf0f46c151b7e3013e39bb78d3b
Author: David Gibson <david at gibson.dropbear.id.au>
Date:   Wed Sep 14 17:02:49 2011 +1000

    Fix subtle integer overflow bug in memory API
    
    It is quite common to have a MemoryRegion with size of INT64_MAX.
    When processing alias regions in render_memory_region() it's quite
    easy to find a case where it will construct a temporary AddrRange with
    a non-zero start, and size still of INT64_MAX.  When means attempting
    to compute the end of such a range as start + size will result in
    signed integer overflow.
    
    This integer overflow means that addrrange_intersects() can
    incorrectly report regions as not intersecting when they do.  For
    example consider the case of address ranges {0x10000000000,
    0x7fffffffffffffff} and {0x10010000000, 0x10000000} where the second
    is in fact included completely in the first.
    
    This patch rearranges addrrange_intersects() to avoid the integer
    overflow, correcting this behaviour.
    
    Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/memory.c b/memory.c
index 57f0fa4..101b67c 100644
--- a/memory.c
+++ b/memory.c
@@ -55,8 +55,8 @@ static AddrRange addrrange_shift(AddrRange range, int64_t delta)
 
 static bool addrrange_intersects(AddrRange r1, AddrRange r2)
 {
-    return (r1.start >= r2.start && r1.start < r2.start + r2.size)
-        || (r2.start >= r1.start && r2.start < r1.start + r1.size);
+    return (r1.start >= r2.start && (r1.start - r2.start) < r2.size)
+        || (r2.start >= r1.start && (r2.start - r1.start) < r1.size);
 }
 
 static AddrRange addrrange_intersection(AddrRange r1, AddrRange r2)
commit ee18e730234792b33e01d47939f4c30f29c9744e
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Sat Sep 10 10:23:56 2011 +0200

    qcow2: fix range check
    
    QCowL2Meta::offset is not cluster aligned but only sector aligned
    however nb_clusters count cluster from cluster start.
    This fix range check. Note that old code have no corruption issues
    related to this check cause it only cause intersection to occur
    when shouldn't.
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 428b5ad..2f76311 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -776,17 +776,17 @@ again:
      */
     QLIST_FOREACH(old_alloc, &s->cluster_allocs, next_in_flight) {
 
-        uint64_t end_offset = offset + nb_clusters * s->cluster_size;
-        uint64_t old_offset = old_alloc->offset;
-        uint64_t old_end_offset = old_alloc->offset +
-            old_alloc->nb_clusters * s->cluster_size;
+        uint64_t start = offset >> s->cluster_bits;
+        uint64_t end = start + nb_clusters;
+        uint64_t old_start = old_alloc->offset >> s->cluster_bits;
+        uint64_t old_end = old_start + old_alloc->nb_clusters;
 
-        if (end_offset < old_offset || offset > old_end_offset) {
+        if (end < old_start || start > old_end) {
             /* No intersection */
         } else {
-            if (offset < old_offset) {
+            if (start < old_start) {
                 /* Stop at the start of a running allocation */
-                nb_clusters = (old_offset - offset) >> s->cluster_bits;
+                nb_clusters = old_start - start;
             } else {
                 nb_clusters = 0;
             }
commit dea43a65d6b09c43cc7df94f76bb7522016318f4
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Sat Sep 10 10:59:16 2011 +0200

    qcow2: align cluster_data to block to improve performance using O_DIRECT
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/qcow2.c b/block/qcow2.c
index 8aed310..510ff68 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -237,7 +237,7 @@ static int qcow2_open(BlockDriverState *bs, int flags)
 
     s->cluster_cache = g_malloc(s->cluster_size);
     /* one more sector for decompressed data alignment */
-    s->cluster_data = g_malloc(QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size
+    s->cluster_data = qemu_blockalign(bs, QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size
                                   + 512);
     s->cluster_cache_offset = -1;
 
@@ -296,7 +296,7 @@ static int qcow2_open(BlockDriverState *bs, int flags)
         qcow2_cache_destroy(bs, s->l2_table_cache);
     }
     g_free(s->cluster_cache);
-    g_free(s->cluster_data);
+    qemu_vfree(s->cluster_data);
     return ret;
 }
 
@@ -456,7 +456,7 @@ static int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
                  */
                 if (!cluster_data) {
                     cluster_data =
-                        g_malloc0(QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size);
+                        qemu_blockalign(bs, QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size);
                 }
 
                 assert(cur_nr_sectors <=
@@ -496,7 +496,7 @@ fail:
     qemu_co_mutex_unlock(&s->lock);
 
     qemu_iovec_destroy(&hd_qiov);
-    g_free(cluster_data);
+    qemu_vfree(cluster_data);
 
     return ret;
 }
@@ -566,7 +566,7 @@ static int qcow2_co_writev(BlockDriverState *bs,
 
         if (s->crypt_method) {
             if (!cluster_data) {
-                cluster_data = g_malloc0(QCOW_MAX_CRYPT_CLUSTERS *
+                cluster_data = qemu_blockalign(bs, QCOW_MAX_CRYPT_CLUSTERS *
                                                  s->cluster_size);
             }
 
@@ -611,7 +611,7 @@ fail:
     qemu_co_mutex_unlock(&s->lock);
 
     qemu_iovec_destroy(&hd_qiov);
-    g_free(cluster_data);
+    qemu_vfree(cluster_data);
 
     return ret;
 }
@@ -628,7 +628,7 @@ static void qcow2_close(BlockDriverState *bs)
     qcow2_cache_destroy(bs, s->refcount_block_cache);
 
     g_free(s->cluster_cache);
-    g_free(s->cluster_data);
+    qemu_vfree(s->cluster_data);
     qcow2_refcount_close(bs);
 }
 
commit 847f171e6ac0c1a9b24e695e3496b140ec265b2c
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Thu Sep 8 21:44:15 2011 +0200

    ahci: Remove unused struct member
    
    Member variable is_read is written, but never read
    (contrary to its name). Remove it.
    
    Kevin Wolf <kwolf at redhat.com>
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index f4fa154..a8659cf 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -754,7 +754,6 @@ static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis,
         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);
 
@@ -768,7 +767,6 @@ static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis,
         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);
 
diff --git a/hw/ide/ahci.h b/hw/ide/ahci.h
index 3c29d93..5de986c 100644
--- a/hw/ide/ahci.h
+++ b/hw/ide/ahci.h
@@ -259,7 +259,6 @@ typedef struct NCQTransferState {
     BlockDriverAIOCB *aiocb;
     QEMUSGList sglist;
     BlockAcctCookie acct;
-    int is_read;
     uint16_t sector_count;
     uint64_t lba;
     uint8_t tag;
commit 05140499d38154df942048109ad78421ae3fd43a
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Thu Sep 8 13:38:42 2011 +0200

    qcow2: initialize metadata before inserting in cluster_allocs
    
    QCow2Meta structure was inserted into list before many fields are
    initialized. Currently is not a problem cause all occur in a lock
    but if qcow2_alloc_clusters would in a future unlock this lock
    some issues could arise.
    Initializing fields before inserting fix the problem.
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 113db8b..428b5ad 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -806,6 +806,11 @@ again:
         abort();
     }
 
+    /* save info needed for meta data update */
+    m->offset = offset;
+    m->n_start = n_start;
+    m->nb_clusters = nb_clusters;
+
     QLIST_INSERT_HEAD(&s->cluster_allocs, m, next_in_flight);
 
     /* allocate a new cluster */
@@ -816,11 +821,6 @@ again:
         goto fail;
     }
 
-    /* save info needed for meta data update */
-    m->offset = offset;
-    m->n_start = n_start;
-    m->nb_clusters = nb_clusters;
-
 out:
     ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
     if (ret < 0) {
commit 25ad22bc4e9c946df694fa7343027b1050b2946b
Author: Markus Armbruster <armbru at redhat.com>
Date:   Tue Sep 6 18:59:00 2011 +0200

    ide/atapi scsi-disk: Make monitor eject -f, then change work
    
    change fails while the tray is locked by the guest.  eject -f forces
    it open and removes any media.  Unfortunately, the tray closes again
    instantly.  Since the lock remains as it is, there is no way to insert
    another medium unless the guest voluntarily unlocks.
    
    Fix by leaving the tray open after monitor eject.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/blockdev.c b/blockdev.c
index 154cc84..0827bf7 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -635,7 +635,8 @@ static int eject_device(Monitor *mon, BlockDriverState *bs, int force)
         qerror_report(QERR_DEVICE_NOT_REMOVABLE, bdrv_get_device_name(bs));
         return -1;
     }
-    if (!force && bdrv_dev_is_medium_locked(bs)) {
+    if (!force && !bdrv_dev_is_tray_open(bs)
+        && bdrv_dev_is_medium_locked(bs)) {
         qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
         return -1;
     }
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 5def25c..9297b9e 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -789,6 +789,7 @@ static void ide_cd_change_cb(void *opaque, bool load)
     IDEState *s = opaque;
     uint64_t nb_sectors;
 
+    s->tray_open = !load;
     bdrv_get_geometry(s->bs, &nb_sectors);
     s->nb_sectors = nb_sectors;
 
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index f5f1d82..4a60820 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -1175,6 +1175,7 @@ static void scsi_destroy(SCSIDevice *dev)
 
 static void scsi_cd_change_media_cb(void *opaque, bool load)
 {
+    ((SCSIDiskState *)opaque)->tray_open = !load;
 }
 
 static bool scsi_cd_is_tray_open(void *opaque)
commit 7d4b4ba5c2bae99d44f265884b567ae63947bb4a
Author: Markus Armbruster <armbru at redhat.com>
Date:   Tue Sep 6 18:58:59 2011 +0200

    block: New change_media_cb() parameter load
    
    To let device models distinguish between eject and load.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index b006e58..e3fe97f 100644
--- a/block.c
+++ b/block.c
@@ -44,7 +44,7 @@
 #include <windows.h>
 #endif
 
-static void bdrv_dev_change_media_cb(BlockDriverState *bs);
+static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load);
 static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
         int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
         BlockDriverCompletionFunc *cb, void *opaque);
@@ -688,7 +688,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
     }
 
     if (!bdrv_key_required(bs)) {
-        bdrv_dev_change_media_cb(bs);
+        bdrv_dev_change_media_cb(bs, true);
     }
 
     return 0;
@@ -724,7 +724,7 @@ void bdrv_close(BlockDriverState *bs)
             bdrv_close(bs->file);
         }
 
-        bdrv_dev_change_media_cb(bs);
+        bdrv_dev_change_media_cb(bs, false);
     }
 }
 
@@ -807,10 +807,10 @@ void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops,
     }
 }
 
-static void bdrv_dev_change_media_cb(BlockDriverState *bs)
+static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load)
 {
     if (bs->dev_ops && bs->dev_ops->change_media_cb) {
-        bs->dev_ops->change_media_cb(bs->dev_opaque);
+        bs->dev_ops->change_media_cb(bs->dev_opaque, load);
     }
 }
 
@@ -1674,7 +1674,7 @@ int bdrv_set_key(BlockDriverState *bs, const char *key)
     } else if (!bs->valid_key) {
         bs->valid_key = 1;
         /* call the change callback now, we skipped it on open */
-        bdrv_dev_change_media_cb(bs);
+        bdrv_dev_change_media_cb(bs, true);
     }
     return ret;
 }
diff --git a/block.h b/block.h
index 4b7fa35..16bfa0a 100644
--- a/block.h
+++ b/block.h
@@ -32,11 +32,12 @@ typedef struct QEMUSnapshotInfo {
 typedef struct BlockDevOps {
     /*
      * Runs when virtual media changed (monitor commands eject, change)
+     * Argument load is true on load and false on eject.
      * Beware: doesn't run when a host device's physical media
      * changes.  Sure would be useful if it did.
      * Device models with removable media must implement this callback.
      */
-    void (*change_media_cb)(void *opaque);
+    void (*change_media_cb)(void *opaque, bool load);
     /*
      * Is the virtual tray open?
      * Device models implement this only when the device has a tray.
diff --git a/hw/fdc.c b/hw/fdc.c
index 57eda0c..433af73 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -1777,7 +1777,7 @@ static void fdctrl_result_timer(void *opaque)
     fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
 }
 
-static void fdctrl_change_cb(void *opaque)
+static void fdctrl_change_cb(void *opaque, bool load)
 {
     FDrive *drive = opaque;
 
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 3771acb..5def25c 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -784,7 +784,7 @@ static void ide_cfata_metadata_write(IDEState *s)
 }
 
 /* called when the inserted state of the media has changed */
-static void ide_cd_change_cb(void *opaque)
+static void ide_cd_change_cb(void *opaque, bool load)
 {
     IDEState *s = opaque;
     uint64_t nb_sectors;
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index b115760..f5f1d82 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -1173,7 +1173,7 @@ static void scsi_destroy(SCSIDevice *dev)
     blockdev_mark_auto_del(s->qdev.conf.bs);
 }
 
-static void scsi_cd_change_media_cb(void *opaque)
+static void scsi_cd_change_media_cb(void *opaque, bool load)
 {
 }
 
diff --git a/hw/sd.c b/hw/sd.c
index 1af62b2..10e26ad 100644
--- a/hw/sd.c
+++ b/hw/sd.c
@@ -419,7 +419,7 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv)
     sd->pwd_len = 0;
 }
 
-static void sd_cardchange(void *opaque)
+static void sd_cardchange(void *opaque, bool load)
 {
     SDState *sd = opaque;
 
commit ab359cd17e77163b672c5fc129cf4bcd0a3b38ce
Author: Markus Armbruster <armbru at redhat.com>
Date:   Tue Sep 6 18:58:58 2011 +0200

    nbd: Clean up use of block_int.h
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/nbd.c b/block/nbd.c
index 55cb2fd..70edd81 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -28,6 +28,7 @@
 
 #include "qemu-common.h"
 #include "nbd.h"
+#include "block_int.h"
 #include "module.h"
 #include "qemu_socket.h"
 
diff --git a/nbd.c b/nbd.c
index e7a585d..6d81cfb 100644
--- a/nbd.c
+++ b/nbd.c
@@ -17,6 +17,7 @@
  */
 
 #include "nbd.h"
+#include "block.h"
 
 #include <errno.h>
 #include <string.h>
diff --git a/nbd.h b/nbd.h
index 273cfa1..df7b7af 100644
--- a/nbd.h
+++ b/nbd.h
@@ -23,8 +23,6 @@
 
 #include "qemu-common.h"
 
-#include "block_int.h"
-
 struct nbd_request {
     uint32_t magic;
     uint32_t type;
commit 29e05f202238fe0efee4a0ecccc3fd348448a37c
Author: Markus Armbruster <armbru at redhat.com>
Date:   Tue Sep 6 18:58:57 2011 +0200

    block: Reset buffer alignment on detach
    
    BlockDriverState member buffer_alignment is initially 512.  The device
    model may set them, with bdrv_set_buffer_alignment().  If the device
    model gets detached (hot unplug), the device's alignment is left
    behind.  Only okay because device hot unplug automatically destroys
    the BlockDriverState.  But that's a questionable feature, best not to
    rely on it.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index e986986..b006e58 100644
--- a/block.c
+++ b/block.c
@@ -788,6 +788,7 @@ void bdrv_detach_dev(BlockDriverState *bs, void *dev)
     bs->dev = NULL;
     bs->dev_ops = NULL;
     bs->dev_opaque = NULL;
+    bs->buffer_alignment = 512;
 }
 
 /* TODO change to return DeviceState * when all users are qdevified */
commit 7b6f9300d55c6f01a65ed27a25b87b2748faceee
Author: Markus Armbruster <armbru at redhat.com>
Date:   Tue Sep 6 18:58:56 2011 +0200

    block: New bdrv_set_buffer_alignment()
    
    Device models should be able to set it without an unclean include of
    block_int.h.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index febfd67..e986986 100644
--- a/block.c
+++ b/block.c
@@ -480,7 +480,6 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename,
     bs->encrypted = 0;
     bs->valid_key = 0;
     bs->open_flags = flags;
-    /* buffer_alignment defaulted to 512, drivers can change this value */
     bs->buffer_alignment = 512;
 
     pstrcpy(bs->filename, sizeof(bs->filename), filename);
@@ -3115,7 +3114,10 @@ BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
     return NULL;
 }
 
-
+void bdrv_set_buffer_alignment(BlockDriverState *bs, int align)
+{
+    bs->buffer_alignment = align;
+}
 
 void *qemu_blockalign(BlockDriverState *bs, size_t size)
 {
diff --git a/block.h b/block.h
index 6e0c468..4b7fa35 100644
--- a/block.h
+++ b/block.h
@@ -269,6 +269,7 @@ 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);
 
+void bdrv_set_buffer_alignment(BlockDriverState *bs, int align);
 void *qemu_blockalign(BlockDriverState *bs, size_t size);
 
 #define BDRV_SECTORS_PER_DIRTY_CHUNK 2048
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 740ffe0..3771acb 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -1847,7 +1847,7 @@ int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
     s->smart_selftest_count = 0;
     if (kind == IDE_CD) {
         bdrv_set_dev_ops(bs, &ide_cd_block_ops, s);
-        bs->buffer_alignment = 2048;
+        bdrv_set_buffer_alignment(bs, 2048);
     } else {
         if (!bdrv_is_inserted(s->bs)) {
             error_report("Device needs media, but drive is empty");
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index d44b3b8..b115760 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -1236,7 +1236,7 @@ static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
         return -1;
     }
     s->cluster_size = s->qdev.blocksize / 512;
-    s->bs->buffer_alignment = s->qdev.blocksize;
+    bdrv_set_buffer_alignment(s->bs, s->qdev.blocksize);
 
     s->qdev.type = scsi_type;
     qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index 7bf684e..c2ee000 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -15,7 +15,6 @@
 #include "qemu-error.h"
 #include "trace.h"
 #include "blockdev.h"
-#include "block_int.h"
 #include "virtio-blk.h"
 #ifdef __linux__
 # include <scsi/sg.h>
@@ -601,7 +600,7 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf,
     register_savevm(dev, "virtio-blk", virtio_blk_id++, 2,
                     virtio_blk_save, virtio_blk_load, s);
     bdrv_set_dev_ops(s->bs, &virtio_block_ops, s);
-    s->bs->buffer_alignment = conf->logical_block_size;
+    bdrv_set_buffer_alignment(s->bs, conf->logical_block_size);
 
     add_boot_device_path(conf->bootindex, dev, "/disk at 0,0");
 
commit fb0c61a5a51cd51f0c4e2f009ccb4a44bd9d8544
Author: Markus Armbruster <armbru at redhat.com>
Date:   Tue Sep 6 18:58:55 2011 +0200

    hw: Trim superfluous #include "block_int.h"
    
    Including it in device models is unclean, including it without a
    reason adds insult to injury.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/fdc.c b/hw/fdc.c
index edade2b..57eda0c 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -36,7 +36,6 @@
 #include "qdev-addr.h"
 #include "blockdev.h"
 #include "sysemu.h"
-#include "block_int.h"
 
 /********************************************************/
 /* debug Floppy devices */
diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c
index 4d91e2c..5fe98b1 100644
--- a/hw/ide/cmd646.c
+++ b/hw/ide/cmd646.c
@@ -27,7 +27,6 @@
 #include <hw/pci.h>
 #include <hw/isa.h>
 #include "block.h"
-#include "block_int.h"
 #include "sysemu.h"
 #include "dma.h"
 
diff --git a/hw/ide/ich.c b/hw/ide/ich.c
index 5278bc4..0327d0e 100644
--- a/hw/ide/ich.c
+++ b/hw/ide/ich.c
@@ -66,7 +66,6 @@
 #include <hw/pci.h>
 #include <hw/isa.h>
 #include "block.h"
-#include "block_int.h"
 #include "dma.h"
 
 #include <hw/ide/pci.h>
diff --git a/hw/ide/isa.c b/hw/ide/isa.c
index 4ac7453..28b69d2 100644
--- a/hw/ide/isa.c
+++ b/hw/ide/isa.c
@@ -26,7 +26,6 @@
 #include <hw/pc.h>
 #include <hw/isa.h>
 #include "block.h"
-#include "block_int.h"
 #include "dma.h"
 
 #include <hw/ide/internal.h>
diff --git a/hw/ide/macio.c b/hw/ide/macio.c
index fdf5d75..c1844cb 100644
--- a/hw/ide/macio.c
+++ b/hw/ide/macio.c
@@ -26,7 +26,6 @@
 #include <hw/ppc_mac.h>
 #include <hw/mac_dbdma.h>
 #include "block.h"
-#include "block_int.h"
 #include "dma.h"
 
 #include <hw/ide/internal.h>
diff --git a/hw/ide/microdrive.c b/hw/ide/microdrive.c
index 91c0e3c..9eee5b5 100644
--- a/hw/ide/microdrive.c
+++ b/hw/ide/microdrive.c
@@ -26,7 +26,6 @@
 #include <hw/pc.h>
 #include <hw/pcmcia.h>
 #include "block.h"
-#include "block_int.h"
 #include "dma.h"
 
 #include <hw/ide/internal.h>
diff --git a/hw/ide/mmio.c b/hw/ide/mmio.c
index 132b751..2ec21b0 100644
--- a/hw/ide/mmio.c
+++ b/hw/ide/mmio.c
@@ -24,7 +24,6 @@
  */
 #include <hw/hw.h>
 #include "block.h"
-#include "block_int.h"
 #include "dma.h"
 
 #include <hw/ide/internal.h>
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index d1a14d7..9fded02 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -27,7 +27,6 @@
 #include <hw/pci.h>
 #include <hw/isa.h>
 #include "block.h"
-#include "block_int.h"
 #include "dma.h"
 
 #include <hw/ide/pci.h>
diff --git a/hw/ide/via.c b/hw/ide/via.c
index c0b9d43..dab8a39 100644
--- a/hw/ide/via.c
+++ b/hw/ide/via.c
@@ -28,7 +28,6 @@
 #include <hw/pci.h>
 #include <hw/isa.h>
 #include "block.h"
-#include "block_int.h"
 #include "sysemu.h"
 #include "dma.h"
 
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index ac284e9..dbb3bdf 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -15,7 +15,6 @@
 #include "hw.h"
 #include "pci.h"
 #include "scsi.h"
-#include "block_int.h"
 
 //#define DEBUG_LSI
 //#define DEBUG_LSI_REG
commit d1a0739de59501809ad5382030a0d0eba98b69b0
Author: Markus Armbruster <armbru at redhat.com>
Date:   Tue Sep 6 18:58:54 2011 +0200

    block: Move BlockConf & friends from block_int.h to block.h
    
    It's convenience stuff for block device models, so block.h isn't the
    ideal home either, but better than block_int.h.
    
    Permits moving some #include "block_int.h" from device model .h into
    .c.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.h b/block.h
index 9f6d02c..6e0c468 100644
--- a/block.h
+++ b/block.h
@@ -350,5 +350,43 @@ typedef enum {
 #define BLKDBG_EVENT(bs, evt) bdrv_debug_event(bs, evt)
 void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event);
 
+
+/* Convenience for block device models */
+
+typedef struct BlockConf {
+    BlockDriverState *bs;
+    uint16_t physical_block_size;
+    uint16_t logical_block_size;
+    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)
+{
+    unsigned int exp = 0, size;
+
+    for (size = conf->physical_block_size;
+        size > conf->logical_block_size;
+        size >>= 1) {
+        exp++;
+    }
+
+    return exp;
+}
+
+#define DEFINE_BLOCK_PROPERTIES(_state, _conf)                          \
+    DEFINE_PROP_DRIVE("drive", _state, _conf.bs),                       \
+    DEFINE_PROP_UINT16("logical_block_size", _state,                    \
+                       _conf.logical_block_size, 512),                  \
+    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_INT32("bootindex", _state, _conf.bootindex, -1),        \
+    DEFINE_PROP_UINT32("discard_granularity", _state, \
+                       _conf.discard_granularity, 0)
+
 #endif
 
diff --git a/block_int.h b/block_int.h
index f30563d..8c3b863 100644
--- a/block_int.h
+++ b/block_int.h
@@ -225,39 +225,4 @@ void qemu_aio_release(void *p);
 int is_windows_drive(const char *filename);
 #endif
 
-typedef struct BlockConf {
-    BlockDriverState *bs;
-    uint16_t physical_block_size;
-    uint16_t logical_block_size;
-    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)
-{
-    unsigned int exp = 0, size;
-
-    for (size = conf->physical_block_size;
-        size > conf->logical_block_size;
-        size >>= 1) {
-        exp++;
-    }
-
-    return exp;
-}
-
-#define DEFINE_BLOCK_PROPERTIES(_state, _conf)                          \
-    DEFINE_PROP_DRIVE("drive", _state, _conf.bs),                       \
-    DEFINE_PROP_UINT16("logical_block_size", _state,                    \
-                       _conf.logical_block_size, 512),                  \
-    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_INT32("bootindex", _state, _conf.bootindex, -1),        \
-    DEFINE_PROP_UINT32("discard_granularity", _state, \
-                       _conf.discard_granularity, 0)
-
 #endif /* BLOCK_INT_H */
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 8f719ee..740ffe0 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -30,6 +30,7 @@
 #include "sysemu.h"
 #include "dma.h"
 #include "blockdev.h"
+#include "block_int.h"
 
 #include <hw/ide/internal.h>
 
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index 663db39..233915c 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -7,7 +7,6 @@
  * non-internal declarations are in hw/ide.h
  */
 #include <hw/ide.h>
-#include "block_int.h"
 #include "iorange.h"
 #include "dma.h"
 
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index f48ca8b..d44b3b8 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -37,6 +37,7 @@ do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
 #include "scsi-defs.h"
 #include "sysemu.h"
 #include "blockdev.h"
+#include "block_int.h"
 
 #define SCSI_DMA_BUF_SIZE    131072
 #define SCSI_MAX_INQUIRY_LEN 256
diff --git a/hw/scsi.h b/hw/scsi.h
index a28cd68..e8dcabf 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -3,7 +3,6 @@
 
 #include "qdev.h"
 #include "block.h"
-#include "block_int.h"
 
 #define MAX_SCSI_DEVS	255
 
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index 6d1a7cf..7bf684e 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -15,6 +15,7 @@
 #include "qemu-error.h"
 #include "trace.h"
 #include "blockdev.h"
+#include "block_int.h"
 #include "virtio-blk.h"
 #ifdef __linux__
 # include <scsi/sg.h>
diff --git a/hw/virtio.h b/hw/virtio.h
index c129264..4d20d9b 100644
--- a/hw/virtio.h
+++ b/hw/virtio.h
@@ -18,7 +18,7 @@
 #include "net.h"
 #include "qdev.h"
 #include "sysemu.h"
-#include "block_int.h"
+#include "block.h"
 #include "event_notifier.h"
 #ifdef CONFIG_LINUX
 #include "9p.h"
commit e4def80b36231e161b91fa984cd0d73b45668f00
Author: Markus Armbruster <armbru at redhat.com>
Date:   Tue Sep 6 18:58:53 2011 +0200

    block: Show whether the virtual tray is open in info block
    
    Need to ask the device, so this requires new BlockDevOps member
    is_tray_open().
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index d8193a3..febfd67 100644
--- a/block.c
+++ b/block.c
@@ -819,6 +819,14 @@ bool bdrv_dev_has_removable_media(BlockDriverState *bs)
     return !bs->dev || (bs->dev_ops && bs->dev_ops->change_media_cb);
 }
 
+bool bdrv_dev_is_tray_open(BlockDriverState *bs)
+{
+    if (bs->dev_ops && bs->dev_ops->is_tray_open) {
+        return bs->dev_ops->is_tray_open(bs->dev_opaque);
+    }
+    return false;
+}
+
 static void bdrv_dev_resize_cb(BlockDriverState *bs)
 {
     if (bs->dev_ops && bs->dev_ops->resize_cb) {
@@ -1853,8 +1861,9 @@ static void bdrv_print_dict(QObject *obj, void *opaque)
 
     if (qdict_get_bool(bs_dict, "removable")) {
         monitor_printf(mon, " locked=%d", qdict_get_bool(bs_dict, "locked"));
+        monitor_printf(mon, " tray-open=%d",
+                       qdict_get_bool(bs_dict, "tray-open"));
     }
-
     if (qdict_haskey(bs_dict, "inserted")) {
         QDict *qdict = qobject_to_qdict(qdict_get(bs_dict, "inserted"));
 
@@ -1889,16 +1898,21 @@ void bdrv_info(Monitor *mon, QObject **ret_data)
 
     QTAILQ_FOREACH(bs, &bdrv_states, list) {
         QObject *bs_obj;
+        QDict *bs_dict;
 
         bs_obj = qobject_from_jsonf("{ 'device': %s, 'type': 'unknown', "
                                     "'removable': %i, 'locked': %i }",
                                     bs->device_name,
                                     bdrv_dev_has_removable_media(bs),
                                     bdrv_dev_is_medium_locked(bs));
+        bs_dict = qobject_to_qdict(bs_obj);
 
+        if (bdrv_dev_has_removable_media(bs)) {
+            qdict_put(bs_dict, "tray-open",
+                      qbool_from_int(bdrv_dev_is_tray_open(bs)));
+        }
         if (bs->drv) {
             QObject *obj;
-            QDict *bs_dict = qobject_to_qdict(bs_obj);
 
             obj = qobject_from_jsonf("{ 'file': %s, 'ro': %i, 'drv': %s, "
                                      "'encrypted': %i }",
diff --git a/block.h b/block.h
index e4b5530..9f6d02c 100644
--- a/block.h
+++ b/block.h
@@ -38,6 +38,11 @@ typedef struct BlockDevOps {
      */
     void (*change_media_cb)(void *opaque);
     /*
+     * Is the virtual tray open?
+     * Device models implement this only when the device has a tray.
+     */
+    bool (*is_tray_open)(void *opaque);
+    /*
      * Is the virtual medium locked into the device?
      * Device models implement this only when device has such a lock.
      */
@@ -101,6 +106,7 @@ void *bdrv_get_attached_dev(BlockDriverState *bs);
 void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops,
                       void *opaque);
 bool bdrv_dev_has_removable_media(BlockDriverState *bs);
+bool bdrv_dev_is_tray_open(BlockDriverState *bs);
 bool bdrv_dev_is_medium_locked(BlockDriverState *bs);
 int bdrv_read(BlockDriverState *bs, int64_t sector_num,
               uint8_t *buf, int nb_sectors);
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 716addc..8f719ee 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -1795,6 +1795,11 @@ void ide_bus_reset(IDEBus *bus)
     bus->dma->ops->reset(bus->dma);
 }
 
+static bool ide_cd_is_tray_open(void *opaque)
+{
+    return ((IDEState *)opaque)->tray_open;
+}
+
 static bool ide_cd_is_medium_locked(void *opaque)
 {
     return ((IDEState *)opaque)->tray_locked;
@@ -1802,6 +1807,7 @@ static bool ide_cd_is_medium_locked(void *opaque)
 
 static const BlockDevOps ide_cd_block_ops = {
     .change_media_cb = ide_cd_change_cb,
+    .is_tray_open = ide_cd_is_tray_open,
     .is_medium_locked = ide_cd_is_medium_locked,
 };
 
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 0f0cddc..f48ca8b 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -1176,6 +1176,11 @@ static void scsi_cd_change_media_cb(void *opaque)
 {
 }
 
+static bool scsi_cd_is_tray_open(void *opaque)
+{
+    return ((SCSIDiskState *)opaque)->tray_open;
+}
+
 static bool scsi_cd_is_medium_locked(void *opaque)
 {
     return ((SCSIDiskState *)opaque)->tray_locked;
@@ -1183,6 +1188,7 @@ static bool scsi_cd_is_medium_locked(void *opaque)
 
 static const BlockDevOps scsi_cd_block_ops = {
     .change_media_cb = scsi_cd_change_media_cb,
+    .is_tray_open = scsi_cd_is_tray_open,
     .is_medium_locked = scsi_cd_is_medium_locked,
 };
 
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 27cc66e..d1c2c59 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1131,6 +1131,8 @@ Each json-object contain the following:
          - Possible values: "unknown"
 - "removable": true if the device is removable, false otherwise (json-bool)
 - "locked": true if the device is locked, false otherwise (json-bool)
+- "tray-open": only present if removable, true if the device has a tray,
+               and it is open (json-bool)
 - "inserted": only present if the device is inserted, it is a json-object
    containing the following:
          - "file": device file name (json-string)
commit 9e6a4c9177bc95aa04438458d75442e80db9ad33
Author: Markus Armbruster <armbru at redhat.com>
Date:   Tue Sep 6 18:58:52 2011 +0200

    block: Drop BlockDriverState member removable
    
    It's a confused mess (see previous commit).  No users remain.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index fee45bf..d8193a3 100644
--- a/block.c
+++ b/block.c
@@ -1614,14 +1614,6 @@ BlockErrorAction bdrv_get_on_error(BlockDriverState *bs, int is_read)
     return is_read ? bs->on_read_error : bs->on_write_error;
 }
 
-void bdrv_set_removable(BlockDriverState *bs, int removable)
-{
-    bs->removable = removable;
-    if (removable && bs == bs_snapshots) {
-        bs_snapshots = NULL;
-    }
-}
-
 int bdrv_is_read_only(BlockDriverState *bs)
 {
     return bs->read_only;
diff --git a/block.h b/block.h
index 860e30d..e4b5530 100644
--- a/block.h
+++ b/block.h
@@ -207,7 +207,6 @@ int bdrv_get_translation_hint(BlockDriverState *bs);
 void bdrv_set_on_error(BlockDriverState *bs, BlockErrorAction on_read_error,
                        BlockErrorAction on_write_error);
 BlockErrorAction bdrv_get_on_error(BlockDriverState *bs, int is_read);
-void bdrv_set_removable(BlockDriverState *bs, int removable);
 int bdrv_is_read_only(BlockDriverState *bs);
 int bdrv_is_sg(BlockDriverState *bs);
 int bdrv_enable_write_cache(BlockDriverState *bs);
diff --git a/block_int.h b/block_int.h
index f42af2c..f30563d 100644
--- a/block_int.h
+++ b/block_int.h
@@ -155,7 +155,6 @@ struct BlockDriverState {
     int read_only; /* if true, the media is read only */
     int keep_read_only; /* if true, the media was requested to stay read only */
     int open_flags; /* flags used to open the file, re-used for re-open */
-    int removable; /* if true, the media can be removed */
     int encrypted; /* if true, the media is encrypted */
     int valid_key; /* if true, a valid encryption key has been set */
     int sg;        /* if true, the device is a /dev/sg* */
diff --git a/blockdev.c b/blockdev.c
index ddf1f8f..154cc84 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -473,17 +473,12 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
             }
 	    break;
 	case MEDIA_CDROM:
-            bdrv_set_removable(dinfo->bdrv, 1);
             dinfo->media_cd = 1;
 	    break;
 	}
         break;
     case IF_SD:
-        /* FIXME: This isn't really a floppy, but it's a reasonable
-           approximation.  */
     case IF_FLOPPY:
-        bdrv_set_removable(dinfo->bdrv, 1);
-        break;
     case IF_PFLASH:
     case IF_MTD:
         break;
diff --git a/hw/fdc.c b/hw/fdc.c
index 1d44bbd..edade2b 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -1813,7 +1813,6 @@ static int fdctrl_connect_drives(FDCtrl *fdctrl)
         fd_revalidate(drive);
         if (drive->bs) {
             drive->media_changed = 1;
-            bdrv_set_removable(drive->bs, 1);
             bdrv_set_dev_ops(drive->bs, &fdctrl_block_ops, drive);
         }
     }
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 18d3c62..716addc 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -1864,7 +1864,6 @@ int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
     }
 
     ide_reset(s);
-    bdrv_set_removable(bs, s->drive_kind == IDE_CD);
     return 0;
 }
 
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index d6e838c..0f0cddc 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -1233,7 +1233,6 @@ static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
 
     s->qdev.type = scsi_type;
     qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
-    bdrv_set_removable(s->bs, scsi_type == TYPE_ROM);
     add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, ",0");
     return 0;
 }
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index cb5d4f1..5ce01af 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -450,7 +450,6 @@ static int scsi_generic_initfn(SCSIDevice *dev)
         }
     }
     DPRINTF("block size %d\n", s->qdev.blocksize);
-    bdrv_set_removable(s->bs, 0);
     return 0;
 }
 
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index d5d4757..6d1a7cf 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -599,7 +599,6 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf,
     s->qdev = dev;
     register_savevm(dev, "virtio-blk", virtio_blk_id++, 2,
                     virtio_blk_save, virtio_blk_load, s);
-    bdrv_set_removable(s->bs, 0);
     bdrv_set_dev_ops(s->bs, &virtio_block_ops, s);
     s->bs->buffer_alignment = conf->logical_block_size;
 
commit 2c6942fa7b332a95286071b92d233853e1000948
Author: Markus Armbruster <armbru at redhat.com>
Date:   Tue Sep 6 18:58:51 2011 +0200

    block: Clean up remaining users of "removable"
    
    BlockDriverState member removable is a confused mess.  It is true when
    an ide-cd, scsi-cd or floppy qdev is attached, or when the
    BlockDriverState was created with -drive if={floppy,sd} or -drive
    if={ide,scsi,xen,none},media=cdrom ("created removable"), except when
    an ide-hd, scsi-hd, scsi-generic or virtio-blk qdev is attached.
    
    Three users remain:
    
    1. eject_device(), via bdrv_is_removable() uses it to determine
       whether a block device can eject media.
    
    2. bdrv_info() is monitor command "info block".  QMP documentation
       says "true if the device is removable, false otherwise".  From the
       monitor user's point of view, the only sensible interpretation of
       "is removable" is "can eject media with monitor commands eject and
       change".
    
    A block device can eject media unless a device is attached that
    doesn't support it.  Switch the two users over to new
    bdrv_dev_has_removable_media() that returns exactly that.
    
    3. bdrv_getlength() uses to suppress its length cache when media can
       change (see commit 46a4e4e6).  Media change is either monitor
       command change (updates the length cache), monitor command eject
       (doesn't update the length cache, easily fixable), or physical
       media change (invalidates length cache, not so easily fixable).
    
    I'm refraining from improving anything here, because this series is
    long enough already.  Instead, I simply switch it over to
    bdrv_dev_has_removable_media() as well.
    
    This changes the behavior of the length cache and of monitor commands
    eject and change in two cases:
    
    a. drive not created removable, no device attached
    
       The commit makes the drive removable, and defeats the length cache.
    
       Example: -drive if=none
    
    b. drive created removable, but the attached drive is non-removable,
       and doesn't call bdrv_set_removable(..., 0) (most devices don't)
    
       The commit makes the drive non-removable, and enables the length
       cache.
    
       Example: -drive if=xen,media=cdrom -M xenpv
    
       The other non-removable devices that don't call
       bdrv_set_removable() can't currently use a drive created removable,
       either because they aren't qdevified, or because they lack a drive
       property.  Won't stay that way.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index 7225b15..fee45bf 100644
--- a/block.c
+++ b/block.c
@@ -802,6 +802,9 @@ void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops,
 {
     bs->dev_ops = ops;
     bs->dev_opaque = opaque;
+    if (bdrv_dev_has_removable_media(bs) && bs == bs_snapshots) {
+        bs_snapshots = NULL;
+    }
 }
 
 static void bdrv_dev_change_media_cb(BlockDriverState *bs)
@@ -811,6 +814,11 @@ static void bdrv_dev_change_media_cb(BlockDriverState *bs)
     }
 }
 
+bool bdrv_dev_has_removable_media(BlockDriverState *bs)
+{
+    return !bs->dev || (bs->dev_ops && bs->dev_ops->change_media_cb);
+}
+
 static void bdrv_dev_resize_cb(BlockDriverState *bs)
 {
     if (bs->dev_ops && bs->dev_ops->resize_cb) {
@@ -1329,7 +1337,7 @@ int64_t bdrv_getlength(BlockDriverState *bs)
     if (!drv)
         return -ENOMEDIUM;
 
-    if (bs->growable || bs->removable) {
+    if (bs->growable || bdrv_dev_has_removable_media(bs)) {
         if (drv->bdrv_getlength) {
             return drv->bdrv_getlength(bs);
         }
@@ -1614,11 +1622,6 @@ void bdrv_set_removable(BlockDriverState *bs, int removable)
     }
 }
 
-int bdrv_is_removable(BlockDriverState *bs)
-{
-    return bs->removable;
-}
-
 int bdrv_is_read_only(BlockDriverState *bs)
 {
     return bs->read_only;
@@ -1897,7 +1900,8 @@ void bdrv_info(Monitor *mon, QObject **ret_data)
 
         bs_obj = qobject_from_jsonf("{ 'device': %s, 'type': 'unknown', "
                                     "'removable': %i, 'locked': %i }",
-                                    bs->device_name, bs->removable,
+                                    bs->device_name,
+                                    bdrv_dev_has_removable_media(bs),
                                     bdrv_dev_is_medium_locked(bs));
 
         if (bs->drv) {
diff --git a/block.h b/block.h
index 4691090..860e30d 100644
--- a/block.h
+++ b/block.h
@@ -34,6 +34,7 @@ typedef struct BlockDevOps {
      * Runs when virtual media changed (monitor commands eject, change)
      * Beware: doesn't run when a host device's physical media
      * changes.  Sure would be useful if it did.
+     * Device models with removable media must implement this callback.
      */
     void (*change_media_cb)(void *opaque);
     /*
@@ -99,6 +100,7 @@ void bdrv_detach_dev(BlockDriverState *bs, void *dev);
 void *bdrv_get_attached_dev(BlockDriverState *bs);
 void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops,
                       void *opaque);
+bool bdrv_dev_has_removable_media(BlockDriverState *bs);
 bool bdrv_dev_is_medium_locked(BlockDriverState *bs);
 int bdrv_read(BlockDriverState *bs, int64_t sector_num,
               uint8_t *buf, int nb_sectors);
@@ -206,7 +208,6 @@ void bdrv_set_on_error(BlockDriverState *bs, BlockErrorAction on_read_error,
                        BlockErrorAction on_write_error);
 BlockErrorAction bdrv_get_on_error(BlockDriverState *bs, int is_read);
 void bdrv_set_removable(BlockDriverState *bs, int removable);
-int bdrv_is_removable(BlockDriverState *bs);
 int bdrv_is_read_only(BlockDriverState *bs);
 int bdrv_is_sg(BlockDriverState *bs);
 int bdrv_enable_write_cache(BlockDriverState *bs);
diff --git a/blockdev.c b/blockdev.c
index 3f00b2e..ddf1f8f 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -636,7 +636,7 @@ out:
 
 static int eject_device(Monitor *mon, BlockDriverState *bs, int force)
 {
-    if (!bdrv_is_removable(bs)) {
+    if (!bdrv_dev_has_removable_media(bs)) {
         qerror_report(QERR_DEVICE_NOT_REMOVABLE, bdrv_get_device_name(bs));
         return -1;
     }
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 1a49217..d6e838c 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -1172,12 +1172,17 @@ static void scsi_destroy(SCSIDevice *dev)
     blockdev_mark_auto_del(s->qdev.conf.bs);
 }
 
+static void scsi_cd_change_media_cb(void *opaque)
+{
+}
+
 static bool scsi_cd_is_medium_locked(void *opaque)
 {
     return ((SCSIDiskState *)opaque)->tray_locked;
 }
 
 static const BlockDevOps scsi_cd_block_ops = {
+    .change_media_cb = scsi_cd_change_media_cb,
     .is_medium_locked = scsi_cd_is_medium_locked,
 };
 
commit db118fe725b92a8271ff7d17f1d932104965bdb0
Author: Markus Armbruster <armbru at redhat.com>
Date:   Tue Sep 6 18:58:50 2011 +0200

    ide/atapi: Preserve tray state on migration
    
    Use a subsection, so that migration to older version still works,
    provided the tray is closed and unlocked.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/ide/core.c b/hw/ide/core.c
index 0403ad2..18d3c62 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -2058,6 +2058,22 @@ static bool ide_drive_pio_state_needed(void *opaque)
         || (s->bus->error_status & BM_STATUS_PIO_RETRY);
 }
 
+static int ide_tray_state_post_load(void *opaque, int version_id)
+{
+    IDEState *s = opaque;
+
+    bdrv_eject(s->bs, s->tray_open);
+    bdrv_lock_medium(s->bs, s->tray_locked);
+    return 0;
+}
+
+static bool ide_tray_state_needed(void *opaque)
+{
+    IDEState *s = opaque;
+
+    return s->tray_open || s->tray_locked;
+}
+
 static bool ide_atapi_gesn_needed(void *opaque)
 {
     IDEState *s = opaque;
@@ -2085,6 +2101,19 @@ static const VMStateDescription vmstate_ide_atapi_gesn_state = {
     }
 };
 
+static const VMStateDescription vmstate_ide_tray_state = {
+    .name = "ide_drive/tray_state",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = ide_tray_state_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_BOOL(tray_open, IDEState),
+        VMSTATE_BOOL(tray_locked, IDEState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static const VMStateDescription vmstate_ide_drive_pio_state = {
     .name = "ide_drive/pio_state",
     .version_id = 1,
@@ -2139,6 +2168,9 @@ const VMStateDescription vmstate_ide_drive = {
             .vmsd = &vmstate_ide_drive_pio_state,
             .needed = ide_drive_pio_state_needed,
         }, {
+            .vmsd = &vmstate_ide_tray_state,
+            .needed = ide_tray_state_needed,
+        }, {
             .vmsd = &vmstate_ide_atapi_gesn_state,
             .needed = ide_atapi_gesn_needed,
         }, {
commit 68bb01f398308eb84f645e2509205a8d9dd0104f
Author: Markus Armbruster <armbru at redhat.com>
Date:   Tue Sep 6 18:58:49 2011 +0200

    scsi-disk: Fix START_STOP to fail when it can't eject
    
    Don't fail when tray is already open.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 59d6ada..0248294 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -772,6 +772,11 @@ const struct SCSISense sense_code_NO_MEDIUM = {
     .key = NOT_READY, .asc = 0x3a, .ascq = 0x00
 };
 
+/* LUN not ready, medium removal prevented */
+const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED = {
+    .key = NOT_READY, .asc = 0x53, .ascq = 0x00
+};
+
 /* Hardware error, internal target failure */
 const struct SCSISense sense_code_TARGET_FAILURE = {
     .key = HARDWARE_ERROR, .asc = 0x44, .ascq = 0x00
@@ -807,6 +812,11 @@ const struct SCSISense sense_code_INCOMPATIBLE_MEDIUM = {
     .key = ILLEGAL_REQUEST, .asc = 0x30, .ascq = 0x00
 };
 
+/* Illegal request, medium removal prevented */
+const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED = {
+    .key = ILLEGAL_REQUEST, .asc = 0x53, .ascq = 0x00
+};
+
 /* Command aborted, I/O process terminated */
 const struct SCSISense sense_code_IO_ERROR = {
     .key = ABORTED_COMMAND, .asc = 0x00, .ascq = 0x06
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 4e89bb1..1a49217 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -822,7 +822,7 @@ static int scsi_disk_emulate_read_toc(SCSIRequest *req, uint8_t *outbuf)
     return toclen;
 }
 
-static void scsi_disk_emulate_start_stop(SCSIDiskReq *r)
+static int scsi_disk_emulate_start_stop(SCSIDiskReq *r)
 {
     SCSIRequest *req = &r->req;
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
@@ -830,12 +830,17 @@ static void scsi_disk_emulate_start_stop(SCSIDiskReq *r)
     bool loej = req->cmd.buf[4] & 2; /* load on start, eject on !start */
 
     if (s->qdev.type == TYPE_ROM && loej) {
-        if (!start && s->tray_locked) {
-            return;
+        if (!start && !s->tray_open && s->tray_locked) {
+            scsi_check_condition(r,
+                                 bdrv_is_inserted(s->bs)
+                                 ? SENSE_CODE(ILLEGAL_REQ_REMOVAL_PREVENTED)
+                                 : SENSE_CODE(NOT_READY_REMOVAL_PREVENTED));
+            return -1;
         }
         bdrv_eject(s->bs, !start);
         s->tray_open = !start;
     }
+    return 0;
 }
 
 static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
@@ -883,7 +888,9 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
             goto illegal_request;
         break;
     case START_STOP:
-        scsi_disk_emulate_start_stop(r);
+        if (scsi_disk_emulate_start_stop(r) < 0) {
+            return -1;
+        }
         break;
     case ALLOW_MEDIUM_REMOVAL:
         s->tray_locked = req->cmd.buf[4] & 1;
diff --git a/hw/scsi.h b/hw/scsi.h
index 98fd689..a28cd68 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -136,6 +136,8 @@ extern const struct SCSISense sense_code_NO_SENSE;
 extern const struct SCSISense sense_code_LUN_NOT_READY;
 /* LUN not ready, Medium not present */
 extern const struct SCSISense sense_code_NO_MEDIUM;
+/* LUN not ready, medium removal prevented */
+extern const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED;
 /* Hardware error, internal target failure */
 extern const struct SCSISense sense_code_TARGET_FAILURE;
 /* Illegal request, invalid command operation code */
@@ -150,6 +152,8 @@ extern const struct SCSISense sense_code_LUN_NOT_SUPPORTED;
 extern const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED;
 /* Illegal request, Incompatible format */
 extern const struct SCSISense sense_code_INCOMPATIBLE_FORMAT;
+/* Illegal request, medium removal prevented */
+extern const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED;
 /* Command aborted, I/O process terminated */
 extern const struct SCSISense sense_code_IO_ERROR;
 /* Command aborted, I_T Nexus loss occurred */
commit 48f65b3f52fdaf8fdae331248236e8b487de2b3b
Author: Markus Armbruster <armbru at redhat.com>
Date:   Tue Sep 6 18:58:48 2011 +0200

    ide/atapi: Don't fail eject when tray is already open
    
    MMC-5 6.40.2.6 specifies that START STOP UNIT succeeds when the drive
    already has the requested state.  cmd_start_stop_unit() fails when
    asked to eject while the tray is open and locked.  Fix that.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c
index 06778f3..3f909c3 100644
--- a/hw/ide/atapi.c
+++ b/hw/ide/atapi.c
@@ -910,7 +910,7 @@ static void cmd_start_stop_unit(IDEState *s, uint8_t* buf)
     bool loej = buf[4] & 2;     /* load on start, eject on !start */
 
     if (loej) {
-        if (!start && s->tray_locked) {
+        if (!start && !s->tray_open && s->tray_locked) {
             sense = bdrv_is_inserted(s->bs)
                 ? SENSE_NOT_READY : SENSE_ILLEGAL_REQUEST;
             ide_atapi_cmd_error(s, sense, ASC_MEDIA_REMOVAL_PREVENTED);
commit eb93d5d9906cfa9fb6c3039a310d796dddfddeea
Author: Sage Weil <sage at newdream.net>
Date:   Wed Sep 7 09:28:06 2011 -0700

    rbd: fix leak in qemu_rbd_open failure paths
    
    Fix leak of s->snap in failure path.  Simplify error paths for the whole
    function.
    
    Reported-by: Stefan Hajnoczi <stefanha at gmail.com>
    Signed-off-by: Sage Weil <sage at newdream.net>
    Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/rbd.c b/block/rbd.c
index 2763092..1b78d51 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -427,10 +427,6 @@ static int qemu_rbd_open(BlockDriverState *bs, const char *filename, int flags)
                            conf, sizeof(conf)) < 0) {
         return -EINVAL;
     }
-    s->snap = NULL;
-    if (snap_buf[0] != '\0') {
-        s->snap = g_strdup(snap_buf);
-    }
 
     clientname = qemu_rbd_parse_clientname(conf, clientname_buf);
     r = rados_create(&s->cluster, clientname);
@@ -439,12 +435,16 @@ static int qemu_rbd_open(BlockDriverState *bs, const char *filename, int flags)
         return r;
     }
 
+    s->snap = NULL;
+    if (snap_buf[0] != '\0') {
+        s->snap = g_strdup(snap_buf);
+    }
+
     if (strstr(conf, "conf=") == NULL) {
         r = rados_conf_read_file(s->cluster, NULL);
         if (r < 0) {
             error_report("error reading config file");
-            rados_shutdown(s->cluster);
-            return r;
+            goto failed_shutdown;
         }
     }
 
@@ -452,31 +452,26 @@ static int qemu_rbd_open(BlockDriverState *bs, const char *filename, int flags)
         r = qemu_rbd_set_conf(s->cluster, conf);
         if (r < 0) {
             error_report("error setting config options");
-            rados_shutdown(s->cluster);
-            return r;
+            goto failed_shutdown;
         }
     }
 
     r = rados_connect(s->cluster);
     if (r < 0) {
         error_report("error connecting");
-        rados_shutdown(s->cluster);
-        return r;
+        goto failed_shutdown;
     }
 
     r = rados_ioctx_create(s->cluster, pool, &s->io_ctx);
     if (r < 0) {
         error_report("error opening pool %s", pool);
-        rados_shutdown(s->cluster);
-        return r;
+        goto failed_shutdown;
     }
 
     r = rbd_open(s->io_ctx, s->name, &s->image, s->snap);
     if (r < 0) {
         error_report("error reading header from %s", s->name);
-        rados_ioctx_destroy(s->io_ctx);
-        rados_shutdown(s->cluster);
-        return r;
+        goto failed_open;
     }
 
     bs->read_only = (s->snap != NULL);
@@ -497,8 +492,11 @@ static int qemu_rbd_open(BlockDriverState *bs, const char *filename, int flags)
 
 failed:
     rbd_close(s->image);
+failed_open:
     rados_ioctx_destroy(s->io_ctx);
+failed_shutdown:
     rados_shutdown(s->cluster);
+    g_free(s->snap);
     return r;
 }
 
commit dfe80b071b6ef6c9c0b4e36191e2fe2d16050766
Author: Sage Weil <sage at newdream.net>
Date:   Wed Sep 7 09:28:05 2011 -0700

    rbd: clean up, fix style
    
    No assignment in condition.  Remove duplicate ret > 0 check.
    
    Signed-off-by: Sage Weil <sage at newdream.net>
    Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/rbd.c b/block/rbd.c
index 6135fc1..2763092 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -391,15 +391,14 @@ static void qemu_rbd_aio_event_reader(void *opaque)
         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;
-                    qemu_rbd_complete_aio(s->event_rcb);
-                    s->qemu_aio_count--;
-                }
+        ret = read(s->fds[RBD_FD_READ], p + s->event_reader_pos,
+                   sizeof(s->event_rcb) - s->event_reader_pos);
+        if (ret > 0) {
+            s->event_reader_pos += ret;
+            if (s->event_reader_pos == sizeof(s->event_rcb)) {
+                s->event_reader_pos = 0;
+                qemu_rbd_complete_aio(s->event_rcb);
+                s->qemu_aio_count--;
             }
         }
     } while (ret < 0 && errno == EINTR);
commit 7c7e9df0232a1ce5c411f0f348038d2e72097ae1
Author: Sage Weil <sage at newdream.net>
Date:   Wed Sep 7 09:28:04 2011 -0700

    rbd: allow client id to be specified in config string
    
    Allow the client id to be specified in the config string via 'id=' so that
    users can control who they authenticate as.  Currently they are stuck with
    the default ('admin').  This is necessary for anyone using authentication
    in their environment.
    
    Signed-off-by: Sage Weil <sage at newdream.net>
    Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/rbd.c b/block/rbd.c
index ce0f6ef..6135fc1 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -169,6 +169,34 @@ done:
     return ret;
 }
 
+static char *qemu_rbd_parse_clientname(const char *conf, char *clientname)
+{
+    const char *p = conf;
+
+    while (*p) {
+        int len;
+        const char *end = strchr(p, ':');
+
+        if (end) {
+            len = end - p;
+        } else {
+            len = strlen(p);
+        }
+
+        if (strncmp(p, "id=", 3) == 0) {
+            len -= 3;
+            strncpy(clientname, p + 3, len);
+            clientname[len] = '\0';
+            return clientname;
+        }
+        if (end == NULL) {
+            break;
+        }
+        p = end + 1;
+    }
+    return NULL;
+}
+
 static int qemu_rbd_set_conf(rados_t cluster, const char *conf)
 {
     char *p, *buf;
@@ -198,17 +226,19 @@ static int qemu_rbd_set_conf(rados_t cluster, const char *conf)
             break;
         }
 
-        if (strcmp(name, "conf")) {
-            ret = rados_conf_set(cluster, name, value);
+        if (strcmp(name, "conf") == 0) {
+            ret = rados_conf_read_file(cluster, value);
             if (ret < 0) {
-                error_report("invalid conf option %s", name);
-                ret = -EINVAL;
+                error_report("error reading conf file %s", value);
                 break;
             }
+        } else if (strcmp(name, "id") == 0) {
+            /* ignore, this is parsed by qemu_rbd_parse_clientname() */
         } else {
-            ret = rados_conf_read_file(cluster, value);
+            ret = rados_conf_set(cluster, name, value);
             if (ret < 0) {
-                error_report("error reading conf file %s", value);
+                error_report("invalid conf option %s", name);
+                ret = -EINVAL;
                 break;
             }
         }
@@ -227,6 +257,8 @@ static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options)
     char name[RBD_MAX_IMAGE_NAME_SIZE];
     char snap_buf[RBD_MAX_SNAP_NAME_SIZE];
     char conf[RBD_MAX_CONF_SIZE];
+    char clientname_buf[RBD_MAX_CONF_SIZE];
+    char *clientname;
     rados_t cluster;
     rados_ioctx_t io_ctx;
     int ret;
@@ -259,7 +291,8 @@ static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options)
         options++;
     }
 
-    if (rados_create(&cluster, NULL) < 0) {
+    clientname = qemu_rbd_parse_clientname(conf, clientname_buf);
+    if (rados_create(&cluster, clientname) < 0) {
         error_report("error initializing");
         return -EIO;
     }
@@ -385,6 +418,8 @@ static int qemu_rbd_open(BlockDriverState *bs, const char *filename, int flags)
     char pool[RBD_MAX_POOL_NAME_SIZE];
     char snap_buf[RBD_MAX_SNAP_NAME_SIZE];
     char conf[RBD_MAX_CONF_SIZE];
+    char clientname_buf[RBD_MAX_CONF_SIZE];
+    char *clientname;
     int r;
 
     if (qemu_rbd_parsename(filename, pool, sizeof(pool),
@@ -398,7 +433,8 @@ static int qemu_rbd_open(BlockDriverState *bs, const char *filename, int flags)
         s->snap = g_strdup(snap_buf);
     }
 
-    r = rados_create(&s->cluster, NULL);
+    clientname = qemu_rbd_parse_clientname(conf, clientname_buf);
+    r = rados_create(&s->cluster, clientname);
     if (r < 0) {
         error_report("error initializing");
         return r;
commit 025e849a50259447aad49a0b45f0133c6a0f5d16
Author: Markus Armbruster <armbru at redhat.com>
Date:   Tue Sep 6 18:58:47 2011 +0200

    block: Rename bdrv_set_locked() to bdrv_lock_medium()
    
    While there, make the locked parameter bool.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index 1e4be73..7225b15 100644
--- a/block.c
+++ b/block.c
@@ -3072,14 +3072,14 @@ void bdrv_eject(BlockDriverState *bs, int eject_flag)
  * Lock or unlock the media (if it is locked, the user won't be able
  * to eject it manually).
  */
-void bdrv_set_locked(BlockDriverState *bs, int locked)
+void bdrv_lock_medium(BlockDriverState *bs, bool locked)
 {
     BlockDriver *drv = bs->drv;
 
-    trace_bdrv_set_locked(bs, locked);
+    trace_bdrv_lock_medium(bs, locked);
 
-    if (drv && drv->bdrv_set_locked) {
-        drv->bdrv_set_locked(bs, locked);
+    if (drv && drv->bdrv_lock_medium) {
+        drv->bdrv_lock_medium(bs, locked);
     }
 }
 
diff --git a/block.h b/block.h
index 396ca0e..4691090 100644
--- a/block.h
+++ b/block.h
@@ -212,7 +212,7 @@ int bdrv_is_sg(BlockDriverState *bs);
 int bdrv_enable_write_cache(BlockDriverState *bs);
 int bdrv_is_inserted(BlockDriverState *bs);
 int bdrv_media_changed(BlockDriverState *bs);
-void bdrv_set_locked(BlockDriverState *bs, int locked);
+void bdrv_lock_medium(BlockDriverState *bs, bool locked);
 void bdrv_eject(BlockDriverState *bs, int eject_flag);
 void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size);
 BlockDriverState *bdrv_find(const char *name);
diff --git a/block/raw-posix.c b/block/raw-posix.c
index bcf50b2..a624f56 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -1362,7 +1362,7 @@ static void cdrom_eject(BlockDriverState *bs, int eject_flag)
     }
 }
 
-static void cdrom_set_locked(BlockDriverState *bs, int locked)
+static void cdrom_lock_medium(BlockDriverState *bs, bool locked)
 {
     BDRVRawState *s = bs->opaque;
 
@@ -1400,7 +1400,7 @@ static BlockDriver bdrv_host_cdrom = {
     /* removable device support */
     .bdrv_is_inserted   = cdrom_is_inserted,
     .bdrv_eject         = cdrom_eject,
-    .bdrv_set_locked    = cdrom_set_locked,
+    .bdrv_lock_medium   = cdrom_lock_medium,
 
     /* generic scsi device */
     .bdrv_ioctl         = hdev_ioctl,
@@ -1481,7 +1481,7 @@ static void cdrom_eject(BlockDriverState *bs, int eject_flag)
     cdrom_reopen(bs);
 }
 
-static void cdrom_set_locked(BlockDriverState *bs, int locked)
+static void cdrom_lock_medium(BlockDriverState *bs, bool locked)
 {
     BDRVRawState *s = bs->opaque;
 
@@ -1521,7 +1521,7 @@ static BlockDriver bdrv_host_cdrom = {
     /* removable device support */
     .bdrv_is_inserted   = cdrom_is_inserted,
     .bdrv_eject         = cdrom_eject,
-    .bdrv_set_locked    = cdrom_set_locked,
+    .bdrv_lock_medium   = cdrom_lock_medium,
 };
 #endif /* __FreeBSD__ */
 
diff --git a/block/raw.c b/block/raw.c
index f197479..63cf2d3 100644
--- a/block/raw.c
+++ b/block/raw.c
@@ -85,9 +85,9 @@ static void raw_eject(BlockDriverState *bs, int eject_flag)
     bdrv_eject(bs->file, eject_flag);
 }
 
-static void raw_set_locked(BlockDriverState *bs, int locked)
+static void raw_lock_medium(BlockDriverState *bs, bool locked)
 {
-    bdrv_set_locked(bs->file, locked);
+    bdrv_lock_medium(bs->file, locked);
 }
 
 static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
@@ -144,7 +144,7 @@ static BlockDriver bdrv_raw = {
     .bdrv_is_inserted   = raw_is_inserted,
     .bdrv_media_changed = raw_media_changed,
     .bdrv_eject         = raw_eject,
-    .bdrv_set_locked    = raw_set_locked,
+    .bdrv_lock_medium   = raw_lock_medium,
 
     .bdrv_ioctl         = raw_ioctl,
     .bdrv_aio_ioctl     = raw_aio_ioctl,
diff --git a/block_int.h b/block_int.h
index 4f7ff3b..f42af2c 100644
--- a/block_int.h
+++ b/block_int.h
@@ -120,7 +120,7 @@ struct BlockDriver {
     int (*bdrv_is_inserted)(BlockDriverState *bs);
     int (*bdrv_media_changed)(BlockDriverState *bs);
     void (*bdrv_eject)(BlockDriverState *bs, int eject_flag);
-    void (*bdrv_set_locked)(BlockDriverState *bs, int locked);
+    void (*bdrv_lock_medium)(BlockDriverState *bs, bool locked);
 
     /* to control generic scsi devices */
     int (*bdrv_ioctl)(BlockDriverState *bs, unsigned long int req, void *buf);
diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c
index afb27c6..06778f3 100644
--- a/hw/ide/atapi.c
+++ b/hw/ide/atapi.c
@@ -833,7 +833,7 @@ static void cmd_test_unit_ready(IDEState *s, uint8_t *buf)
 static void cmd_prevent_allow_medium_removal(IDEState *s, uint8_t* buf)
 {
     s->tray_locked = buf[4] & 1;
-    bdrv_set_locked(s->bs, buf[4] & 1);
+    bdrv_lock_medium(s->bs, buf[4] & 1);
     ide_atapi_cmd_ok(s);
 }
 
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 42682d0..4e89bb1 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -887,7 +887,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
         break;
     case ALLOW_MEDIUM_REMOVAL:
         s->tray_locked = req->cmd.buf[4] & 1;
-        bdrv_set_locked(s->bs, req->cmd.buf[4] & 1);
+        bdrv_lock_medium(s->bs, req->cmd.buf[4] & 1);
         break;
     case READ_CAPACITY_10:
         /* The normal LEN field for this command is zero.  */
diff --git a/trace-events b/trace-events
index a8e7684..8bed3be 100644
--- a/trace-events
+++ b/trace-events
@@ -62,7 +62,7 @@ bdrv_aio_multiwrite_latefail(void *mcb, int i) "mcb %p i %d"
 bdrv_aio_flush(void *bs, void *opaque) "bs %p opaque %p"
 bdrv_aio_readv(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
 bdrv_aio_writev(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
-bdrv_set_locked(void *bs, int locked) "bs %p locked %d"
+bdrv_lock_medium(void *bs, bool locked) "bs %p locked %d"
 bdrv_co_readv(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
 bdrv_co_writev(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
 bdrv_co_io(int is_write, void *acb) "is_write %d acb %p"
commit f107639a6ff0c8d02f6a2dfdfce3a9d9f1e2eb27
Author: Markus Armbruster <armbru at redhat.com>
Date:   Tue Sep 6 18:58:46 2011 +0200

    block: Drop medium lock tracking, ask device models instead
    
    Requires new BlockDevOps member is_medium_locked().  Implement for IDE
    and SCSI CD-ROMs.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index 7408fa9..1e4be73 100644
--- a/block.c
+++ b/block.c
@@ -818,6 +818,14 @@ static void bdrv_dev_resize_cb(BlockDriverState *bs)
     }
 }
 
+bool bdrv_dev_is_medium_locked(BlockDriverState *bs)
+{
+    if (bs->dev_ops && bs->dev_ops->is_medium_locked) {
+        return bs->dev_ops->is_medium_locked(bs->dev_opaque);
+    }
+    return false;
+}
+
 /*
  * Run consistency checks on an image
  *
@@ -1890,7 +1898,7 @@ void bdrv_info(Monitor *mon, QObject **ret_data)
         bs_obj = qobject_from_jsonf("{ 'device': %s, 'type': 'unknown', "
                                     "'removable': %i, 'locked': %i }",
                                     bs->device_name, bs->removable,
-                                    bs->locked);
+                                    bdrv_dev_is_medium_locked(bs));
 
         if (bs->drv) {
             QObject *obj;
@@ -3060,11 +3068,6 @@ void bdrv_eject(BlockDriverState *bs, int eject_flag)
     }
 }
 
-int bdrv_is_locked(BlockDriverState *bs)
-{
-    return bs->locked;
-}
-
 /**
  * Lock or unlock the media (if it is locked, the user won't be able
  * to eject it manually).
@@ -3075,7 +3078,6 @@ void bdrv_set_locked(BlockDriverState *bs, int locked)
 
     trace_bdrv_set_locked(bs, locked);
 
-    bs->locked = locked;
     if (drv && drv->bdrv_set_locked) {
         drv->bdrv_set_locked(bs, locked);
     }
diff --git a/block.h b/block.h
index 5d941e9..396ca0e 100644
--- a/block.h
+++ b/block.h
@@ -37,6 +37,11 @@ typedef struct BlockDevOps {
      */
     void (*change_media_cb)(void *opaque);
     /*
+     * Is the virtual medium locked into the device?
+     * Device models implement this only when device has such a lock.
+     */
+    bool (*is_medium_locked)(void *opaque);
+    /*
      * Runs when the size changed (e.g. monitor command block_resize)
      */
     void (*resize_cb)(void *opaque);
@@ -94,6 +99,7 @@ void bdrv_detach_dev(BlockDriverState *bs, void *dev);
 void *bdrv_get_attached_dev(BlockDriverState *bs);
 void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops,
                       void *opaque);
+bool bdrv_dev_is_medium_locked(BlockDriverState *bs);
 int bdrv_read(BlockDriverState *bs, int64_t sector_num,
               uint8_t *buf, int nb_sectors);
 int bdrv_write(BlockDriverState *bs, int64_t sector_num,
@@ -206,7 +212,6 @@ int bdrv_is_sg(BlockDriverState *bs);
 int bdrv_enable_write_cache(BlockDriverState *bs);
 int bdrv_is_inserted(BlockDriverState *bs);
 int bdrv_media_changed(BlockDriverState *bs);
-int bdrv_is_locked(BlockDriverState *bs);
 void bdrv_set_locked(BlockDriverState *bs, int locked);
 void bdrv_eject(BlockDriverState *bs, int eject_flag);
 void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size);
diff --git a/block_int.h b/block_int.h
index b63c57b..4f7ff3b 100644
--- a/block_int.h
+++ b/block_int.h
@@ -156,7 +156,6 @@ struct BlockDriverState {
     int keep_read_only; /* if true, the media was requested to stay read only */
     int open_flags; /* flags used to open the file, re-used for re-open */
     int removable; /* if true, the media can be removed */
-    int locked;    /* if true, the media cannot temporarily be ejected */
     int encrypted; /* if true, the media is encrypted */
     int valid_key; /* if true, a valid encryption key has been set */
     int sg;        /* if true, the device is a /dev/sg* */
diff --git a/blockdev.c b/blockdev.c
index 049dda5..3f00b2e 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -640,7 +640,7 @@ static int eject_device(Monitor *mon, BlockDriverState *bs, int force)
         qerror_report(QERR_DEVICE_NOT_REMOVABLE, bdrv_get_device_name(bs));
         return -1;
     }
-    if (!force && bdrv_is_locked(bs)) {
+    if (!force && bdrv_dev_is_medium_locked(bs)) {
         qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
         return -1;
     }
diff --git a/hw/ide/core.c b/hw/ide/core.c
index b33f84e..0403ad2 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -1795,8 +1795,14 @@ void ide_bus_reset(IDEBus *bus)
     bus->dma->ops->reset(bus->dma);
 }
 
+static bool ide_cd_is_medium_locked(void *opaque)
+{
+    return ((IDEState *)opaque)->tray_locked;
+}
+
 static const BlockDevOps ide_cd_block_ops = {
     .change_media_cb = ide_cd_change_cb,
+    .is_medium_locked = ide_cd_is_medium_locked,
 };
 
 int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 65783a7..42682d0 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -1165,6 +1165,15 @@ static void scsi_destroy(SCSIDevice *dev)
     blockdev_mark_auto_del(s->qdev.conf.bs);
 }
 
+static bool scsi_cd_is_medium_locked(void *opaque)
+{
+    return ((SCSIDiskState *)opaque)->tray_locked;
+}
+
+static const BlockDevOps scsi_cd_block_ops = {
+    .is_medium_locked = scsi_cd_is_medium_locked,
+};
+
 static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
 {
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
@@ -1199,6 +1208,7 @@ static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
     }
 
     if (scsi_type == TYPE_ROM) {
+        bdrv_set_dev_ops(s->bs, &scsi_cd_block_ops, s);
         s->qdev.blocksize = 2048;
     } else if (scsi_type == TYPE_DISK) {
         s->qdev.blocksize = s->qdev.conf.logical_block_size;
commit fdec4404ddfaf9e121bef84eac1303a8a0e47d75
Author: Markus Armbruster <armbru at redhat.com>
Date:   Tue Sep 6 18:58:45 2011 +0200

    block: Leave enforcing tray lock to device models
    
    The device model knows best when to accept the guest's eject command.
    No need to detour through the block layer.
    
    bdrv_eject() can't fail anymore.  Make it void.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index 8c86251..7408fa9 100644
--- a/block.c
+++ b/block.c
@@ -3051,18 +3051,13 @@ int bdrv_media_changed(BlockDriverState *bs)
 /**
  * If eject_flag is TRUE, eject the media. Otherwise, close the tray
  */
-int bdrv_eject(BlockDriverState *bs, int eject_flag)
+void bdrv_eject(BlockDriverState *bs, int eject_flag)
 {
     BlockDriver *drv = bs->drv;
 
-    if (eject_flag && bs->locked) {
-        return -EBUSY;
-    }
-
     if (drv && drv->bdrv_eject) {
         drv->bdrv_eject(bs, eject_flag);
     }
-    return 0;
 }
 
 int bdrv_is_locked(BlockDriverState *bs)
diff --git a/block.h b/block.h
index 8ec409f..5d941e9 100644
--- a/block.h
+++ b/block.h
@@ -208,7 +208,7 @@ int bdrv_is_inserted(BlockDriverState *bs);
 int bdrv_media_changed(BlockDriverState *bs);
 int bdrv_is_locked(BlockDriverState *bs);
 void bdrv_set_locked(BlockDriverState *bs, int locked);
-int bdrv_eject(BlockDriverState *bs, int eject_flag);
+void bdrv_eject(BlockDriverState *bs, int eject_flag);
 void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size);
 BlockDriverState *bdrv_find(const char *name);
 BlockDriverState *bdrv_next(BlockDriverState *bs);
diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c
index d9db6de..afb27c6 100644
--- a/hw/ide/atapi.c
+++ b/hw/ide/atapi.c
@@ -905,33 +905,22 @@ static void cmd_seek(IDEState *s, uint8_t* buf)
 
 static void cmd_start_stop_unit(IDEState *s, uint8_t* buf)
 {
-    int sense, err = 0;
+    int sense;
     bool start = buf[4] & 1;
     bool loej = buf[4] & 2;     /* load on start, eject on !start */
 
     if (loej) {
-        err = bdrv_eject(s->bs, !start);
-    }
-
-    switch (err) {
-    case 0:
-        ide_atapi_cmd_ok(s);
-        break;
-    case -EBUSY:
-        sense = SENSE_NOT_READY;
-        if (bdrv_is_inserted(s->bs)) {
-            sense = SENSE_ILLEGAL_REQUEST;
+        if (!start && s->tray_locked) {
+            sense = bdrv_is_inserted(s->bs)
+                ? SENSE_NOT_READY : SENSE_ILLEGAL_REQUEST;
+            ide_atapi_cmd_error(s, sense, ASC_MEDIA_REMOVAL_PREVENTED);
+            return;
         }
-        ide_atapi_cmd_error(s, sense, ASC_MEDIA_REMOVAL_PREVENTED);
-        break;
-    default:
-        ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
-        break;
-    }
-
-    if (loej && !err) {
+        bdrv_eject(s->bs, !start);
         s->tray_open = !start;
     }
+
+    ide_atapi_cmd_ok(s);
 }
 
 static void cmd_mechanism_status(IDEState *s, uint8_t* buf)
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index e7358e3..65783a7 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -830,6 +830,9 @@ static void scsi_disk_emulate_start_stop(SCSIDiskReq *r)
     bool loej = req->cmd.buf[4] & 2; /* load on start, eject on !start */
 
     if (s->qdev.type == TYPE_ROM && loej) {
+        if (!start && s->tray_locked) {
+            return;
+        }
         bdrv_eject(s->bs, !start);
         s->tray_open = !start;
     }
commit 81b1008d50829fdcbe79aa67fa1113bb00a787d6
Author: Markus Armbruster <armbru at redhat.com>
Date:   Tue Sep 6 18:58:44 2011 +0200

    scsi-disk: Track tray locked state
    
    We already track it in BlockDriverState.  Just like tray open/close
    state, we should track it in the device models instead, because it's
    device state.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index f35ada4..e7358e3 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -73,6 +73,7 @@ struct SCSIDiskState
     char *version;
     char *serial;
     bool tray_open;
+    bool tray_locked;
 };
 
 static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type);
@@ -671,7 +672,7 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
         p[5] = 0xff; /* CD DA, DA accurate, RW supported,
                         RW corrected, C2 errors, ISRC,
                         UPC, Bar code */
-        p[6] = 0x2d | (bdrv_is_locked(s->bs)? 2 : 0);
+        p[6] = 0x2d | (s->tray_locked ? 2 : 0);
         /* Locking supported, jumper present, eject, tray */
         p[7] = 0; /* no volume & mute control, no
                      changer */
@@ -882,6 +883,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
         scsi_disk_emulate_start_stop(r);
         break;
     case ALLOW_MEDIUM_REMOVAL:
+        s->tray_locked = req->cmd.buf[4] & 1;
         bdrv_set_locked(s->bs, req->cmd.buf[4] & 1);
         break;
     case READ_CAPACITY_10:
commit a0a7573b846ae9b346a34f10c4fe4e317b9eebfd
Author: Markus Armbruster <armbru at redhat.com>
Date:   Tue Sep 6 18:58:43 2011 +0200

    ide/atapi: Track tray locked state
    
    We already track it in BlockDriverState.  Just like tray open/close
    state, we should track it in the device models instead, because it's
    device state.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c
index 0943f66..d9db6de 100644
--- a/hw/ide/atapi.c
+++ b/hw/ide/atapi.c
@@ -788,8 +788,9 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
             buf[12] = 0x71;
             buf[13] = 3 << 5;
             buf[14] = (1 << 0) | (1 << 3) | (1 << 5);
-            if (bdrv_is_locked(s->bs))
+            if (s->tray_locked) {
                 buf[6] |= 1 << 1;
+            }
             buf[15] = 0x00;
             cpu_to_ube16(&buf[16], 706);
             buf[18] = 0;
@@ -831,6 +832,7 @@ static void cmd_test_unit_ready(IDEState *s, uint8_t *buf)
 
 static void cmd_prevent_allow_medium_removal(IDEState *s, uint8_t* buf)
 {
+    s->tray_locked = buf[4] & 1;
     bdrv_set_locked(s->bs, buf[4] & 1);
     ide_atapi_cmd_ok(s);
 }
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index 8a9052e..663db39 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -443,6 +443,7 @@ struct IDEState {
     uint8_t sense_key;
     uint8_t asc;
     bool tray_open;
+    bool tray_locked;
     uint8_t cdrom_changed;
     int packet_transfer_size;
     int elementary_transfer_size;
commit 22cf56c4d81935bf89a30c2dc0296c1f14199518
Author: Markus Armbruster <armbru at redhat.com>
Date:   Tue Sep 6 18:58:42 2011 +0200

    block: Drop tray status tracking, no longer used
    
    Commit 4be9762a is now completely redone.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index 6fe8add..8c86251 100644
--- a/block.c
+++ b/block.c
@@ -3062,7 +3062,6 @@ int bdrv_eject(BlockDriverState *bs, int eject_flag)
     if (drv && drv->bdrv_eject) {
         drv->bdrv_eject(bs, eject_flag);
     }
-    bs->tray_open = eject_flag;
     return 0;
 }
 
diff --git a/block_int.h b/block_int.h
index 5dc0074..b63c57b 100644
--- a/block_int.h
+++ b/block_int.h
@@ -157,7 +157,6 @@ struct BlockDriverState {
     int open_flags; /* flags used to open the file, re-used for re-open */
     int removable; /* if true, the media can be removed */
     int locked;    /* if true, the media cannot temporarily be ejected */
-    int tray_open; /* if true, the virtual tray is open */
     int encrypted; /* if true, the media is encrypted */
     int valid_key; /* if true, a valid encryption key has been set */
     int sg;        /* if true, the device is a /dev/sg* */
commit a1aff5bf6786e6e8478373e4ada869a4ef2a7fc4
Author: Markus Armbruster <armbru at redhat.com>
Date:   Tue Sep 6 18:58:41 2011 +0200

    block: Revert entanglement of bdrv_is_inserted() with tray status
    
    Commit 4be9762a changed bdrv_is_inserted() to fail when the tray is
    open.  Unfortunately, there are two different kinds of users, with
    conflicting needs.
    
    1. Device models using bdrv_eject(), currently ide-cd and scsi-cd.
    They expect bdrv_is_inserted() to reflect the tray status.  Commit
    4be9762a makes them happy.
    
    2. Code that wants to know whether a BlockDriverState has media, such
    as find_image_format(), bdrv_flush_all().  Commit 4be9762a makes them
    unhappy.  In particular, it breaks flush on VM stop for media ejected
    by the guest.
    
    Revert the change to bdrv_is_inserted().  Check the tray status in the
    device models instead.
    
    Note on IDE: Since only ATAPI devices have a tray, and they don't
    accept ATA commands since the recent commit "ide: Reject ATA commands
    specific to drive kinds", checking in atapi.c suffices.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index a8c789a..6fe8add 100644
--- a/block.c
+++ b/block.c
@@ -3026,13 +3026,12 @@ static int coroutine_fn bdrv_co_flush_em(BlockDriverState *bs)
 int bdrv_is_inserted(BlockDriverState *bs)
 {
     BlockDriver *drv = bs->drv;
-    int ret;
+
     if (!drv)
         return 0;
     if (!drv->bdrv_is_inserted)
-        return !bs->tray_open;
-    ret = drv->bdrv_is_inserted(bs);
-    return ret;
+        return 1;
+    return drv->bdrv_is_inserted(bs);
 }
 
 /**
diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c
index 713b1fd..0943f66 100644
--- a/hw/ide/atapi.c
+++ b/hw/ide/atapi.c
@@ -73,7 +73,7 @@ static void lba_to_msf(uint8_t *buf, int lba)
 
 static inline int media_present(IDEState *s)
 {
-    return (s->nb_sectors > 0);
+    return !s->tray_open && s->nb_sectors > 0;
 }
 
 /* XXX: DVDs that could fit on a CD will be reported as a CD */
@@ -1077,20 +1077,21 @@ static const struct {
     [ 0x03 ] = { cmd_request_sense,                 ALLOW_UA },
     [ 0x12 ] = { cmd_inquiry,                       ALLOW_UA },
     [ 0x1a ] = { cmd_mode_sense, /* (6) */          0 },
-    [ 0x1b ] = { cmd_start_stop_unit,               0 },
+    [ 0x1b ] = { cmd_start_stop_unit,               0 }, /* [1] */
     [ 0x1e ] = { cmd_prevent_allow_medium_removal,  0 },
     [ 0x25 ] = { cmd_read_cdvd_capacity,            CHECK_READY },
-    [ 0x28 ] = { cmd_read, /* (10) */               0 },
+    [ 0x28 ] = { cmd_read, /* (10) */               CHECK_READY },
     [ 0x2b ] = { cmd_seek,                          CHECK_READY },
     [ 0x43 ] = { cmd_read_toc_pma_atip,             CHECK_READY },
     [ 0x46 ] = { cmd_get_configuration,             ALLOW_UA },
     [ 0x4a ] = { cmd_get_event_status_notification, ALLOW_UA },
     [ 0x5a ] = { cmd_mode_sense, /* (10) */         0 },
-    [ 0xa8 ] = { cmd_read, /* (12) */               0 },
-    [ 0xad ] = { cmd_read_dvd_structure,            0 },
+    [ 0xa8 ] = { cmd_read, /* (12) */               CHECK_READY },
+    [ 0xad ] = { cmd_read_dvd_structure,            CHECK_READY },
     [ 0xbb ] = { cmd_set_speed,                     0 },
     [ 0xbd ] = { cmd_mechanism_status,              0 },
-    [ 0xbe ] = { cmd_read_cd,                       0 },
+    [ 0xbe ] = { cmd_read_cd,                       CHECK_READY },
+    /* [1] handler detects and reports not ready condition itself */
 };
 
 void ide_atapi_cmd(IDEState *s)
@@ -1126,7 +1127,7 @@ void ide_atapi_cmd(IDEState *s)
      * GET_EVENT_STATUS_NOTIFICATION to detect such tray open/close
      * states rely on this behavior.
      */
-    if (bdrv_is_inserted(s->bs) && s->cdrom_changed) {
+    if (!s->tray_open && bdrv_is_inserted(s->bs) && s->cdrom_changed) {
         ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
 
         s->cdrom_changed = 0;
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index f18ddd7..f35ada4 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -183,6 +183,9 @@ static void scsi_read_data(SCSIRequest *req)
     if (n > SCSI_DMA_BUF_SIZE / 512)
         n = SCSI_DMA_BUF_SIZE / 512;
 
+    if (s->tray_open) {
+        scsi_read_complete(r, -ENOMEDIUM);
+    }
     r->iov.iov_len = n * 512;
     qemu_iovec_init_external(&r->qiov, &r->iov, 1);
 
@@ -281,6 +284,9 @@ static void scsi_write_data(SCSIRequest *req)
 
     n = r->iov.iov_len / 512;
     if (n) {
+        if (s->tray_open) {
+            scsi_write_complete(r, -ENOMEDIUM);
+        }
         qemu_iovec_init_external(&r->qiov, &r->iov, 1);
 
         bdrv_acct_start(s->bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_WRITE);
@@ -837,7 +843,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
 
     switch (req->cmd.buf[0]) {
     case TEST_UNIT_READY:
-        if (!bdrv_is_inserted(s->bs))
+        if (s->tray_open || !bdrv_is_inserted(s->bs))
             goto not_ready;
         break;
     case INQUIRY:
@@ -957,7 +963,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
     return buflen;
 
 not_ready:
-    if (!bdrv_is_inserted(s->bs)) {
+    if (s->tray_open || !bdrv_is_inserted(s->bs)) {
         scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
     } else {
         scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY));
commit ece0d5e9a736df174509751980ca0613a778f8b4
Author: Markus Armbruster <armbru at redhat.com>
Date:   Tue Sep 6 18:58:40 2011 +0200

    scsi-disk: Track tray open/close state
    
    We already track it in BlockDriverState since commit 4be9762a.  As
    discussed in that commit's message, we should track it in the device
    device models instead, because it's device state.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index c8ad2e7..f18ddd7 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -72,6 +72,7 @@ struct SCSIDiskState
     QEMUBH *bh;
     char *version;
     char *serial;
+    bool tray_open;
 };
 
 static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type);
@@ -823,6 +824,7 @@ static void scsi_disk_emulate_start_stop(SCSIDiskReq *r)
 
     if (s->qdev.type == TYPE_ROM && loej) {
         bdrv_eject(s->bs, !start);
+        s->tray_open = !start;
     }
 }
 
commit bfd52647adc17ec05b708e2a061f85707cbe4dcc
Author: Markus Armbruster <armbru at redhat.com>
Date:   Tue Sep 6 18:58:39 2011 +0200

    scsi-disk: Factor out scsi_disk_emulate_start_stop()
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 9724d0f..c8ad2e7 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -814,6 +814,18 @@ static int scsi_disk_emulate_read_toc(SCSIRequest *req, uint8_t *outbuf)
     return toclen;
 }
 
+static void scsi_disk_emulate_start_stop(SCSIDiskReq *r)
+{
+    SCSIRequest *req = &r->req;
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
+    bool start = req->cmd.buf[4] & 1;
+    bool loej = req->cmd.buf[4] & 2; /* load on start, eject on !start */
+
+    if (s->qdev.type == TYPE_ROM && loej) {
+        bdrv_eject(s->bs, !start);
+    }
+}
+
 static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
 {
     SCSIRequest *req = &r->req;
@@ -859,10 +871,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
             goto illegal_request;
         break;
     case START_STOP:
-        if (s->qdev.type == TYPE_ROM && (req->cmd.buf[4] & 2)) {
-            /* load/eject medium */
-            bdrv_eject(s->bs, !(req->cmd.buf[4] & 1));
-        }
+        scsi_disk_emulate_start_stop(r);
         break;
     case ALLOW_MEDIUM_REMOVAL:
         bdrv_set_locked(s->bs, req->cmd.buf[4] & 1);
commit dd063333929f2e2a44dc900aa4f75f11dea7cb28
Author: Markus Armbruster <armbru at redhat.com>
Date:   Tue Sep 6 18:58:38 2011 +0200

    ide/atapi: Track tray open/close state
    
    We already track it in BlockDriverState since commit 4be9762a.  As
    discussed in that commit's message, we should track it in the device
    device models instead, because it's device state.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c
index cb0cdac..713b1fd 100644
--- a/hw/ide/atapi.c
+++ b/hw/ide/atapi.c
@@ -521,7 +521,7 @@ static unsigned int event_status_media(IDEState *s,
     uint8_t event_code, media_status;
 
     media_status = 0;
-    if (s->bs->tray_open) {
+    if (s->tray_open) {
         media_status = MS_TRAY_OPEN;
     } else if (bdrv_is_inserted(s->bs)) {
         media_status = MS_MEDIA_PRESENT;
@@ -926,6 +926,10 @@ static void cmd_start_stop_unit(IDEState *s, uint8_t* buf)
         ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
         break;
     }
+
+    if (loej && !err) {
+        s->tray_open = !start;
+    }
 }
 
 static void cmd_mechanism_status(IDEState *s, uint8_t* buf)
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index 1117852..8a9052e 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -442,6 +442,7 @@ struct IDEState {
     struct unreported_events events;
     uint8_t sense_key;
     uint8_t asc;
+    bool tray_open;
     uint8_t cdrom_changed;
     int packet_transfer_size;
     int elementary_transfer_size;
commit f0776564182c37362f070b84b5fc63c2a944df6e
Author: Markus Armbruster <armbru at redhat.com>
Date:   Tue Sep 6 18:58:37 2011 +0200

    ide/atapi: Clean up misleading name in cmd_start_stop_unit()
    
    "eject" is misleading; it means "eject" when start is clear, but
    "load" when start is set.  Rename to loej, because that's how MMC-5
    calls it, in section 6.40.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c
index f38d289..cb0cdac 100644
--- a/hw/ide/atapi.c
+++ b/hw/ide/atapi.c
@@ -903,11 +903,11 @@ static void cmd_seek(IDEState *s, uint8_t* buf)
 
 static void cmd_start_stop_unit(IDEState *s, uint8_t* buf)
 {
-    int start, eject, sense, err = 0;
-    start = buf[4] & 1;
-    eject = (buf[4] >> 1) & 1;
+    int sense, err = 0;
+    bool start = buf[4] & 1;
+    bool loej = buf[4] & 2;     /* load on start, eject on !start */
 
-    if (eject) {
+    if (loej) {
         err = bdrv_eject(s->bs, !start);
     }
 
commit 3cfc22692ec3a60affbd8e39da75fa449cefe234
Author: Markus Armbruster <armbru at redhat.com>
Date:   Tue Sep 6 18:58:36 2011 +0200

    ide: Reject ATA commands specific to drive kinds
    
    ACS-2 Table B.2 explicitly prohibits ATAPI devices from implementing
    WIN_RECAL, WIN_READ_EXT, WIN_READDMA_EXT, WIN_READ_NATIVE_MAX,
    WIN_MULTREAD_EXT, WIN_WRITE, WIN_WRITE_ONCE, WIN_WRITE_EXT,
    WIN_WRITEDMA_EXT, WIN_MULTWRITE_EXT, WIN_WRITE_VERIFY, WIN_VERIFY,
    WIN_VERIFY_ONCE, WIN_VERIFY_EXT, WIN_SPECIFY, WIN_MULTREAD,
    WIN_MULTWRITE, WIN_SETMULT, WIN_READDMA, WIN_READDMA_ONCE,
    WIN_WRITEDMA, WIN_WRITEDMA_ONCE, WIN_FLUSH_CACHE_EXT.  Restrict them
    to IDE_HD and IDE_CFATA.
    
    Same for CFA_WRITE_SECT_WO_ERASE, CFA_WRITE_MULTI_WO_ERASE.  Restrict
    them to IDE_CFATA, like the other CFA_ commands.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/ide/core.c b/hw/ide/core.c
index 4a45b3e..b33f84e 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -913,27 +913,27 @@ static const uint8_t ide_cmd_table[0x100] = {
     [CFA_REQ_EXT_ERROR_CODE]            = CFA_OK,
     [WIN_DSM]                           = ALL_OK,
     [WIN_DEVICE_RESET]                  = CD_OK,
-    [WIN_RECAL]                         = ALL_OK,
+    [WIN_RECAL]                         = HD_CFA_OK,
     [WIN_READ]                          = ALL_OK,
     [WIN_READ_ONCE]                     = ALL_OK,
-    [WIN_READ_EXT]                      = ALL_OK,
-    [WIN_READDMA_EXT]                   = ALL_OK,
-    [WIN_READ_NATIVE_MAX_EXT]           = ALL_OK,
-    [WIN_MULTREAD_EXT]                  = ALL_OK,
-    [WIN_WRITE]                         = ALL_OK,
-    [WIN_WRITE_ONCE]                    = ALL_OK,
-    [WIN_WRITE_EXT]                     = ALL_OK,
-    [WIN_WRITEDMA_EXT]                  = ALL_OK,
-    [CFA_WRITE_SECT_WO_ERASE]           = ALL_OK,
-    [WIN_MULTWRITE_EXT]                 = ALL_OK,
-    [WIN_WRITE_VERIFY]                  = ALL_OK,
-    [WIN_VERIFY]                        = ALL_OK,
-    [WIN_VERIFY_ONCE]                   = ALL_OK,
-    [WIN_VERIFY_EXT]                    = ALL_OK,
+    [WIN_READ_EXT]                      = HD_CFA_OK,
+    [WIN_READDMA_EXT]                   = HD_CFA_OK,
+    [WIN_READ_NATIVE_MAX_EXT]           = HD_CFA_OK,
+    [WIN_MULTREAD_EXT]                  = HD_CFA_OK,
+    [WIN_WRITE]                         = HD_CFA_OK,
+    [WIN_WRITE_ONCE]                    = HD_CFA_OK,
+    [WIN_WRITE_EXT]                     = HD_CFA_OK,
+    [WIN_WRITEDMA_EXT]                  = HD_CFA_OK,
+    [CFA_WRITE_SECT_WO_ERASE]           = CFA_OK,
+    [WIN_MULTWRITE_EXT]                 = HD_CFA_OK,
+    [WIN_WRITE_VERIFY]                  = HD_CFA_OK,
+    [WIN_VERIFY]                        = HD_CFA_OK,
+    [WIN_VERIFY_ONCE]                   = HD_CFA_OK,
+    [WIN_VERIFY_EXT]                    = HD_CFA_OK,
     [WIN_SEEK]                          = HD_CFA_OK,
     [CFA_TRANSLATE_SECTOR]              = CFA_OK,
     [WIN_DIAGNOSE]                      = ALL_OK,
-    [WIN_SPECIFY]                       = ALL_OK,
+    [WIN_SPECIFY]                       = HD_CFA_OK,
     [WIN_STANDBYNOW2]                   = ALL_OK,
     [WIN_IDLEIMMEDIATE2]                = ALL_OK,
     [WIN_STANDBY2]                      = ALL_OK,
@@ -945,14 +945,14 @@ static const uint8_t ide_cmd_table[0x100] = {
     [WIN_SMART]                         = HD_CFA_OK,
     [CFA_ACCESS_METADATA_STORAGE]       = CFA_OK,
     [CFA_ERASE_SECTORS]                 = CFA_OK,
-    [WIN_MULTREAD]                      = ALL_OK,
-    [WIN_MULTWRITE]                     = ALL_OK,
-    [WIN_SETMULT]                       = ALL_OK,
-    [WIN_READDMA]                       = ALL_OK,
-    [WIN_READDMA_ONCE]                  = ALL_OK,
-    [WIN_WRITEDMA]                      = ALL_OK,
-    [WIN_WRITEDMA_ONCE]                 = ALL_OK,
-    [CFA_WRITE_MULTI_WO_ERASE]          = ALL_OK,
+    [WIN_MULTREAD]                      = HD_CFA_OK,
+    [WIN_MULTWRITE]                     = HD_CFA_OK,
+    [WIN_SETMULT]                       = HD_CFA_OK,
+    [WIN_READDMA]                       = HD_CFA_OK,
+    [WIN_READDMA_ONCE]                  = HD_CFA_OK,
+    [WIN_WRITEDMA]                      = HD_CFA_OK,
+    [WIN_WRITEDMA_ONCE]                 = HD_CFA_OK,
+    [CFA_WRITE_MULTI_WO_ERASE]          = CFA_OK,
     [WIN_STANDBYNOW1]                   = ALL_OK,
     [WIN_IDLEIMMEDIATE]                 = ALL_OK,
     [WIN_STANDBY]                       = ALL_OK,
@@ -960,7 +960,7 @@ static const uint8_t ide_cmd_table[0x100] = {
     [WIN_CHECKPOWERMODE1]               = ALL_OK,
     [WIN_SLEEPNOW1]                     = ALL_OK,
     [WIN_FLUSH_CACHE]                   = ALL_OK,
-    [WIN_FLUSH_CACHE_EXT]               = ALL_OK,
+    [WIN_FLUSH_CACHE_EXT]               = HD_CFA_OK,
     [WIN_IDENTIFY]                      = ALL_OK,
     [WIN_SETFEATURES]                   = ALL_OK,
     [IBM_SENSE_CONDITION]               = CFA_OK,
commit 844505b12e722d9ba7060480e766351fc6313501
Author: Markus Armbruster <armbru at redhat.com>
Date:   Tue Sep 6 18:58:35 2011 +0200

    ide: Use a table to declare which drive kinds accept each command
    
    No functional change.
    
    It would be nice to have handler functions in the table, like commit
    e1a064f9 did for ATAPI.  Left for another day.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/ide/core.c b/hw/ide/core.c
index def0126..4a45b3e 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -901,6 +901,78 @@ void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
     }
 }
 
+#define HD_OK (1u << IDE_HD)
+#define CD_OK (1u << IDE_CD)
+#define CFA_OK (1u << IDE_CFATA)
+#define HD_CFA_OK (HD_OK | CFA_OK)
+#define ALL_OK (HD_OK | CD_OK | CFA_OK)
+
+/* See ACS-2 T13/2015-D Table B.2 Command codes */
+static const uint8_t ide_cmd_table[0x100] = {
+    /* NOP not implemented, mandatory for CD */
+    [CFA_REQ_EXT_ERROR_CODE]            = CFA_OK,
+    [WIN_DSM]                           = ALL_OK,
+    [WIN_DEVICE_RESET]                  = CD_OK,
+    [WIN_RECAL]                         = ALL_OK,
+    [WIN_READ]                          = ALL_OK,
+    [WIN_READ_ONCE]                     = ALL_OK,
+    [WIN_READ_EXT]                      = ALL_OK,
+    [WIN_READDMA_EXT]                   = ALL_OK,
+    [WIN_READ_NATIVE_MAX_EXT]           = ALL_OK,
+    [WIN_MULTREAD_EXT]                  = ALL_OK,
+    [WIN_WRITE]                         = ALL_OK,
+    [WIN_WRITE_ONCE]                    = ALL_OK,
+    [WIN_WRITE_EXT]                     = ALL_OK,
+    [WIN_WRITEDMA_EXT]                  = ALL_OK,
+    [CFA_WRITE_SECT_WO_ERASE]           = ALL_OK,
+    [WIN_MULTWRITE_EXT]                 = ALL_OK,
+    [WIN_WRITE_VERIFY]                  = ALL_OK,
+    [WIN_VERIFY]                        = ALL_OK,
+    [WIN_VERIFY_ONCE]                   = ALL_OK,
+    [WIN_VERIFY_EXT]                    = ALL_OK,
+    [WIN_SEEK]                          = HD_CFA_OK,
+    [CFA_TRANSLATE_SECTOR]              = CFA_OK,
+    [WIN_DIAGNOSE]                      = ALL_OK,
+    [WIN_SPECIFY]                       = ALL_OK,
+    [WIN_STANDBYNOW2]                   = ALL_OK,
+    [WIN_IDLEIMMEDIATE2]                = ALL_OK,
+    [WIN_STANDBY2]                      = ALL_OK,
+    [WIN_SETIDLE2]                      = ALL_OK,
+    [WIN_CHECKPOWERMODE2]               = ALL_OK,
+    [WIN_SLEEPNOW2]                     = ALL_OK,
+    [WIN_PACKETCMD]                     = CD_OK,
+    [WIN_PIDENTIFY]                     = CD_OK,
+    [WIN_SMART]                         = HD_CFA_OK,
+    [CFA_ACCESS_METADATA_STORAGE]       = CFA_OK,
+    [CFA_ERASE_SECTORS]                 = CFA_OK,
+    [WIN_MULTREAD]                      = ALL_OK,
+    [WIN_MULTWRITE]                     = ALL_OK,
+    [WIN_SETMULT]                       = ALL_OK,
+    [WIN_READDMA]                       = ALL_OK,
+    [WIN_READDMA_ONCE]                  = ALL_OK,
+    [WIN_WRITEDMA]                      = ALL_OK,
+    [WIN_WRITEDMA_ONCE]                 = ALL_OK,
+    [CFA_WRITE_MULTI_WO_ERASE]          = ALL_OK,
+    [WIN_STANDBYNOW1]                   = ALL_OK,
+    [WIN_IDLEIMMEDIATE]                 = ALL_OK,
+    [WIN_STANDBY]                       = ALL_OK,
+    [WIN_SETIDLE1]                      = ALL_OK,
+    [WIN_CHECKPOWERMODE1]               = ALL_OK,
+    [WIN_SLEEPNOW1]                     = ALL_OK,
+    [WIN_FLUSH_CACHE]                   = ALL_OK,
+    [WIN_FLUSH_CACHE_EXT]               = ALL_OK,
+    [WIN_IDENTIFY]                      = ALL_OK,
+    [WIN_SETFEATURES]                   = ALL_OK,
+    [IBM_SENSE_CONDITION]               = CFA_OK,
+    [CFA_WEAR_LEVEL]                    = CFA_OK,
+    [WIN_READ_NATIVE_MAX]               = ALL_OK,
+};
+
+static bool ide_cmd_permitted(IDEState *s, uint32_t cmd)
+{
+    return cmd < ARRAY_SIZE(ide_cmd_table)
+        && (ide_cmd_table[cmd] & (1u << s->drive_kind));
+}
 
 void ide_exec_cmd(IDEBus *bus, uint32_t val)
 {
@@ -920,6 +992,10 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
     if ((s->status & (BUSY_STAT|DRQ_STAT)) && val != WIN_DEVICE_RESET)
         return;
 
+    if (!ide_cmd_permitted(s, val)) {
+        goto abort_cmd;
+    }
+
     switch(val) {
     case WIN_DSM:
         switch (s->feature) {
@@ -1140,21 +1216,15 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
         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_atapi_identify(s);
+        s->status = READY_STAT | SEEK_STAT;
+        ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);
         ide_set_irq(s->bus);
         break;
     case WIN_DIAGNOSE:
@@ -1171,15 +1241,11 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
         ide_set_irq(s->bus);
         break;
     case WIN_DEVICE_RESET:
-        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;
@@ -1191,16 +1257,12 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
         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)
@@ -1210,8 +1272,6 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
         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);
@@ -1230,8 +1290,6 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
         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);
@@ -1250,8 +1308,6 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
         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 */
@@ -1264,8 +1320,6 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
         break;
 
     case WIN_SMART:
-	if (s->drive_kind == IDE_CD)
-		goto abort_cmd;
 	if (s->hcyl != 0xc2 || s->lcyl != 0x4f)
 		goto abort_cmd;
 	if (!s->smart_enabled && s->feature != SMART_ENABLE)
@@ -1420,6 +1474,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
 	}
 	break;
     default:
+        /* should not be reachable */
     abort_cmd:
         ide_abort_command(s);
         ide_set_irq(s->bus);
commit 3f76a7c3815716d21b9932b892825309bf477ee8
Author: Markus Armbruster <armbru at redhat.com>
Date:   Tue Sep 6 18:58:34 2011 +0200

    ide: Fix ATA command READ to set ATAPI signature for CD-ROM
    
    Must set the ATAPI device signature, see ATA4 8.27.5.2 Outputs for
    PACKET Command feature set devices, and ACS-2 7.36.6 Outputs for
    PACKET feature set devices.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/ide/core.c b/hw/ide/core.c
index 1806e00..def0126 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -983,8 +983,10 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
 	lba48 = 1;
     case WIN_READ:
     case WIN_READ_ONCE:
-        if (!s->bs)
+        if (s->drive_kind == IDE_CD) {
+            ide_set_signature(s); /* odd, but ATA4 8.27.5.2 requires it */
             goto abort_cmd;
+        }
 	ide_cmd_lba48_transform(s, lba48);
         s->req_nb_sectors = 1;
         ide_sector_read(s);
commit a7912369929f91aaf42a88b3a0a80f106a681bf4
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Wed Sep 7 16:19:17 2011 +0200

    qcow2: removed unused depends_on field
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index e06be64..113db8b 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -694,7 +694,7 @@ err:
  * If the offset is not found, allocate a new cluster.
  *
  * If the cluster was already allocated, m->nb_clusters is set to 0,
- * m->depends_on is set to NULL and the other fields in m are meaningless.
+ * other fields in m are meaningless.
  *
  * If the cluster is newly allocated, m->nb_clusters is set to the number of
  * contiguous clusters that have been allocated. In this case, the other
@@ -736,7 +736,6 @@ again:
 
         cluster_offset &= ~QCOW_OFLAG_COPIED;
         m->nb_clusters = 0;
-        m->depends_on = NULL;
 
         goto out;
     }
diff --git a/block/qcow2.h b/block/qcow2.h
index c8ca3bc..531af39 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -148,7 +148,6 @@ typedef struct QCowL2Meta
     int n_start;
     int nb_available;
     int nb_clusters;
-    struct QCowL2Meta *depends_on;
     CoQueue dependent_requests;
 
     QLIST_ENTRY(QCowL2Meta) next_in_flight;
commit 44520db10b1b92f272348ab7028e7afc68ac3edf
Author: Fabien Chouteau <chouteau at adacore.com>
Date:   Thu Sep 8 12:48:16 2011 +0200

    Gdbstub: Fix back-trace on SPARC32
    
    Gdb expects all registers windows to be flushed in ram, which is not the case
    in Qemu. Therefore the back-trace generation doesn't work. This patch adds a
    function to handle reads (and only read) in stack frames as if windows were
    flushed.
    
    Signed-off-by: Fabien Chouteau <chouteau at adacore.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/gdbstub.c b/gdbstub.c
index 9330885..90683a4 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -41,6 +41,15 @@
 #include "qemu_socket.h"
 #include "kvm.h"
 
+#ifndef TARGET_CPU_MEMORY_RW_DEBUG
+static inline int target_memory_rw_debug(CPUState *env, target_ulong addr,
+                                         uint8_t *buf, int len, int is_write)
+{
+    return cpu_memory_rw_debug(env, addr, buf, len, is_write);
+}
+#else
+/* target_memory_rw_debug() defined in cpu.h */
+#endif
 
 enum {
     GDB_SIGNAL_0 = 0,
@@ -2109,7 +2118,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
         if (*p == ',')
             p++;
         len = strtoull(p, NULL, 16);
-        if (cpu_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 0) != 0) {
+        if (target_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 0) != 0) {
             put_packet (s, "E14");
         } else {
             memtohex(buf, mem_buf, len);
@@ -2124,10 +2133,11 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
         if (*p == ':')
             p++;
         hextomem(mem_buf, p, len);
-        if (cpu_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 1) != 0)
+        if (target_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 1) != 0) {
             put_packet(s, "E14");
-        else
+        } else {
             put_packet(s, "OK");
+        }
         break;
     case 'p':
         /* Older gdb are really dumb, and don't use 'g' if 'p' is avaialable.
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index 8654f26..19de5ba 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -495,6 +495,13 @@ int cpu_sparc_handle_mmu_fault(CPUSPARCState *env1, target_ulong address, int rw
 target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev);
 void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env);
 
+#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
+int target_memory_rw_debug(CPUState *env, target_ulong addr,
+                           uint8_t *buf, int len, int is_write);
+#define TARGET_CPU_MEMORY_RW_DEBUG
+#endif
+
+
 /* translate.c */
 void gen_intermediate_code_init(CPUSPARCState *env);
 
diff --git a/target-sparc/helper.c b/target-sparc/helper.c
index 1fe1f07..c80531a 100644
--- a/target-sparc/helper.c
+++ b/target-sparc/helper.c
@@ -358,6 +358,90 @@ void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
     }
 }
 
+#if !defined(CONFIG_USER_ONLY)
+
+/* Gdb expects all registers windows to be flushed in ram. This function handles
+ * reads (and only reads) in stack frames as if windows were flushed. We assume
+ * that the sparc ABI is followed.
+ */
+int target_memory_rw_debug(CPUState *env, target_ulong addr,
+                           uint8_t *buf, int len, int is_write)
+{
+    int i;
+    int len1;
+    int cwp = env->cwp;
+
+    if (!is_write) {
+        for (i = 0; i < env->nwindows; i++) {
+            int off;
+            target_ulong fp = env->regbase[cwp * 16 + 22];
+
+            /* Assume fp == 0 means end of frame.  */
+            if (fp == 0) {
+                break;
+            }
+
+            cwp = cpu_cwp_inc(env, cwp + 1);
+
+            /* Invalid window ? */
+            if (env->wim & (1 << cwp)) {
+                break;
+            }
+
+            /* According to the ABI, the stack is growing downward.  */
+            if (addr + len < fp) {
+                break;
+            }
+
+            /* Not in this frame.  */
+            if (addr > fp + 64) {
+                continue;
+            }
+
+            /* Handle access before this window.  */
+            if (addr < fp) {
+                len1 = fp - addr;
+                if (cpu_memory_rw_debug(env, addr, buf, len1, is_write) != 0) {
+                    return -1;
+                }
+                addr += len1;
+                len -= len1;
+                buf += len1;
+            }
+
+            /* Access byte per byte to registers. Not very efficient but speed
+             * is not critical.
+             */
+            off = addr - fp;
+            len1 = 64 - off;
+
+            if (len1 > len) {
+                len1 = len;
+            }
+
+            for (; len1; len1--) {
+                int reg = cwp * 16 + 8 + (off >> 2);
+                union {
+                    uint32_t v;
+                    uint8_t c[4];
+                } u;
+                u.v = cpu_to_be32(env->regbase[reg]);
+                *buf++ = u.c[off & 3];
+                addr++;
+                len--;
+                off++;
+            }
+
+            if (len == 0) {
+                return 0;
+            }
+        }
+    }
+    return cpu_memory_rw_debug(env, addr, buf, len, is_write);
+}
+
+#endif  /* !defined(CONFIG_USER_ONLY) */
+
 #else /* !TARGET_SPARC64 */
 
 // 41 bit physical address space
commit 7d890b4074a415d39f02d3b01e7c40ece1b57087
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Tue Sep 6 03:55:57 2011 +0400

    target-xtensa: add regression testsuite
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/tests/xtensa/Makefile b/tests/xtensa/Makefile
new file mode 100644
index 0000000..70bd097
--- /dev/null
+++ b/tests/xtensa/Makefile
@@ -0,0 +1,74 @@
+-include ../../config-host.mak
+
+CROSS=xtensa-dc232b-elf-
+
+ifndef XT
+SIM = qemu-system-xtensa
+SIMFLAGS = -M dc232b -nographic -semihosting $(EXTFLAGS) -kernel
+SIMDEBUG = -s -S
+else
+SIM = xt-run
+SIMFLAGS = --xtensa-core=DC_B_232L --exit_with_target_code $(EXTFLAGS)
+SIMDEBUG = --gdbserve=0
+endif
+
+CC      = $(CROSS)gcc
+AS      = $(CROSS)gcc -x assembler
+LD      = $(CROSS)ld
+
+LDFLAGS = -Tlinker.ld
+
+CRT        = crt.o vectors.o
+
+TESTCASES += test_b.tst
+TESTCASES += test_bi.tst
+#TESTCASES += test_boolean.tst
+TESTCASES += test_bz.tst
+TESTCASES += test_clamps.tst
+TESTCASES += test_fail.tst
+TESTCASES += test_interrupt.tst
+TESTCASES += test_loop.tst
+TESTCASES += test_max.tst
+TESTCASES += test_min.tst
+TESTCASES += test_mmu.tst
+TESTCASES += test_mul16.tst
+TESTCASES += test_mul32.tst
+TESTCASES += test_nsa.tst
+ifdef XT
+TESTCASES += test_pipeline.tst
+endif
+TESTCASES += test_quo.tst
+TESTCASES += test_rem.tst
+TESTCASES += test_rst0.tst
+TESTCASES += test_sar.tst
+TESTCASES += test_sext.tst
+TESTCASES += test_shift.tst
+TESTCASES += test_timer.tst
+TESTCASES += test_windowed.tst
+
+all: build
+
+%.o: $(SRC_PATH)/tests/xtensa/%.c
+	$(CC) $(CFLAGS) -c $< -o $@
+
+%.o: $(SRC_PATH)/tests/xtensa/%.S
+	$(AS) $(ASFLAGS) -c $< -o $@
+
+%.tst: %.o macros.inc $(CRT) Makefile
+	$(LD) $(LDFLAGS) $(NOSTDFLAGS) $(CRT) $< -o $@
+
+build: $(TESTCASES)
+
+check: $(addprefix run-, $(TESTCASES))
+
+run-%.tst: %.tst
+	$(SIM) $(SIMFLAGS) ./$<
+
+run-test_fail.tst: test_fail.tst
+	! $(SIM) $(SIMFLAGS) ./$<
+
+debug-%.tst: %.tst
+	$(SIM) $(SIMDEBUG) $(SIMFLAGS) ./$<
+
+clean:
+	$(RM) -fr $(TESTCASES) $(CRT)
diff --git a/tests/xtensa/crt.S b/tests/xtensa/crt.S
new file mode 100644
index 0000000..d9846ac
--- /dev/null
+++ b/tests/xtensa/crt.S
@@ -0,0 +1,24 @@
+.section .init
+    j       1f
+.section .init.text
+1:
+    movi    a2, _start
+    jx      a2
+
+.text
+.global _start
+_start:
+    movi    a2, 1
+    wsr     a2, windowstart
+    movi    a2, 0
+    wsr     a2, windowbase
+    movi    a1, _fstack
+    movi    a2, 0x4000f
+    wsr     a2, ps
+    isync
+
+    call0   main
+
+    mov     a3, a2
+    movi    a2, 1
+    simcall
diff --git a/tests/xtensa/linker.ld b/tests/xtensa/linker.ld
new file mode 100644
index 0000000..4d0b307
--- /dev/null
+++ b/tests/xtensa/linker.ld
@@ -0,0 +1,112 @@
+OUTPUT_FORMAT("elf32-xtensa-le")
+ENTRY(_start)
+
+__DYNAMIC = 0;
+
+MEMORY {
+	ram : ORIGIN = 0xd0000000, LENGTH = 0x08000000  /* 128M */
+	rom : ORIGIN = 0xfe000000, LENGTH = 0x00001000  /* 4k */
+}
+
+SECTIONS
+{
+    .init :
+    {
+        *(.init)
+		*(.init.*)
+    } > rom
+
+    .vector :
+    {
+    . = 0x00000000;
+        *(.vector.window_overflow_4)
+        *(.vector.window_overflow_4.*)
+    . = 0x00000040;
+        *(.vector.window_underflow_4)
+        *(.vector.window_underflow_4.*)
+    . = 0x00000080;
+        *(.vector.window_overflow_8)
+        *(.vector.window_overflow_8.*)
+    . = 0x000000c0;
+        *(.vector.window_underflow_8)
+        *(.vector.window_underflow_8.*)
+    . = 0x00000100;
+        *(.vector.window_overflow_12)
+        *(.vector.window_overflow_12.*)
+    . = 0x00000140;
+        *(.vector.window_underflow_12)
+        *(.vector.window_underflow_12.*)
+
+    . = 0x00000180;
+        *(.vector.level2)
+        *(.vector.level2.*)
+    . = 0x000001c0;
+        *(.vector.level3)
+        *(.vector.level3.*)
+    . = 0x00000200;
+        *(.vector.level4)
+        *(.vector.level4.*)
+    . = 0x00000240;
+        *(.vector.level5)
+        *(.vector.level5.*)
+    . = 0x00000280;
+        *(.vector.level6)
+        *(.vector.level6.*)
+    . = 0x000002c0;
+        *(.vector.level7)
+        *(.vector.level7.*)
+
+    . = 0x00000300;
+        *(.vector.kernel)
+        *(.vector.kernel.*)
+    . = 0x00000340;
+        *(.vector.user)
+        *(.vector.user.*)
+    . = 0x000003c0;
+        *(.vector.double)
+        *(.vector.double.*)
+    } > ram
+
+	.text :
+	{
+		_ftext = .;
+		*(.text .stub .text.* .gnu.linkonce.t.* .literal .literal.*)
+		_etext = .;
+	} > ram
+
+	.rodata :
+	{
+		. = ALIGN(4);
+		_frodata = .;
+		*(.rodata .rodata.* .gnu.linkonce.r.*)
+		*(.rodata1)
+		_erodata = .;
+	} > ram
+
+	.data :
+	{
+		. = ALIGN(4);
+		_fdata = .;
+		*(.data .data.* .gnu.linkonce.d.*)
+		*(.data1)
+		_gp = ALIGN(16);
+		*(.sdata .sdata.* .gnu.linkonce.s.*)
+		_edata = .;
+	} > ram
+
+	.bss :
+	{
+		. = ALIGN(4);
+		_fbss = .;
+		*(.dynsbss)
+		*(.sbss .sbss.* .gnu.linkonce.sb.*)
+		*(.scommon)
+		*(.dynbss)
+		*(.bss .bss.* .gnu.linkonce.b.*)
+		*(COMMON)
+		_ebss = .;
+		_end = .;
+	} > ram
+}
+
+PROVIDE(_fstack = ORIGIN(ram) + LENGTH(ram) - 4);
diff --git a/tests/xtensa/macros.inc b/tests/xtensa/macros.inc
new file mode 100644
index 0000000..2d4515e
--- /dev/null
+++ b/tests/xtensa/macros.inc
@@ -0,0 +1,68 @@
+.macro test_suite name
+.data
+status: .word result
+result: .space 20
+.text
+.global main
+.align 4
+main:
+.endm
+
+.macro reset_ps
+    movi    a2, 0x4000f
+    wsr     a2, ps
+    isync
+.endm
+
+.macro test_suite_end
+    reset_ps
+    movi    a0, status
+    l32i    a2, a0, 0
+    movi    a0, result
+    sub     a2, a2, a0
+    movi    a3, 0
+    loopnez a2, 1f
+    l8ui    a2, a0, 0
+    or      a3, a3, a2
+    addi    a0, a0, 1
+1:
+    exit
+.endm
+
+.macro test name
+.endm
+
+.macro test_end
+99:
+    reset_ps
+    movi    a2, status
+    l32i    a3, a2, 0
+    addi    a3, a3, 1
+    s32i    a3, a2, 0
+.endm
+
+.macro exit
+    movi    a2, 1
+    simcall
+.endm
+
+.macro test_fail
+    movi    a2, status
+    l32i    a2, a2, 0
+    movi    a3, 1
+    s8i     a3, a2, 0
+    j       99f
+.endm
+
+.macro assert cond, arg1, arg2
+    b\cond  \arg1, \arg2, 90f
+    test_fail
+90:
+    nop
+.endm
+
+.macro set_vector vector, addr
+    movi    a2, handler_\vector
+    movi    a3, \addr
+    s32i    a3, a2, 0
+.endm
diff --git a/tests/xtensa/test_b.S b/tests/xtensa/test_b.S
new file mode 100644
index 0000000..6cbe5f1
--- /dev/null
+++ b/tests/xtensa/test_b.S
@@ -0,0 +1,221 @@
+.include "macros.inc"
+
+test_suite b
+
+test bnone
+    movi    a2, 0xa5a5ff00
+    movi    a3, 0x5a5a00ff
+    bnone   a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 0xa5a5ff01
+    bnone   a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test beq
+    movi    a2, 0
+    movi    a3, 0
+    beq     a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 1
+    beq     a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test blt
+    movi    a2, 6
+    movi    a3, 7
+    blt     a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 0xffffffff
+    blt     a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 7
+    blt     a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bltu
+    movi    a2, 6
+    movi    a3, 7
+    bltu    a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 7
+    bltu    a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+    movi    a2, 0xffffffff
+    bltu    a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test ball
+    movi    a2, 0xa5a5ffa5
+    movi    a3, 0xa5a5ff00
+    ball    a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 0xa5a5a5a5
+    ball    a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bbc
+    movi    a2, 0xfffffffd
+    movi    a3, 0xffffff01
+    bbc     a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 8
+    movi    a3, 0xffffff03
+    bbc     a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bbci
+    movi    a2, 0xfffdffff
+    bbci    a2, 17, 1f
+    test_fail
+1:
+    movi    a2, 0x00020000
+    bbci    a2, 17, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bany
+    movi    a2, 0xa5a5ff01
+    movi    a3, 0x5a5a00ff
+    bany    a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 0xa5a5ff00
+    bany    a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bne
+    movi    a2, 1
+    movi    a3, 0
+    bne     a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 0
+    bne     a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bge
+    movi    a2, 7
+    movi    a3, 7
+    bge     a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 6
+    bge     a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+    movi    a2, 0xffffffff
+    bge     a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bgeu
+    movi    a2, 7
+    movi    a3, 7
+    bgeu    a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 0xffffffff
+    bgeu    a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 6
+    bgeu    a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bnall
+    movi    a2, 0xa5a5a5a5
+    movi    a3, 0xa5a5ff00
+    bnall   a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 0xa5a5ffa5
+    bnall   a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bbs
+    movi    a2, 8
+    movi    a3, 0xffffff03
+    bbs     a2, a3, 1f
+    test_fail
+1:
+    movi    a2, 0xfffffffd
+    movi    a3, 0xffffff01
+    bbs     a2, a3, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bbsi
+    movi    a2, 0x00020000
+    bbsi    a2, 17, 1f
+    test_fail
+1:
+    movi    a2, 0xfffdffff
+    bbsi    a2, 17, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_bi.S b/tests/xtensa/test_bi.S
new file mode 100644
index 0000000..6a5f1df
--- /dev/null
+++ b/tests/xtensa/test_bi.S
@@ -0,0 +1,103 @@
+.include "macros.inc"
+
+test_suite bi
+
+test beqi
+    movi    a2, 7
+    beqi    a2, 7, 1f
+    test_fail
+1:
+    movi    a2, 1
+    beqi    a2, 7, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bnei
+    movi    a2, 1
+    bnei    a2, 7, 1f
+    test_fail
+1:
+    movi    a2, 7
+    bnei    a2, 7, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test blti
+    movi    a2, 6
+    blti    a2, 7, 1f
+    test_fail
+1:
+    movi    a2, 0xffffffff
+    blti    a2, 7, 1f
+    test_fail
+1:
+    movi    a2, 7
+    blti    a2, 7, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bgei
+    movi    a2, 7
+    bgei    a2, 7, 1f
+    test_fail
+1:
+    movi    a2, 6
+    bgei    a2, 7, 1f
+    j       2f
+1:
+    test_fail
+2:
+    movi    a2, 0xffffffff
+    bgei    a2, 7, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bltui
+    movi    a2, 6
+    bltui   a2, 7, 1f
+    test_fail
+1:
+    movi    a2, 7
+    bltui   a2, 7, 1f
+    j       2f
+1:
+    test_fail
+2:
+    movi    a2, 0xffffffff
+    bltui   a2, 7, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bgeui
+    movi    a2, 7
+    bgeui   a2, 7, 1f
+    test_fail
+1:
+    movi    a2, 0xffffffff
+    bgeui   a2, 7, 1f
+    test_fail
+1:
+    movi    a2, 6
+    bgeui   a2, 7, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_boolean.S b/tests/xtensa/test_boolean.S
new file mode 100644
index 0000000..50e6d2c
--- /dev/null
+++ b/tests/xtensa/test_boolean.S
@@ -0,0 +1,23 @@
+.include "macros.inc"
+
+test_suite boolean
+
+test all4
+    movi    a2, 0xfec0
+    wsr     a2, br
+    all4    b0, b0
+    rsr     a3, br
+    assert  eq, a2, a3
+    all4    b0, b4
+    rsr     a3, br
+    assert  eq, a2, a3
+    all4    b0, b8
+    rsr     a3, br
+    assert  eq, a2, a3
+    all4    b0, b12
+    rsr     a3, br
+    addi    a2, a2, 1
+    assert  eq, a2, a3
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_bz.S b/tests/xtensa/test_bz.S
new file mode 100644
index 0000000..f9ba6e2
--- /dev/null
+++ b/tests/xtensa/test_bz.S
@@ -0,0 +1,57 @@
+.include "macros.inc"
+
+test_suite bz
+
+test beqz
+    movi    a2, 0
+    _beqz   a2, 1f
+    test_fail
+1:
+    movi    a2, 1
+    _beqz   a2, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bnez
+    movi    a2, 1
+    _bnez   a2, 1f
+    test_fail
+1:
+    movi    a2, 0
+    _bnez   a2, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bltz
+    movi    a2, 0xffffffff
+    bltz    a2, 1f
+    test_fail
+1:
+    movi    a2, 0
+    bltz    a2, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test bgez
+    movi    a2, 0
+    bgez    a2, 1f
+    test_fail
+1:
+    movi    a2, 0xffffffff
+    bgez    a2, 1f
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_clamps.S b/tests/xtensa/test_clamps.S
new file mode 100644
index 0000000..c186cc9
--- /dev/null
+++ b/tests/xtensa/test_clamps.S
@@ -0,0 +1,42 @@
+.include "macros.inc"
+
+test_suite clamps
+
+test clamps
+    movi    a2, 0
+    movi    a3, 0
+    clamps  a4, a2, 7
+    assert  eq, a3, a4
+
+    movi    a2, 0x7f
+    movi    a3, 0x7f
+    clamps  a4, a2, 7
+    assert  eq, a3, a4
+
+    movi    a2, 0xffffff80
+    movi    a3, 0xffffff80
+    clamps  a4, a2, 7
+    assert  eq, a3, a4
+
+    movi    a2, 0x80
+    movi    a3, 0x7f
+    clamps  a2, a2, 7
+    assert  eq, a3, a2
+
+    movi    a2, 0xffffff7f
+    movi    a3, 0xffffff80
+    clamps  a2, a2, 7
+    assert  eq, a3, a2
+
+    movi    a2, 0x7fffffff
+    movi    a3, 0x7f
+    clamps  a2, a2, 7
+    assert  eq, a3, a2
+
+    movi    a2, 0x80000000
+    movi    a3, 0xffffff80
+    clamps  a2, a2, 7
+    assert  eq, a3, a2
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_fail.S b/tests/xtensa/test_fail.S
new file mode 100644
index 0000000..e8d1b42
--- /dev/null
+++ b/tests/xtensa/test_fail.S
@@ -0,0 +1,9 @@
+.include "macros.inc"
+
+test_suite fail
+
+test fail
+    test_fail
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_interrupt.S b/tests/xtensa/test_interrupt.S
new file mode 100644
index 0000000..68b3ee1
--- /dev/null
+++ b/tests/xtensa/test_interrupt.S
@@ -0,0 +1,194 @@
+.include "macros.inc"
+
+test_suite interrupt
+
+.macro clear_interrupts
+    movi    a2, 0
+    wsr     a2, intenable
+    wsr     a2, ccompare0
+    wsr     a2, ccompare1
+    wsr     a2, ccompare2
+    esync
+    rsr     a2, interrupt
+    wsr     a2, intclear
+
+    esync
+    rsr     a2, interrupt
+    assert  eqi, a2, 0
+.endm
+
+.macro check_l1
+    rsr     a2, ps
+    movi    a3, 0x1f        /* EXCM | INTMASK */
+    and     a2, a2, a3
+    assert  eqi, a2, 0x10   /* only EXCM is set for level-1 interrupt */
+    rsr     a2, exccause
+    assert  eqi, a2, 4
+.endm
+
+test rsil
+    clear_interrupts
+
+    rsr     a2, ps
+    rsil    a3, 7
+    rsr     a4, ps
+    assert  eq, a2, a3
+    movi    a2, 0xf
+    and     a2, a4, a2
+    assert  eqi, a2, 7
+    xor     a3, a3, a4
+    movi    a2, 0xfffffff0
+    and     a2, a3, a2
+    assert  eqi, a2, 0
+test_end
+
+test soft_disabled
+    set_vector kernel, 1f
+    clear_interrupts
+
+    movi    a2, 0x80
+    wsr     a2, intset
+    esync
+    rsr     a3, interrupt
+    assert  eq, a2, a3
+    wsr     a2, intclear
+    esync
+    rsr     a3, interrupt
+    assert  eqi, a3, 0
+    j       2f
+1:
+    test_fail
+2:
+test_end
+
+test soft_intenable
+    set_vector kernel, 1f
+    clear_interrupts
+
+    movi    a2, 0x80
+    wsr     a2, intset
+    esync
+    rsr     a3, interrupt
+    assert  eq, a2, a3
+    rsil    a3, 0
+    wsr     a2, intenable
+    esync
+    test_fail
+1:
+    check_l1
+test_end
+
+test soft_rsil
+    set_vector kernel, 1f
+    clear_interrupts
+
+    movi    a2, 0x80
+    wsr     a2, intset
+    esync
+    rsr     a3, interrupt
+    assert  eq, a2, a3
+    wsr     a2, intenable
+    rsil    a3, 0
+    esync
+    test_fail
+1:
+    check_l1
+test_end
+
+test soft_waiti
+    set_vector kernel, 1f
+    clear_interrupts
+
+    movi    a2, 0x80
+    wsr     a2, intset
+    esync
+    rsr     a3, interrupt
+    assert  eq, a2, a3
+    wsr     a2, intenable
+    waiti   0
+    test_fail
+1:
+    check_l1
+test_end
+
+test soft_user
+    set_vector kernel, 1f
+    set_vector user, 2f
+    clear_interrupts
+
+    movi    a2, 0x80
+    wsr     a2, intset
+    esync
+    rsr     a3, interrupt
+    assert  eq, a2, a3
+    wsr     a2, intenable
+
+    rsr     a2, ps
+    movi    a3, 0x20
+    or      a2, a2, a3
+    wsr     a2, ps
+    waiti   0
+1:
+    test_fail
+2:
+    check_l1
+test_end
+
+test soft_priority
+    set_vector kernel, 1f
+    set_vector level3, 2f
+    clear_interrupts
+
+    movi    a2, 0x880
+    wsr     a2, intenable
+    rsil    a3, 0
+    esync
+    wsr     a2, intset
+    esync
+1:
+    test_fail
+2:
+    rsr     a2, ps
+    movi    a3, 0x1f        /* EXCM | INTMASK */
+    and     a2, a2, a3
+    movi    a3, 0x13
+    assert  eq, a2, a3      /* EXCM and INTMASK are set
+                               for high-priority interrupt */
+test_end
+
+test eps_epc_rfi
+    set_vector level3, 3f
+    clear_interrupts
+    reset_ps
+
+    movi    a2, 0x880
+    wsr     a2, intenable
+    rsil    a3, 0
+    rsr     a3, ps
+    esync
+    wsr     a2, intset
+1:
+    esync
+2:
+    test_fail
+3:
+    rsr     a2, eps3
+    assert  eq, a2, a3
+    rsr     a2, epc3
+    movi    a3, 1b
+    assert  ge, a2, a3
+    movi    a3, 2b
+    assert  ge, a3, a2
+    movi    a2, 4f
+    wsr     a2, epc3
+    movi    a2, 0x40003
+    wsr     a2, eps3
+    rfi     3
+    test_fail
+4:
+    rsr     a2, ps
+    movi    a3, 0x40003
+    assert  eq, a2, a3
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_loop.S b/tests/xtensa/test_loop.S
new file mode 100644
index 0000000..a5ea933
--- /dev/null
+++ b/tests/xtensa/test_loop.S
@@ -0,0 +1,77 @@
+.include "macros.inc"
+
+test_suite loop
+
+test loop
+    movi    a2, 0
+    movi    a3, 5
+    loop    a3, 1f
+    addi    a2, a2, 1
+1:
+    assert  eqi, a2, 5
+test_end
+
+test loop0
+    movi    a2, 0
+    loop    a2, 1f
+    rsr     a2, lcount
+    assert  eqi, a2, -1
+    j       1f
+1:
+test_end
+
+test loop_jump
+    movi    a2, 0
+    movi    a3, 5
+    loop    a3, 1f
+    addi    a2, a2, 1
+    j       1f
+1:
+    assert  eqi, a2, 1
+test_end
+
+test loop_branch
+    movi    a2, 0
+    movi    a3, 5
+    loop    a3, 1f
+    addi    a2, a2, 1
+    beqi    a2, 3, 1f
+1:
+    assert  eqi, a2, 3
+test_end
+
+test loop_manual
+    movi    a2, 0
+    movi    a3, 5
+    movi    a4, 1f
+    movi    a5, 2f
+    wsr     a3, lcount
+    wsr     a4, lbeg
+    wsr     a5, lend
+    isync
+    j       1f
+.align 4
+1:
+    addi    a2, a2, 1
+2:
+    assert  eqi, a2, 6
+test_end
+
+test loop_excm
+    movi    a2, 0
+    movi    a3, 5
+    rsr     a4, ps
+    movi    a5, 0x10
+    or      a4, a4, a5
+    wsr     a4, ps
+    isync
+    loop    a3, 1f
+    addi    a2, a2, 1
+1:
+    xor     a4, a4, a5
+    isync
+    wsr     a4, ps
+    assert  eqi, a2, 1
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_max.S b/tests/xtensa/test_max.S
new file mode 100644
index 0000000..2534c9d
--- /dev/null
+++ b/tests/xtensa/test_max.S
@@ -0,0 +1,81 @@
+.include "macros.inc"
+
+test_suite max
+
+test max
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 1
+    max     a5, a2, a3
+    assert  eq, a5, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 1
+    max     a5, a2, a3
+    assert  eq, a5, a4
+
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 1
+    max     a2, a2, a3
+    assert  eq, a2, a4
+
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 1
+    max     a3, a2, a3
+    assert  eq, a3, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 1
+    max     a2, a2, a3
+    assert  eq, a2, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 1
+    max     a3, a2, a3
+    assert  eq, a3, a4
+test_end
+
+test maxu
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 0xffffffff
+    maxu    a5, a2, a3
+    assert  eq, a5, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 0xffffffff
+    maxu    a5, a2, a3
+    assert  eq, a5, a4
+
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 0xffffffff
+    maxu    a2, a2, a3
+    assert  eq, a2, a4
+
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 0xffffffff
+    maxu    a3, a2, a3
+    assert  eq, a3, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 0xffffffff
+    maxu    a2, a2, a3
+    assert  eq, a2, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 0xffffffff
+    maxu    a3, a2, a3
+    assert  eq, a3, a4
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_min.S b/tests/xtensa/test_min.S
new file mode 100644
index 0000000..6d9ddeb
--- /dev/null
+++ b/tests/xtensa/test_min.S
@@ -0,0 +1,81 @@
+.include "macros.inc"
+
+test_suite min
+
+test min
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 0xffffffff
+    min     a5, a2, a3
+    assert  eq, a5, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 0xffffffff
+    min     a5, a2, a3
+    assert  eq, a5, a4
+
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 0xffffffff
+    min     a2, a2, a3
+    assert  eq, a2, a4
+
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 0xffffffff
+    min     a3, a2, a3
+    assert  eq, a3, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 0xffffffff
+    min     a2, a2, a3
+    assert  eq, a2, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 0xffffffff
+    min     a3, a2, a3
+    assert  eq, a3, a4
+test_end
+
+test minu
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 1
+    minu    a5, a2, a3
+    assert  eq, a5, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 1
+    minu    a5, a2, a3
+    assert  eq, a5, a4
+
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 1
+    minu    a2, a2, a3
+    assert  eq, a2, a4
+
+    movi    a2, 0xffffffff
+    movi    a3, 1
+    movi    a4, 1
+    minu    a3, a2, a3
+    assert  eq, a3, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 1
+    minu    a2, a2, a3
+    assert  eq, a2, a4
+
+    movi    a2, 1
+    movi    a3, 0xffffffff
+    movi    a4, 1
+    minu    a3, a2, a3
+    assert  eq, a3, a4
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_mmu.S b/tests/xtensa/test_mmu.S
new file mode 100644
index 0000000..52d5774
--- /dev/null
+++ b/tests/xtensa/test_mmu.S
@@ -0,0 +1,318 @@
+.include "macros.inc"
+
+test_suite mmu
+
+.purgem test
+
+.macro test name
+    movi    a2, 0x00000004
+    idtlb   a2
+    movi    a2, 0x00100004
+    idtlb   a2
+    movi    a2, 0x00200004
+    idtlb   a2
+    movi    a2, 0x00300004
+    idtlb   a2
+    movi    a2, 0x00000007
+    idtlb   a2
+.endm
+
+test tlb_group
+    movi    a2, 0x04000002 /* PPN */
+    movi    a3, 0x01200004 /* VPN */
+    wdtlb   a2, a3
+    witlb   a2, a3
+    movi    a3, 0x00200004
+    rdtlb0  a1, a3
+    ritlb0  a2, a3
+    movi    a3, 0x01000001
+    assert  eq, a1, a3
+    assert  eq, a2, a3
+    movi    a3, 0x00200004
+    rdtlb1  a1, a3
+    ritlb1  a2, a3
+    movi    a3, 0x04000002
+    assert  eq, a1, a3
+    assert  eq, a2, a3
+    movi    a3, 0x01234567
+    pdtlb   a1, a3
+    pitlb   a2, a3
+    movi    a3, 0x01234014
+    assert  eq, a1, a3
+    movi    a3, 0x0123400c
+    assert  eq, a2, a3
+    movi    a3, 0x00200004
+    idtlb   a3
+    iitlb   a3
+    movi    a3, 0x01234567
+    pdtlb   a1, a3
+    pitlb   a2, a3
+    movi    a3, 0x00000010
+    and     a1, a1, a3
+    assert  eqi, a1, 0
+    movi    a3, 0x00000008
+    and     a2, a2, a3
+    assert  eqi, a2, 0
+test_end
+
+test itlb_miss
+    set_vector kernel, 1f
+
+    movi    a3, 0x00100000
+    jx      a3
+    test_fail
+1:
+    rsr     a2, excvaddr
+    assert  eq, a2, a3
+    rsr     a2, exccause
+    movi    a3, 16
+    assert  eq, a2, a3
+test_end
+
+test dtlb_miss
+    set_vector kernel, 1f
+
+    movi    a3, 0x00100000
+    l8ui    a2, a3, 0
+    test_fail
+1:
+    rsr     a2, excvaddr
+    assert  eq, a2, a3
+    rsr     a2, exccause
+    movi    a3, 24
+    assert  eq, a2, a3
+test_end
+
+test itlb_multi_hit
+    set_vector kernel, 1f
+
+    movi    a2, 0x04000002 /* PPN */
+    movi    a3, 0xf0000004 /* VPN */
+    witlb   a2, a3
+    movi    a3, 0xf0000000
+    pitlb   a2, a3
+    test_fail
+1:
+    rsr     a2, exccause
+    movi    a3, 17
+    assert  eq, a2, a3
+test_end
+
+test dtlb_multi_hit
+    set_vector kernel, 1f
+
+    movi    a2, 0x04000002 /* PPN */
+    movi    a3, 0x01200004 /* VPN */
+    wdtlb   a2, a3
+    movi    a3, 0x01200007 /* VPN */
+    wdtlb   a2, a3
+    movi    a3, 0x01200000
+    pdtlb   a2, a3
+    test_fail
+1:
+    rsr     a2, exccause
+    movi    a3, 25
+    assert  eq, a2, a3
+test_end
+
+test inst_fetch_privilege
+    set_vector kernel, 3f
+
+    movi    a2, 0x4004f
+    wsr     a2, ps
+1:
+    isync
+    nop
+2:
+    test_fail
+3:
+    movi    a1, 1b
+    rsr     a2, excvaddr
+    rsr     a3, epc1
+    assert  ge, a2, a1
+    assert  ge, a3, a1
+    movi    a1, 2b
+    assert  lt, a2, a1
+    assert  lt, a3, a1
+    rsr     a2, exccause
+    movi    a3, 18
+    assert  eq, a2, a3
+    rsr     a2, ps
+    movi    a3, 0x4005f
+    assert  eq, a2, a3
+test_end
+
+test load_store_privilege
+    set_vector kernel, 2f
+
+    movi    a3, 10f
+    pitlb   a3, a3
+    ritlb1  a2, a3
+    movi    a1, 0x10
+    or      a2, a2, a1
+    movi    a1, 0x000ff000
+    and     a3, a3, a1
+    movi    a1, 4
+    or      a3, a3, a1
+    witlb   a2, a3
+    movi    a3, 10f
+    movi    a1, 0x000fffff
+    and     a1, a3, a1
+
+    movi    a2, 0x04000003 /* PPN */
+    movi    a3, 0x01200004 /* VPN */
+    wdtlb   a2, a3
+    movi    a3, 0x01200001
+    movi    a2, 0x4004f
+    jx      a1
+10:
+    wsr     a2, ps
+    isync
+1:
+    l8ui    a2, a3, 0
+    test_fail
+2:
+    rsr     a2, excvaddr
+    assert  eq, a2, a3
+    rsr     a2, epc1
+    movi    a3, 1b
+    movi    a1, 0x000fffff
+    and     a3, a3, a1
+    assert  eq, a2, a3
+    rsr     a2, exccause
+    movi    a3, 26
+    assert  eq, a2, a3
+    rsr     a2, ps
+    movi    a3, 0x4005f
+    assert  eq, a2, a3
+test_end
+
+test cring_load_store_privilege
+    set_vector kernel, 0
+    set_vector double, 2f
+
+    movi    a2, 0x04000003 /* PPN */
+    movi    a3, 0x01200004 /* VPN */
+    wdtlb   a2, a3
+    movi    a3, 0x01200004
+    movi    a2, 0x4005f    /* ring 1 + excm => cring == 0 */
+    wsr     a2, ps
+    isync
+    l8ui    a2, a3, 0      /* cring used */
+1:
+    l32e    a2, a3, -4     /* ring used */
+    test_fail
+2:
+    rsr     a2, excvaddr
+    addi    a2, a2, 4
+    assert  eq, a2, a3
+    rsr     a2, depc
+    movi    a3, 1b
+    assert  eq, a2, a3
+    rsr     a2, exccause
+    movi    a3, 26
+    assert  eq, a2, a3
+    rsr     a2, ps
+    movi    a3, 0x4005f
+    assert  eq, a2, a3
+test_end
+
+test inst_fetch_prohibited
+    set_vector kernel, 2f
+
+    movi    a3, 10f
+    pitlb   a3, a3
+    ritlb1  a2, a3
+    movi    a1, 0xfffff000
+    and     a2, a2, a1
+    movi    a1, 0x4
+    or      a2, a2, a1
+    movi    a1, 0x000ff000
+    and     a3, a3, a1
+    movi    a1, 4
+    or      a3, a3, a1
+    witlb   a2, a3
+    movi    a3, 10f
+    movi    a1, 0x000fffff
+    and     a1, a3, a1
+    jx      a1
+    .align  4
+10:
+    nop
+    test_fail
+2:
+    rsr     a2, excvaddr
+    assert  eq, a2, a1
+    rsr     a2, epc1
+    assert  eq, a2, a1
+    rsr     a2, exccause
+    movi    a3, 20
+    assert  eq, a2, a3
+test_end
+
+test load_prohibited
+    set_vector kernel, 2f
+
+    movi    a2, 0x0400000c /* PPN */
+    movi    a3, 0x01200004 /* VPN */
+    wdtlb   a2, a3
+    movi    a3, 0x01200002
+1:
+    l8ui    a2, a3, 0
+    test_fail
+2:
+    rsr     a2, excvaddr
+    assert  eq, a2, a3
+    rsr     a2, epc1
+    movi    a3, 1b
+    assert  eq, a2, a3
+    rsr     a2, exccause
+    movi    a3, 28
+    assert  eq, a2, a3
+test_end
+
+test store_prohibited
+    set_vector kernel, 2f
+
+    movi    a2, 0x04000001 /* PPN */
+    movi    a3, 0x01200004 /* VPN */
+    wdtlb   a2, a3
+    movi    a3, 0x01200003
+    l8ui    a2, a3, 0
+1:
+    s8i     a2, a3, 0
+    test_fail
+2:
+    rsr     a2, excvaddr
+    assert  eq, a2, a3
+    rsr     a2, epc1
+    movi    a3, 1b
+    assert  eq, a2, a3
+    rsr     a2, exccause
+    movi    a3, 29
+    assert  eq, a2, a3
+test_end
+
+test dtlb_autoload
+    set_vector kernel, 0
+
+    movi    a2, 0xd4000000
+    wsr     a2, ptevaddr
+    movi    a3, 0x00001013
+    s32i    a3, a2, 4
+    pdtlb   a2, a3
+    movi    a1, 0x10
+    and     a1, a1, a2
+    assert  eqi, a1, 0
+    l8ui    a1, a3, 0
+    pdtlb   a2, a3
+    movi    a1, 0xfffff010
+    and     a1, a1, a2
+    movi    a3, 0x00001010
+    assert  eq, a1, a3
+    movi    a1, 0xf
+    and     a1, a1, a2
+    assert  lti, a1, 4
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_mul16.S b/tests/xtensa/test_mul16.S
new file mode 100644
index 0000000..bf94376
--- /dev/null
+++ b/tests/xtensa/test_mul16.S
@@ -0,0 +1,83 @@
+.include "macros.inc"
+
+test_suite mul16
+
+test mul16u_pp
+    movi    a2, 0x137f5a5a
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0x06e180a6
+    mul16u  a5, a2, a4
+    assert  eq, a5, a6
+    mul16u  a2, a2, a4
+    assert  eq, a2, a6
+    mul16u  a3, a4, a3
+    assert  eq, a3, a6
+test_end
+
+test mul16u_np
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0x0c9d6bdb
+    mul16u  a5, a2, a4
+    assert  eq, a5, a6
+    mul16u  a2, a2, a4
+    assert  eq, a2, a6
+    mul16u  a3, a4, a3
+    assert  eq, a3, a6
+test_end
+
+test mul16u_nn
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5f731
+    movi    a6, 0x9ff1e795
+    mul16u  a5, a2, a4
+    assert  eq, a5, a6
+    mul16u  a2, a2, a4
+    assert  eq, a2, a6
+    mul16u  a3, a4, a3
+    assert  eq, a3, a6
+test_end
+
+test mul16s_pp
+    movi    a2, 0x137f5a5a
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0x06e180a6
+    mul16s  a5, a2, a4
+    assert  eq, a5, a6
+    mul16s  a2, a2, a4
+    assert  eq, a2, a6
+    mul16s  a3, a4, a3
+    assert  eq, a3, a6
+test_end
+
+test mul16s_np
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0xf91e6bdb
+    mul16s  a5, a2, a4
+    assert  eq, a5, a6
+    mul16s  a2, a2, a4
+    assert  eq, a2, a6
+    mul16s  a3, a4, a3
+    assert  eq, a3, a6
+test_end
+
+test mul16s_nn
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5f731
+    movi    a6, 0x031be795
+    mul16s  a5, a2, a4
+    assert  eq, a5, a6
+    mul16s  a2, a2, a4
+    assert  eq, a2, a6
+    mul16s  a3, a4, a3
+    assert  eq, a3, a6
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_mul32.S b/tests/xtensa/test_mul32.S
new file mode 100644
index 0000000..fdaf573
--- /dev/null
+++ b/tests/xtensa/test_mul32.S
@@ -0,0 +1,20 @@
+.include "macros.inc"
+
+test_suite mul32
+
+test mull
+    movi    a2, 0x137f5a5a
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0x5de480a6
+    mull    a5, a2, a4
+    assert  eq, a5, a6
+    mull    a2, a2, a4
+    assert  eq, a2, a6
+    mull    a3, a4, a3
+    assert  eq, a3, a6
+test_end
+
+/* unfortunately dc232b doesn't have muluh/mulsh*/
+
+test_suite_end
diff --git a/tests/xtensa/test_nsa.S b/tests/xtensa/test_nsa.S
new file mode 100644
index 0000000..a5fe5de
--- /dev/null
+++ b/tests/xtensa/test_nsa.S
@@ -0,0 +1,59 @@
+.include "macros.inc"
+
+test_suite nsa
+
+test nsa
+    movi    a2, 0
+    movi    a3, 31
+    nsa     a4, a2
+    assert  eq, a3, a4
+
+    movi    a2, 0xffffffff
+    movi    a3, 31
+    nsa     a4, a2
+    assert  eq, a3, a4
+
+    movi    a2, 1
+    movi    a3, 30
+    nsa     a2, a2
+    assert  eq, a3, a2
+
+    movi    a2, 0xfffffffe
+    movi    a3, 30
+    nsa     a2, a2
+    assert  eq, a3, a2
+
+    movi    a2, 0x5a5a5a5a
+    movi    a3, 0
+    nsa     a4, a2
+    assert  eq, a3, a4
+
+    movi    a2, 0xa5a5a5a5
+    movi    a3, 0
+    nsa     a4, a2
+    assert  eq, a3, a4
+test_end
+
+test nsau
+    movi    a2, 0
+    movi    a3, 32
+    nsau    a4, a2
+    assert  eq, a3, a4
+
+    movi    a2, 0xffffffff
+    movi    a3, 0
+    nsau    a4, a2
+    assert  eq, a3, a4
+
+    movi    a2, 1
+    movi    a3, 31
+    nsau    a2, a2
+    assert  eq, a3, a2
+
+    movi    a2, 0x5a5a5a5a
+    movi    a3, 1
+    nsau    a2, a2
+    assert  eq, a3, a2
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_pipeline.S b/tests/xtensa/test_pipeline.S
new file mode 100644
index 0000000..6be6085
--- /dev/null
+++ b/tests/xtensa/test_pipeline.S
@@ -0,0 +1,157 @@
+.include "macros.inc"
+
+.purgem test
+.macro test name
+    movi    a2, 1f
+    movi    a3, 99f
+0:
+    ipf     a2, 0
+    ipf     a2, 4
+    ipf     a2, 8
+    ipf     a2, 12
+    addi    a2, a2, 16
+    blt     a2, a3, 0b
+    j       1f
+    .align 4
+1:
+.endm
+
+test_suite pipeline
+
+test register_no_stall
+    rsr     a3, ccount
+    add     a5, a6, a6
+    add     a6, a5, a5
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    assert  eqi, a3, 3
+test_end
+
+test register_stall
+    l32i    a5, a1, 0   /* data cache preload */
+    nop
+    rsr     a3, ccount
+    l32i    a5, a1, 0
+    add     a6, a5, a5  /* M-to-E interlock */
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    assert  eqi, a3, 4
+test_end
+
+test j0_stall
+    rsr     a3, ccount
+    j       1f          /* E + 2-cycle penalty */
+1:
+    rsr     a4, ccount  /* E */
+    sub     a3, a4, a3
+    assert  eqi, a3, 4
+test_end
+
+test j1_stall
+    rsr     a3, ccount
+    j       1f
+    nop
+1:
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    assert  eqi, a3, 4
+test_end
+
+test j5_stall
+    rsr     a3, ccount
+    j       1f
+    nop
+    nop
+    nop
+    nop
+    nop
+1:
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    assert  eqi, a3, 4
+test_end
+
+test b_no_stall
+    movi    a5, 1
+    rsr     a3, ccount
+    beqi    a5, 2, 1f
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    assert  eqi, a3, 2
+1:
+test_end
+
+test b1_stall
+    movi    a5, 1
+    rsr     a3, ccount
+    beqi    a5, 1, 1f
+    nop
+1:
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    assert  eqi, a3, 4
+test_end
+
+test b5_stall
+    movi    a5, 1
+    rsr     a3, ccount
+    beqi    a5, 1, 1f
+    nop
+    nop
+    nop
+    nop
+    nop
+1:
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    assert  eqi, a3, 4
+test_end
+
+/* PS *SYNC */
+
+test ps_dsync
+    rsr     a5, ps
+    isync
+    rsr     a3, ccount
+    wsr     a5, ps
+    dsync
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    assert  eqi, a3, 5
+test_end
+
+test ps_esync
+    rsr     a5, ps
+    isync
+    rsr     a3, ccount
+    wsr     a5, ps
+    esync
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    assert  eqi, a3, 5
+test_end
+
+test ps_rsync
+    rsr     a5, ps
+    isync
+    rsr     a3, ccount
+    wsr     a5, ps
+    rsync
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    assert  eqi, a3, 5
+test_end
+
+test ps_isync
+    rsr     a5, ps
+    isync
+    rsr     a3, ccount
+    wsr     a5, ps
+    isync
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    movi    a4, 9
+    assert  eq, a3, a4
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_quo.S b/tests/xtensa/test_quo.S
new file mode 100644
index 0000000..12debf1
--- /dev/null
+++ b/tests/xtensa/test_quo.S
@@ -0,0 +1,147 @@
+.include "macros.inc"
+
+test_suite quo
+
+test quou_pp
+    movi    a2, 0x5a5a137f
+    mov     a3, a2
+    movi    a4, 0x137f5a5a
+    movi    a6, 0x4
+    quou    a5, a2, a4
+    assert  eq, a5, a6
+    quou    a2, a2, a4
+    assert  eq, a2, a6
+    quou    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test quou_np
+    movi    a2, 0xa5a5137f
+    mov     a3, a2
+    movi    a4, 0x137f5a5a
+    movi    a6, 0x8
+    quou    a5, a2, a4
+    assert  eq, a5, a6
+    quou    a2, a2, a4
+    assert  eq, a2, a6
+    quou    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test quou_pn
+    movi    a2, 0x5a5a137f
+    mov     a3, a2
+    movi    a4, 0xf7315a5a
+    movi    a6, 0
+    quou    a5, a2, a4
+    assert  eq, a5, a6
+    quou    a2, a2, a4
+    assert  eq, a2, a6
+    quou    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test quou_nn
+    movi    a2, 0xf7315a5a
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0x1
+    quou    a5, a2, a4
+    assert  eq, a5, a6
+    quou    a2, a2, a4
+    assert  eq, a2, a6
+    quou    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test quou_exc
+    set_vector kernel, 2f
+    movi    a2, 0xf7315a5a
+    movi    a4, 0x00000000
+1:
+    quou    a5, a2, a4
+    test_fail
+2:
+    rsr     a2, exccause
+    assert  eqi, a2, 6 /* INTEGER_DIVIDE_BY_ZERO_CAUSE */
+    rsr     a2, epc1
+    movi    a3, 1b
+    assert  eq, a2, a3
+test_end
+
+test quos_pp
+    movi    a2, 0x5a5a137f
+    mov     a3, a2
+    movi    a4, 0x137f5a5a
+    movi    a6, 0x4
+    quos    a5, a2, a4
+    assert  eq, a5, a6
+    quos    a2, a2, a4
+    assert  eq, a2, a6
+    quos    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test quos_np
+    movi    a2, 0xa5a5137f
+    mov     a3, a2
+    movi    a4, 0x137f5a5a
+    movi    a6, 0xfffffffc
+    quos    a5, a2, a4
+    assert  eq, a5, a6
+    quos    a2, a2, a4
+    assert  eq, a2, a6
+    quos    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test quos_pn
+    movi    a2, 0x5a5a137f
+    mov     a3, a2
+    movi    a4, 0xf7315a5a
+    movi    a6, 0xfffffff6
+    quos    a5, a2, a4
+    assert  eq, a5, a6
+    quos    a2, a2, a4
+    assert  eq, a2, a6
+    quos    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test quos_nn
+    movi    a2, 0xf7315a5a
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0
+    quos    a5, a2, a4
+    assert  eq, a5, a6
+    quos    a2, a2, a4
+    assert  eq, a2, a6
+    quos    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test quos_over
+    movi    a2, 0x80000000
+    movi    a4, 0xffffffff
+    movi    a6, 0x80000000
+    quos    a5, a2, a4
+    assert  eq, a5, a6
+test_end
+
+test quos_exc
+    set_vector kernel, 2f
+    movi    a2, 0xf7315a5a
+    movi    a4, 0x00000000
+1:
+    quos    a5, a2, a4
+    test_fail
+2:
+    rsr     a2, exccause
+    assert  eqi, a2, 6 /* INTEGER_DIVIDE_BY_ZERO_CAUSE */
+    rsr     a2, epc1
+    movi    a3, 1b
+    assert  eq, a2, a3
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_rem.S b/tests/xtensa/test_rem.S
new file mode 100644
index 0000000..bb0d5fe
--- /dev/null
+++ b/tests/xtensa/test_rem.S
@@ -0,0 +1,147 @@
+.include "macros.inc"
+
+test_suite rem
+
+test remu_pp
+    movi    a2, 0x5a5a137f
+    mov     a3, a2
+    movi    a4, 0x137f5a5a
+    movi    a6, 0x0c5caa17
+    remu    a5, a2, a4
+    assert  eq, a5, a6
+    remu    a2, a2, a4
+    assert  eq, a2, a6
+    remu    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test remu_np
+    movi    a2, 0xa5a5137f
+    mov     a3, a2
+    movi    a4, 0x137f5a5a
+    movi    a6, 0x9aa40af
+    remu    a5, a2, a4
+    assert  eq, a5, a6
+    remu    a2, a2, a4
+    assert  eq, a2, a6
+    remu    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test remu_pn
+    movi    a2, 0x5a5a137f
+    mov     a3, a2
+    movi    a4, 0xf7315a5a
+    movi    a6, 0x5a5a137f
+    remu    a5, a2, a4
+    assert  eq, a5, a6
+    remu    a2, a2, a4
+    assert  eq, a2, a6
+    remu    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test remu_nn
+    movi    a2, 0xf7315a5a
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0x518c46db
+    remu    a5, a2, a4
+    assert  eq, a5, a6
+    remu    a2, a2, a4
+    assert  eq, a2, a6
+    remu    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test remu_exc
+    set_vector kernel, 2f
+    movi    a2, 0xf7315a5a
+    movi    a4, 0x00000000
+1:
+    remu    a5, a2, a4
+    test_fail
+2:
+    rsr     a2, exccause
+    assert  eqi, a2, 6 /* INTEGER_DIVIDE_BY_ZERO_CAUSE */
+    rsr     a2, epc1
+    movi    a3, 1b
+    assert  eq, a2, a3
+test_end
+
+test rems_pp
+    movi    a2, 0x5a5a137f
+    mov     a3, a2
+    movi    a4, 0x137f5a5a
+    movi    a6, 0x0c5caa17
+    rems    a5, a2, a4
+    assert  eq, a5, a6
+    rems    a2, a2, a4
+    assert  eq, a2, a6
+    rems    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test rems_np
+    movi    a2, 0xa5a5137f
+    mov     a3, a2
+    movi    a4, 0x137f5a5a
+    movi    a6, 0xf3a27ce7
+    rems    a5, a2, a4
+    assert  eq, a5, a6
+    rems    a2, a2, a4
+    assert  eq, a2, a6
+    rems    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test rems_pn
+    movi    a2, 0x5a5a137f
+    mov     a3, a2
+    movi    a4, 0xf7315a5a
+    movi    a6, 0x02479b03
+    rems    a5, a2, a4
+    assert  eq, a5, a6
+    rems    a2, a2, a4
+    assert  eq, a2, a6
+    rems    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test rems_nn
+    movi    a2, 0xf7315a5a
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0xf7315a5a
+    rems    a5, a2, a4
+    assert  eq, a5, a6
+    rems    a2, a2, a4
+    assert  eq, a2, a6
+    rems    a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test rems_over
+    movi    a2, 0x80000000
+    movi    a4, 0xffffffff
+    movi    a6, 0
+    rems    a5, a2, a4
+    assert  eq, a5, a6
+test_end
+
+test rems_exc
+    set_vector kernel, 2f
+    movi    a2, 0xf7315a5a
+    movi    a4, 0x00000000
+1:
+    rems    a5, a2, a4
+    test_fail
+2:
+    rsr     a2, exccause
+    assert  eqi, a2, 6 /* INTEGER_DIVIDE_BY_ZERO_CAUSE */
+    rsr     a2, epc1
+    movi    a3, 1b
+    assert  eq, a2, a3
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_rst0.S b/tests/xtensa/test_rst0.S
new file mode 100644
index 0000000..3eda565
--- /dev/null
+++ b/tests/xtensa/test_rst0.S
@@ -0,0 +1,148 @@
+.include "macros.inc"
+
+test_suite rst0
+
+test and
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0x01250125
+    and     a5, a2, a4
+    assert  eq, a5, a6
+    and     a2, a2, a4
+    assert  eq, a2, a6
+    and     a3, a4, a3
+    assert  eq, a3, a6
+test_end
+
+test or
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0xb7ffb7ff
+    or      a5, a2, a4
+    assert  eq, a5, a6
+    or      a2, a2, a4
+    assert  eq, a2, a6
+    or      a3, a4, a3
+    assert  eq, a3, a6
+test_end
+
+test xor
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0xb6dab6da
+    xor     a5, a2, a4
+    assert  eq, a5, a6
+    xor     a2, a2, a4
+    assert  eq, a2, a6
+    xor     a3, a4, a3
+    assert  eq, a3, a6
+test_end
+
+test add
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0xb924b924
+    add     a5, a2, a4
+    assert  eq, a5, a6
+    add     a2, a2, a4
+    assert  eq, a2, a6
+    add     a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test addx2
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0xcca45ec9
+    addx2   a5, a2, a4
+    assert  eq, a5, a6
+    addx2   a2, a2, a4
+    assert  eq, a2, a6
+    addx2   a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test addx4
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0xf3a3aa13
+    addx4   a5, a2, a4
+    assert  eq, a5, a6
+    addx4   a2, a2, a4
+    assert  eq, a2, a6
+    addx4   a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test addx8
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0x41a240a7
+    addx8   a5, a2, a4
+    assert  eq, a5, a6
+    addx8   a2, a2, a4
+    assert  eq, a2, a6
+    addx8   a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test sub
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0x6dda9226
+    sub     a5, a2, a4
+    assert  eq, a5, a6
+    sub     a2, a2, a4
+    assert  eq, a2, a6
+    sub     a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test subx2
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0x815a37cb
+    subx2   a5, a2, a4
+    assert  eq, a5, a6
+    subx2   a2, a2, a4
+    assert  eq, a2, a6
+    subx2   a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test subx4
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0xa8598315
+    subx4   a5, a2, a4
+    assert  eq, a5, a6
+    subx4   a2, a2, a4
+    assert  eq, a2, a6
+    subx4   a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test subx8
+    movi    a2, 0x137fa5a5
+    mov     a3, a2
+    movi    a4, 0xa5a5137f
+    movi    a6, 0xf65819a9
+    subx8   a5, a2, a4
+    assert  eq, a5, a6
+    subx8   a2, a2, a4
+    assert  eq, a2, a6
+    subx8   a4, a3, a4
+    assert  eq, a4, a6
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_sar.S b/tests/xtensa/test_sar.S
new file mode 100644
index 0000000..40c649f
--- /dev/null
+++ b/tests/xtensa/test_sar.S
@@ -0,0 +1,111 @@
+.include "macros.inc"
+
+test_suite sar
+
+.macro test_sar prefix, imm
+    \prefix\()_set \imm
+    \prefix\()_ver \imm
+.endm
+
+.macro tests_sar prefix
+    test_sar \prefix, 0
+    test_sar \prefix, 1
+    test_sar \prefix, 2
+    test_sar \prefix, 3
+    test_sar \prefix, 0x1f
+    test_sar \prefix, 0x20
+    test_sar \prefix, 0x3f
+    test_sar \prefix, 0x40
+    test_sar \prefix, 0xfffffffe
+.endm
+
+.macro sar_set imm
+    movi    a2, \imm
+    wsr     a2, sar
+.endm
+
+.macro sar_ver imm
+    rsr     a3, sar
+    movi    a2, \imm & 0x3f
+    assert  eq, a2, a3
+.endm
+
+test sar
+    tests_sar sar
+test_end
+
+.macro ssr_set imm
+    movi    a2, \imm
+    ssr     a2
+.endm
+
+.macro ssr_ver imm
+    rsr     a3, sar
+    movi    a2, \imm & 0x1f
+    assert  eq, a2, a3
+.endm
+
+test ssr
+    tests_sar ssr
+test_end
+
+.macro ssl_set imm
+    movi    a2, \imm
+    ssl     a2
+.endm
+
+.macro ssl_ver imm
+    rsr     a3, sar
+    movi    a2, 32 - (\imm & 0x1f)
+    assert  eq, a2, a3
+.endm
+
+test ssl
+    tests_sar ssl
+test_end
+
+.macro ssa8l_set imm
+    movi    a2, \imm
+    ssa8l   a2
+.endm
+
+.macro ssa8l_ver imm
+    rsr     a3, sar
+    movi    a2, (\imm & 0x3) << 3
+    assert  eq, a2, a3
+.endm
+
+test ssa8l
+    tests_sar ssa8l
+test_end
+
+.macro ssa8b_set imm
+    movi    a2, \imm
+    ssa8b   a2
+.endm
+
+.macro ssa8b_ver imm
+    rsr     a3, sar
+    movi    a2, 32 - ((\imm & 0x3) << 3)
+    assert  eq, a2, a3
+.endm
+
+test ssa8b
+    tests_sar ssa8b
+test_end
+
+.macro ssai_set imm
+    ssai    \imm & 0x1f
+.endm
+
+.macro ssai_ver imm
+    rsr     a3, sar
+    movi    a2, \imm & 0x1f
+    assert  eq, a2, a3
+.endm
+
+test ssai
+    tests_sar ssai
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_sext.S b/tests/xtensa/test_sext.S
new file mode 100644
index 0000000..04dc650
--- /dev/null
+++ b/tests/xtensa/test_sext.S
@@ -0,0 +1,69 @@
+.include "macros.inc"
+
+test_suite sext
+
+test sext
+    movi    a2, 0xffffff5a
+    movi    a3, 0x0000005a
+    sext    a4, a2, 7
+    assert  eq, a3, a4
+
+    movi    a2, 0x000000a5
+    movi    a3, 0xffffffa5
+    sext    a4, a2, 7
+    assert  eq, a3, a4
+
+    movi    a2, 0xfffffaa5
+    movi    a3, 0x000000a5
+    sext    a4, a2, 8
+    assert  eq, a3, a4
+
+    movi    a2, 0x0000055a
+    movi    a3, 0xffffff5a
+    sext    a4, a2, 8
+    assert  eq, a3, a4
+
+    movi    a2, 0xffff5a5a
+    movi    a3, 0x00005a5a
+    sext    a4, a2, 15
+    assert  eq, a3, a4
+
+    movi    a2, 0x0000a5a5
+    movi    a3, 0xffffa5a5
+    sext    a4, a2, 15
+    assert  eq, a3, a4
+
+    movi    a2, 0x00055a5a
+    movi    a3, 0xffff5a5a
+    sext    a4, a2, 16
+    assert  eq, a3, a4
+
+    movi    a2, 0x000aa5a5
+    movi    a3, 0x0000a5a5
+    sext    a4, a2, 16
+    assert  eq, a3, a4
+
+    movi    a2, 0x005a5a5a
+    movi    a3, 0xffda5a5a
+    sext    a4, a2, 22
+    assert  eq, a3, a4
+
+    movi    a2, 0xffa5a5a5
+    movi    a3, 0x0025a5a5
+    sext    a4, a2, 22
+    assert  eq, a3, a4
+test_end
+
+test sext_same_rs
+    movi    a2, 0xffffff5a
+    movi    a3, 0x0000005a
+    sext    a2, a2, 7
+    assert  eq, a3, a2
+
+    movi    a2, 0x000000a5
+    movi    a3, 0xffffffa5
+    sext    a2, a2, 7
+    assert  eq, a3, a2
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_shift.S b/tests/xtensa/test_shift.S
new file mode 100644
index 0000000..a8e4364
--- /dev/null
+++ b/tests/xtensa/test_shift.S
@@ -0,0 +1,206 @@
+.include "macros.inc"
+
+test_suite shift
+
+.macro test_shift prefix, dst, src, v, imm
+    \prefix\()_set \dst, \src, \v, \imm
+    \prefix\()_ver \dst, \v, \imm
+.endm
+
+.macro test_shift_sd prefix, v, imm
+    test_shift \prefix, a3, a2, \v, \imm
+    test_shift \prefix, a2, a2, \v, \imm
+.endm
+
+.macro tests_imm_shift prefix, v
+    test_shift_sd \prefix, \v, 1
+    test_shift_sd \prefix, \v, 2
+    test_shift_sd \prefix, \v, 7
+    test_shift_sd \prefix, \v, 8
+    test_shift_sd \prefix, \v, 15
+    test_shift_sd \prefix, \v, 16
+    test_shift_sd \prefix, \v, 31
+.endm
+
+.macro tests_shift prefix, v
+    test_shift_sd \prefix, \v, 0
+    tests_imm_shift \prefix, \v
+    test_shift_sd \prefix, \v, 32
+.endm
+
+
+.macro slli_set dst, src, v, imm
+    movi    \src, \v
+    slli    \dst, \src, \imm
+.endm
+
+.macro slli_ver dst, v, imm
+    mov     a2, \dst
+    movi    a3, ((\v) << (\imm)) & 0xffffffff
+    assert  eq, a2, a3
+.endm
+
+test slli
+    tests_imm_shift slli, 0xa3c51249
+test_end
+
+
+.macro srai_set dst, src, v, imm
+    movi    \src, \v
+    srai    \dst, \src, \imm
+.endm
+
+.macro srai_ver dst, v, imm
+    mov     a2, \dst
+    .if (\imm)
+    movi    a3, (((\v) >> (\imm)) & 0xffffffff) | \
+                ~((((\v) & 0x80000000) >> ((\imm) - 1)) - 1)
+    .else
+    movi    a3, \v
+    .endif
+    assert  eq, a2, a3
+.endm
+
+test srai
+    tests_imm_shift srai, 0x49a3c512
+    tests_imm_shift srai, 0xa3c51249
+test_end
+
+
+.macro srli_set dst, src, v, imm
+    movi    \src, \v
+    srli    \dst, \src, \imm
+.endm
+
+.macro srli_ver dst, v, imm
+    mov     a2, \dst
+    movi    a3, (((\v) >> (\imm)) & 0xffffffff)
+    assert  eq, a2, a3
+.endm
+
+test srli
+    tests_imm_shift srli, 0x49a3c512
+    tests_imm_shift srli, 0xa3c51249
+test_end
+
+
+.macro sll_set dst, src, v, imm
+    movi    a2, \imm
+    ssl     a2
+    movi    \src, \v
+    sll     \dst, \src
+.endm
+
+.macro sll_sar_set dst, src, v, imm
+    movi    a2, 32 - \imm
+    wsr     a2, sar
+    movi    \src, \v
+    sll     \dst, \src
+.endm
+
+.macro sll_ver dst, v, imm
+    slli_ver \dst, \v, (\imm) & 0x1f
+.endm
+
+.macro sll_sar_ver dst, v, imm
+    slli_ver \dst, \v, \imm
+.endm
+
+test sll
+    tests_shift sll, 0xa3c51249
+    tests_shift sll_sar, 0xa3c51249
+test_end
+
+
+.macro srl_set dst, src, v, imm
+    movi    a2, \imm
+    ssr     a2
+    movi    \src, \v
+    srl     \dst, \src
+.endm
+
+.macro srl_sar_set dst, src, v, imm
+    movi    a2, \imm
+    wsr     a2, sar
+    movi    \src, \v
+    srl     \dst, \src
+.endm
+
+.macro srl_ver dst, v, imm
+    srli_ver \dst, \v, (\imm) & 0x1f
+.endm
+
+.macro srl_sar_ver dst, v, imm
+    srli_ver \dst, \v, \imm
+.endm
+
+test srl
+    tests_shift srl, 0xa3c51249
+    tests_shift srl_sar, 0xa3c51249
+    tests_shift srl, 0x49a3c512
+    tests_shift srl_sar, 0x49a3c512
+test_end
+
+
+.macro sra_set dst, src, v, imm
+    movi    a2, \imm
+    ssr     a2
+    movi    \src, \v
+    sra     \dst, \src
+.endm
+
+.macro sra_sar_set dst, src, v, imm
+    movi    a2, \imm
+    wsr     a2, sar
+    movi    \src, \v
+    sra     \dst, \src
+.endm
+
+.macro sra_ver dst, v, imm
+    srai_ver \dst, \v, (\imm) & 0x1f
+.endm
+
+.macro sra_sar_ver dst, v, imm
+    srai_ver \dst, \v, \imm
+.endm
+
+test sra
+    tests_shift sra, 0xa3c51249
+    tests_shift sra_sar, 0xa3c51249
+    tests_shift sra, 0x49a3c512
+    tests_shift sra_sar, 0x49a3c512
+test_end
+
+
+.macro src_set dst, src, v, imm
+    movi    a2, \imm
+    ssr     a2
+    movi    \src, (\v) & 0xffffffff
+    movi    a4, (\v) >> 32
+    src     \dst, a4, \src
+.endm
+
+.macro src_sar_set dst, src, v, imm
+    movi    a2, \imm
+    wsr     a2, sar
+    movi    \src, (\v) & 0xffffffff
+    movi    a4, (\v) >> 32
+    src     \dst, a4, \src
+.endm
+
+.macro src_ver dst, v, imm
+    src_sar_ver \dst, \v, (\imm) & 0x1f
+.endm
+
+.macro src_sar_ver dst, v, imm
+    mov     a2, \dst
+    movi    a3, ((\v) >> (\imm)) & 0xffffffff
+    assert  eq, a2, a3
+.endm
+
+test src
+    tests_shift src, 0xa3c51249215c3a94
+    tests_shift src_sar, 0xa3c51249215c3a94
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_timer.S b/tests/xtensa/test_timer.S
new file mode 100644
index 0000000..ede6395
--- /dev/null
+++ b/tests/xtensa/test_timer.S
@@ -0,0 +1,115 @@
+.include "macros.inc"
+
+test_suite timer
+
+test ccount
+    rsr     a3, ccount
+    rsr     a4, ccount
+    sub     a3, a4, a3
+    assert  eqi, a3, 1
+test_end
+
+test ccompare
+    movi    a2, 0
+    wsr     a2, intenable
+    rsr     a2, interrupt
+    wsr     a2, intclear
+    wsr     a2, ccompare1
+    wsr     a2, ccompare2
+
+    movi    a3, 20
+    rsr     a2, ccount
+    addi    a2, a2, 20
+    wsr     a2, ccompare0
+    rsr     a2, interrupt
+    assert  eqi, a2, 0
+    loop    a3, 1f
+    rsr     a3, interrupt
+    bnez    a3, 2f
+1:
+    test_fail
+2:
+test_end
+
+test ccompare0_interrupt
+    set_vector kernel, 2f
+    movi    a2, 0
+    wsr     a2, intenable
+    rsr     a2, interrupt
+    wsr     a2, intclear
+    wsr     a2, ccompare1
+    wsr     a2, ccompare2
+
+    movi    a3, 20
+    rsr     a2, ccount
+    addi    a2, a2, 20
+    wsr     a2, ccompare0
+    rsync
+    rsr     a2, interrupt
+    assert  eqi, a2, 0
+
+    movi    a2, 0x40
+    wsr     a2, intenable
+    rsil    a2, 0
+    loop    a3, 1f
+    nop
+1:
+    test_fail
+2:
+    rsr     a2, exccause
+    assert  eqi, a2, 4 /* LEVEL1_INTERRUPT_CAUSE */
+test_end
+
+test ccompare1_interrupt
+    set_vector level3, 2f
+    movi    a2, 0
+    wsr     a2, intenable
+    rsr     a2, interrupt
+    wsr     a2, intclear
+    wsr     a2, ccompare0
+    wsr     a2, ccompare2
+
+    movi    a3, 20
+    rsr     a2, ccount
+    addi    a2, a2, 20
+    wsr     a2, ccompare1
+    rsync
+    rsr     a2, interrupt
+    assert  eqi, a2, 0
+    movi    a2, 0x400
+    wsr     a2, intenable
+    rsil    a2, 2
+    loop    a3, 1f
+    nop
+1:
+    test_fail
+2:
+test_end
+
+test ccompare2_interrupt
+    set_vector level5, 2f
+    movi    a2, 0
+    wsr     a2, intenable
+    rsr     a2, interrupt
+    wsr     a2, intclear
+    wsr     a2, ccompare0
+    wsr     a2, ccompare1
+
+    movi    a3, 20
+    rsr     a2, ccount
+    addi    a2, a2, 20
+    wsr     a2, ccompare2
+    rsync
+    rsr     a2, interrupt
+    assert  eqi, a2, 0
+    movi    a2, 0x2000
+    wsr     a2, intenable
+    rsil    a2, 4
+    loop    a3, 1f
+    nop
+1:
+    test_fail
+2:
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/test_windowed.S b/tests/xtensa/test_windowed.S
new file mode 100644
index 0000000..cb2d39e
--- /dev/null
+++ b/tests/xtensa/test_windowed.S
@@ -0,0 +1,302 @@
+.include "macros.inc"
+
+test_suite windowed
+
+.altmacro
+
+.macro reset_window start
+    movi    a2, 0xff
+    wsr     a2, windowstart
+    rsync
+    movi    a2, 0
+    wsr     a2, windowbase
+    rsync
+    movi    a2, \start
+    wsr     a2, windowstart
+    rsync
+.endm
+
+.macro overflow_test shift, window, probe_ok, probe_ex
+    set_vector window_overflow_4, 0
+    set_vector window_overflow_8, 0
+    set_vector window_overflow_12, 0
+
+    movi    a2, 1 | (((1 << ((\window) / 4)) | 1) << ((\shift) / 4))
+    wsr     a2, windowstart
+    reset_ps
+
+    mov     a2, a\probe_ok
+    set_vector window_overflow_\window, 10f
+1:
+    mov     a2, a\probe_ex
+    test_fail
+10:
+    rsr     a2, epc1
+    movi    a3, 1b
+    assert  eq, a2, a3
+    movi    a2, 2f
+    wsr     a2, epc1
+
+    rsr     a2, windowbase
+    movi    a3, (\shift) / 4
+    assert  eq, a2, a3
+    rsr     a2, ps
+    movi    a3, 0x4001f
+    assert  eq, a2, a3
+    rfwo
+    test_fail
+2:
+    rsr     a2, windowbase
+    assert  eqi, a2, 0
+    rsr     a2, windowstart
+    movi    a3, 1 | ((1 << ((\window) / 4)) << ((\shift) / 4))
+    assert  eq, a2, a3
+    rsr     a2, ps
+    movi    a3, 0x4000f
+    assert  eq, a2, a3
+.endm
+
+.macro overflow_tests shift, window, probe
+    .if \probe < 15
+    overflow_test \shift, \window, %((\shift) - 1), \probe
+    overflow_tests \shift, \window, %((\probe) + 1)
+    .endif
+.endm
+
+.macro all_overflow_tests
+    .irp shift, 4, 8, 12
+    .irp window, 4, 8, 12
+    overflow_tests \shift, \window, \shift
+    .endr
+    .endr
+.endm
+
+test overflow
+    all_overflow_tests
+test_end
+
+
+.macro underflow_test window
+    set_vector window_underflow_4, 0
+    set_vector window_underflow_8, 0
+    set_vector window_underflow_12, 0
+
+    set_vector window_underflow_\window, 10f
+
+    reset_window 1
+    reset_ps
+
+    ssai    2
+    movi    a2, 2f
+    slli    a2, a2, 2
+    movi    a3, (\window) / 4
+    src     a0, a3, a2
+1:
+    retw
+    test_fail
+10:
+    rsr     a2, epc1
+    movi    a3, 1b
+    assert  eq, a2, a3
+    movi    a2, 2f
+    wsr     a2, epc1
+
+    rsr     a2, ps
+    movi    a3, 0x4001f
+    assert  eq, a2, a3
+    rsr     a2, windowbase
+    assert  eqi, a2, 8 - ((\window) / 4)
+    rsr     a2, windowstart
+    assert  eqi, a2, 1
+    rfwu
+2:
+    rsr     a2, ps
+    movi    a3, 0x4000f
+    assert  eq, a2, a3
+    rsr     a2, windowbase
+    assert  eqi, a2, 0
+    rsr     a2, windowstart
+    assert  bsi, a2, 0
+    assert  bsi, a2, 8 - ((\window) / 4)
+.endm
+
+test underflow
+    set_vector window_overflow_4, 0
+    set_vector window_overflow_8, 0
+    set_vector window_overflow_12, 0
+
+    underflow_test 4
+    underflow_test 8
+    underflow_test 12
+test_end
+
+
+.macro retw_test window
+    reset_window %(1 | (1 << (8 - (\window) / 4)))
+    reset_ps
+
+    ssai    2
+    movi    a2, 1f
+    slli    a2, a2, 2
+    movi    a3, (\window) / 4
+    src     a0, a3, a2
+    retw
+    test_fail
+1:
+    rsr     a2, ps
+    movi    a3, 0x4000f
+    assert  eq, a2, a3
+    rsr     a2, windowbase
+    assert  eqi, a2, 8 - ((\window) / 4)
+    rsr     a2, windowstart
+    assert  bci, a2, 0
+    assert  bsi, a2, 8 - ((\window) / 4)
+.endm
+
+test retw
+    set_vector window_underflow_4, 0
+    set_vector window_underflow_8, 0
+    set_vector window_underflow_12, 0
+
+    retw_test 4
+    retw_test 8
+    retw_test 12
+test_end
+
+test movsp
+    set_vector kernel, 2f
+
+    reset_window 1
+    reset_ps
+1:
+    movsp   a2, a3
+    test_fail
+2:
+    rsr     a2, exccause
+    assert  eqi, a2, 5
+    rsr     a2, epc1
+    movi    a3, 1b
+    assert  eq, a2, a3
+
+    set_vector kernel, 0
+
+    reset_window 0x81
+    reset_ps
+
+    movsp   a2, a3
+test_end
+
+test rotw
+    reset_window 0x4b
+    reset_ps
+
+    movi    a3, 0x10
+
+    rotw    1
+    rsr     a2, windowbase
+    assert  eqi, a2, 1
+    movi    a3, 0x11
+    movi    a7, 0x12
+
+    rotw    2
+    rsr     a2, windowbase
+    assert  eqi, a2, 3
+    movi    a3, 0x13
+    movi    a7, 0x14
+    movi    a11, 0x15
+
+    rotw    3
+    rsr     a2, windowbase
+    assert  eqi, a2, 6
+    movi    a3, 0x16
+    movi    a7, 0x17
+
+    movi    a2, 0x44
+    wsr     a2, windowstart
+    rsync
+
+    movi    a2, 0x10
+    assert  eq, a2, a11
+    movi    a11, 0x18
+    movi    a2, 0x11
+    assert  eq, a2, a15
+    movi    a15, 0x19
+
+    rotw    4
+    movi    a2, 0x12
+    assert  eq, a2, a3
+    movi    a2, 0x13
+    assert  eq, a2, a7
+    movi    a2, 0x14
+    assert  eq, a2, a11
+    movi    a2, 0x15
+    assert  eq, a2, a15
+
+    movi    a2, 0x5
+    wsr     a2, windowstart
+    rsync
+
+    rotw    -2
+    movi    a2, 0x18
+    assert  eq, a2, a3
+    movi    a2, 0x19
+    assert  eq, a2, a7
+test_end
+
+.macro callw_test window
+    call\window 2f
+1:
+    test_fail
+    .align  4
+2:
+    rsr     a2, windowbase
+    assert  eqi, a2, 0
+    rsr     a2, ps
+    movi    a3, 0x4000f | ((\window) << 14)
+    assert  eq, a2, a3
+    movi    a2, 1b
+    slli    a2, a2, 2
+    ssai    2
+    movi    a3, (\window) / 4
+    src     a2, a3, a2
+    assert  eq, a2, a\window
+.endm
+
+test callw
+    reset_window 0x1
+    reset_ps
+
+    callw_test 4
+    callw_test 8
+    callw_test 12
+test_end
+
+
+.macro entry_test window
+    reset_window 0x1
+    reset_ps
+    movi    a2, 0x4000f | ((\window) << 14)
+    wsr     a2, ps
+    isync
+    movi    a3, 0x12345678
+    j       1f
+    .align  4
+1:
+    entry   a3, 0x5678
+    movi    a2, 0x12340000
+    assert  eq, a2, a3
+    rsr     a2, windowbase
+    assert  eqi, a2, (\window) / 4
+    rsr     a2, windowstart
+    movi    a3, 1 | (1 << ((\window) / 4))
+    assert  eq, a2, a3
+    rotw    -(\window) / 4
+.endm
+
+test entry
+    entry_test 4
+    entry_test 8
+    entry_test 12
+test_end
+
+test_suite_end
diff --git a/tests/xtensa/vectors.S b/tests/xtensa/vectors.S
new file mode 100644
index 0000000..265a181
--- /dev/null
+++ b/tests/xtensa/vectors.S
@@ -0,0 +1,39 @@
+.macro vector name
+
+.section .vector.\name
+    j       1f
+.section .vector.\name\().text
+1:
+    wsr     a2, excsave1
+    movi    a2, handler_\name
+    l32i    a2, a2, 0
+    beqz    a2, 1f
+    jx      a2
+1:
+    movi    a3, 1b
+    movi    a2, 1
+    simcall
+
+.align 4
+.global handler_\name
+handler_\name\(): .word 0
+
+.endm
+
+vector window_overflow_4
+vector window_overflow_8
+vector window_overflow_12
+vector window_underflow_4
+vector window_underflow_8
+vector window_underflow_12
+
+vector level2
+vector level3
+vector level4
+vector level5
+vector level6
+vector level7
+
+vector kernel
+vector user
+vector double
commit 16e7caae53f6143d0d4d2cb1dadb048b4de790a5
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Tue Sep 6 03:55:56 2011 +0400

    MAINTAINERS: add xtensa maintainer
    
    Add myself as target-xtensa and DC232B maintainer.
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/MAINTAINERS b/MAINTAINERS
index 508ea1e..72b2099 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -115,6 +115,12 @@ M: qemu-devel at nongnu.org
 S: Odd Fixes
 F: target-i386/
 
+Xtensa
+M: Max Filippov <jcmvbkbc at gmail.com>
+W: http://kkv.spb.su/doku.php?id=etc:users:jcmvbkbc:qemu-target-xtensa
+S: Maintained
+F: target-xtensa/
+
 Guest CPU Cores (KVM):
 ----------------------
 
@@ -335,6 +341,13 @@ M: Anthony Liguori <aliguori at us.ibm.com>
 S: Supported
 F: hw/pc.[ch] hw/pc_piix.c
 
+Xtensa Machines
+---------------
+DC232B
+M: Max Filippov <jcmvbkbc at gmail.com>
+S: Maintained
+F: hw/xtensa_dc232b.c
+
 Devices
 -------
 IDE
commit 47d05a8629b0b37770676e80e1075baa7e691b36
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Tue Sep 6 03:55:55 2011 +0400

    target-xtensa: add dc232b core and board
    
    This is Diamond 232L Standard Core Rev.B (LE).
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/Makefile.target b/Makefile.target
index ca8eaf2..f708453 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -370,6 +370,7 @@ obj-alpha-y += vga.o cirrus_vga.o
 
 obj-xtensa-y += xtensa_pic.o
 obj-xtensa-y += xtensa_sample.o
+obj-xtensa-y += xtensa_dc232b.o
 obj-xtensa-y += xtensa-semi.o
 
 main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
diff --git a/hw/xtensa_dc232b.c b/hw/xtensa_dc232b.c
new file mode 100644
index 0000000..015d6aa
--- /dev/null
+++ b/hw/xtensa_dc232b.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "sysemu.h"
+#include "boards.h"
+#include "loader.h"
+#include "elf.h"
+#include "memory.h"
+#include "exec-memory.h"
+
+static uint64_t translate_phys_addr(void *env, uint64_t addr)
+{
+    return cpu_get_phys_page_debug(env, addr);
+}
+
+static void dc232b_reset(void *env)
+{
+    cpu_reset(env);
+}
+
+static void dc232b_init(ram_addr_t ram_size,
+        const char *boot_device,
+        const char *kernel_filename, const char *kernel_cmdline,
+        const char *initrd_filename, const char *cpu_model)
+{
+    CPUState *env = NULL;
+    MemoryRegion *ram, *rom;
+    int n;
+
+    for (n = 0; n < smp_cpus; n++) {
+        env = cpu_init(cpu_model);
+        if (!env) {
+            fprintf(stderr, "Unable to find CPU definition\n");
+            exit(1);
+        }
+        env->sregs[PRID] = n;
+        qemu_register_reset(dc232b_reset, env);
+        /* Need MMU initialized prior to ELF loading,
+         * so that ELF gets loaded into virtual addresses
+         */
+        dc232b_reset(env);
+    }
+
+    ram = g_malloc(sizeof(*ram));
+    memory_region_init_ram(ram, NULL, "xtensa.sram", ram_size);
+    memory_region_add_subregion(get_system_memory(), 0, ram);
+
+    rom = g_malloc(sizeof(*rom));
+    memory_region_init_ram(rom, NULL, "xtensa.rom", 0x1000);
+    memory_region_add_subregion(get_system_memory(), 0xfe000000, rom);
+
+    if (kernel_filename) {
+        uint64_t elf_entry;
+        uint64_t elf_lowaddr;
+#ifdef TARGET_WORDS_BIGENDIAN
+        int success = load_elf(kernel_filename, translate_phys_addr, env,
+                &elf_entry, &elf_lowaddr, NULL, 1, ELF_MACHINE, 0);
+#else
+        int success = load_elf(kernel_filename, translate_phys_addr, env,
+                &elf_entry, &elf_lowaddr, NULL, 0, ELF_MACHINE, 0);
+#endif
+        if (success > 0) {
+            env->pc = elf_entry;
+        }
+    }
+}
+
+static void xtensa_dc232b_init(ram_addr_t ram_size,
+                     const char *boot_device,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename, const char *cpu_model)
+{
+    if (!cpu_model) {
+        cpu_model = "dc232b";
+    }
+    dc232b_init(ram_size, boot_device, kernel_filename, kernel_cmdline,
+            initrd_filename, cpu_model);
+}
+
+static QEMUMachine xtensa_dc232b_machine = {
+    .name = "dc232b",
+    .desc = "Diamond 232L Standard Core Rev.B (LE) (dc232b)",
+    .init = xtensa_dc232b_init,
+    .max_cpus = 4,
+};
+
+static void xtensa_dc232b_machine_init(void)
+{
+    qemu_register_machine(&xtensa_dc232b_machine);
+}
+
+machine_init(xtensa_dc232b_machine_init);
diff --git a/target-xtensa/gdb-config-dc232b.c b/target-xtensa/gdb-config-dc232b.c
new file mode 100644
index 0000000..13aba5e
--- /dev/null
+++ b/target-xtensa/gdb-config-dc232b.c
@@ -0,0 +1,261 @@
+/* Configuration for the Xtensa architecture for GDB, the GNU debugger.
+
+   Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 of the License, or
+   (at your option) any later version.
+
+   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, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+  XTREG(0,   0, 32, 4, 4, 0x0020, 0x0006, -2, 9, 0x0100, pc,
+          0, 0, 0, 0, 0, 0)
+  XTREG(1,   4, 32, 4, 4, 0x0100, 0x0006, -2, 1, 0x0002, ar0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(2,   8, 32, 4, 4, 0x0101, 0x0006, -2, 1, 0x0002, ar1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(3,  12, 32, 4, 4, 0x0102, 0x0006, -2, 1, 0x0002, ar2,
+          0, 0, 0, 0, 0, 0)
+  XTREG(4,  16, 32, 4, 4, 0x0103, 0x0006, -2, 1, 0x0002, ar3,
+          0, 0, 0, 0, 0, 0)
+  XTREG(5,  20, 32, 4, 4, 0x0104, 0x0006, -2, 1, 0x0002, ar4,
+          0, 0, 0, 0, 0, 0)
+  XTREG(6,  24, 32, 4, 4, 0x0105, 0x0006, -2, 1, 0x0002, ar5,
+          0, 0, 0, 0, 0, 0)
+  XTREG(7,  28, 32, 4, 4, 0x0106, 0x0006, -2, 1, 0x0002, ar6,
+          0, 0, 0, 0, 0, 0)
+  XTREG(8,  32, 32, 4, 4, 0x0107, 0x0006, -2, 1, 0x0002, ar7,
+          0, 0, 0, 0, 0, 0)
+  XTREG(9,  36, 32, 4, 4, 0x0108, 0x0006, -2, 1, 0x0002, ar8,
+          0, 0, 0, 0, 0, 0)
+  XTREG(10,  40, 32, 4, 4, 0x0109, 0x0006, -2, 1, 0x0002, ar9,
+          0, 0, 0, 0, 0, 0)
+  XTREG(11,  44, 32, 4, 4, 0x010a, 0x0006, -2, 1, 0x0002, ar10,
+          0, 0, 0, 0, 0, 0)
+  XTREG(12,  48, 32, 4, 4, 0x010b, 0x0006, -2, 1, 0x0002, ar11,
+          0, 0, 0, 0, 0, 0)
+  XTREG(13,  52, 32, 4, 4, 0x010c, 0x0006, -2, 1, 0x0002, ar12,
+          0, 0, 0, 0, 0, 0)
+  XTREG(14,  56, 32, 4, 4, 0x010d, 0x0006, -2, 1, 0x0002, ar13,
+          0, 0, 0, 0, 0, 0)
+  XTREG(15,  60, 32, 4, 4, 0x010e, 0x0006, -2, 1, 0x0002, ar14,
+          0, 0, 0, 0, 0, 0)
+  XTREG(16,  64, 32, 4, 4, 0x010f, 0x0006, -2, 1, 0x0002, ar15,
+          0, 0, 0, 0, 0, 0)
+  XTREG(17,  68, 32, 4, 4, 0x0110, 0x0006, -2, 1, 0x0002, ar16,
+          0, 0, 0, 0, 0, 0)
+  XTREG(18,  72, 32, 4, 4, 0x0111, 0x0006, -2, 1, 0x0002, ar17,
+          0, 0, 0, 0, 0, 0)
+  XTREG(19,  76, 32, 4, 4, 0x0112, 0x0006, -2, 1, 0x0002, ar18,
+          0, 0, 0, 0, 0, 0)
+  XTREG(20,  80, 32, 4, 4, 0x0113, 0x0006, -2, 1, 0x0002, ar19,
+          0, 0, 0, 0, 0, 0)
+  XTREG(21,  84, 32, 4, 4, 0x0114, 0x0006, -2, 1, 0x0002, ar20,
+          0, 0, 0, 0, 0, 0)
+  XTREG(22,  88, 32, 4, 4, 0x0115, 0x0006, -2, 1, 0x0002, ar21,
+          0, 0, 0, 0, 0, 0)
+  XTREG(23,  92, 32, 4, 4, 0x0116, 0x0006, -2, 1, 0x0002, ar22,
+          0, 0, 0, 0, 0, 0)
+  XTREG(24,  96, 32, 4, 4, 0x0117, 0x0006, -2, 1, 0x0002, ar23,
+          0, 0, 0, 0, 0, 0)
+  XTREG(25, 100, 32, 4, 4, 0x0118, 0x0006, -2, 1, 0x0002, ar24,
+          0, 0, 0, 0, 0, 0)
+  XTREG(26, 104, 32, 4, 4, 0x0119, 0x0006, -2, 1, 0x0002, ar25,
+          0, 0, 0, 0, 0, 0)
+  XTREG(27, 108, 32, 4, 4, 0x011a, 0x0006, -2, 1, 0x0002, ar26,
+          0, 0, 0, 0, 0, 0)
+  XTREG(28, 112, 32, 4, 4, 0x011b, 0x0006, -2, 1, 0x0002, ar27,
+          0, 0, 0, 0, 0, 0)
+  XTREG(29, 116, 32, 4, 4, 0x011c, 0x0006, -2, 1, 0x0002, ar28,
+          0, 0, 0, 0, 0, 0)
+  XTREG(30, 120, 32, 4, 4, 0x011d, 0x0006, -2, 1, 0x0002, ar29,
+          0, 0, 0, 0, 0, 0)
+  XTREG(31, 124, 32, 4, 4, 0x011e, 0x0006, -2, 1, 0x0002, ar30,
+          0, 0, 0, 0, 0, 0)
+  XTREG(32, 128, 32, 4, 4, 0x011f, 0x0006, -2, 1, 0x0002, ar31,
+          0, 0, 0, 0, 0, 0)
+  XTREG(33, 132, 32, 4, 4, 0x0200, 0x0006, -2, 2, 0x1100, lbeg,
+          0, 0, 0, 0, 0, 0)
+  XTREG(34, 136, 32, 4, 4, 0x0201, 0x0006, -2, 2, 0x1100, lend,
+          0, 0, 0, 0, 0, 0)
+  XTREG(35, 140, 32, 4, 4, 0x0202, 0x0006, -2, 2, 0x1100, lcount,
+          0, 0, 0, 0, 0, 0)
+  XTREG(36, 144,  6, 4, 4, 0x0203, 0x0006, -2, 2, 0x1100, sar,
+          0, 0, 0, 0, 0, 0)
+  XTREG(37, 148, 32, 4, 4, 0x0205, 0x0006, -2, 2, 0x1100, litbase,
+          0, 0, 0, 0, 0, 0)
+  XTREG(38, 152,  3, 4, 4, 0x0248, 0x0006, -2, 2, 0x1002, windowbase,
+          0, 0, 0, 0, 0, 0)
+  XTREG(39, 156,  8, 4, 4, 0x0249, 0x0006, -2, 2, 0x1002, windowstart,
+          0, 0, 0, 0, 0, 0)
+  XTREG(40, 160, 32, 4, 4, 0x02b0, 0x0002, -2, 2, 0x1000, sr176,
+          0, 0, 0, 0, 0, 0)
+  XTREG(41, 164, 32, 4, 4, 0x02d0, 0x0002, -2, 2, 0x1000, sr208,
+          0, 0, 0, 0, 0, 0)
+  XTREG(42, 168, 19, 4, 4, 0x02e6, 0x0006, -2, 2, 0x1100, ps,
+          0, 0, 0, 0, 0, 0)
+  XTREG(43, 172, 32, 4, 4, 0x03e7, 0x0006, -2, 3, 0x0110, threadptr,
+          0, 0, 0, 0, 0, 0)
+  XTREG(44, 176, 32, 4, 4, 0x020c, 0x0006, -1, 2, 0x1100, scompare1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(45, 180, 32, 4, 4, 0x0210, 0x0006, -1, 2, 0x1100, acclo,
+          0, 0, 0, 0, 0, 0)
+  XTREG(46, 184,  8, 4, 4, 0x0211, 0x0006, -1, 2, 0x1100, acchi,
+          0, 0, 0, 0, 0, 0)
+  XTREG(47, 188, 32, 4, 4, 0x0220, 0x0006, -1, 2, 0x1100, m0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(48, 192, 32, 4, 4, 0x0221, 0x0006, -1, 2, 0x1100, m1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(49, 196, 32, 4, 4, 0x0222, 0x0006, -1, 2, 0x1100, m2,
+          0, 0, 0, 0, 0, 0)
+  XTREG(50, 200, 32, 4, 4, 0x0223, 0x0006, -1, 2, 0x1100, m3,
+          0, 0, 0, 0, 0, 0)
+  XTREG(51, 204, 32, 4, 4, 0x03e6, 0x000e, -1, 3, 0x0110, expstate,
+          0, 0, 0, 0, 0, 0)
+  XTREG(52, 208, 32, 4, 4, 0x0253, 0x0007, -2, 2, 0x1000, ptevaddr,
+          0, 0, 0, 0, 0, 0)
+  XTREG(53, 212, 32, 4, 4, 0x0259, 0x000d, -2, 2, 0x1000, mmid,
+          0, 0, 0, 0, 0, 0)
+  XTREG(54, 216, 32, 4, 4, 0x025a, 0x0007, -2, 2, 0x1000, rasid,
+          0, 0, 0, 0, 0, 0)
+  XTREG(55, 220, 18, 4, 4, 0x025b, 0x0007, -2, 2, 0x1000, itlbcfg,
+          0, 0, 0, 0, 0, 0)
+  XTREG(56, 224, 18, 4, 4, 0x025c, 0x0007, -2, 2, 0x1000, dtlbcfg,
+          0, 0, 0, 0, 0, 0)
+  XTREG(57, 228,  2, 4, 4, 0x0260, 0x0007, -2, 2, 0x1000, ibreakenable,
+          0, 0, 0, 0, 0, 0)
+  XTREG(58, 232, 32, 4, 4, 0x0268, 0x0007, -2, 2, 0x1000, ddr,
+          0, 0, 0, 0, 0, 0)
+  XTREG(59, 236, 32, 4, 4, 0x0280, 0x0007, -2, 2, 0x1000, ibreaka0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(60, 240, 32, 4, 4, 0x0281, 0x0007, -2, 2, 0x1000, ibreaka1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(61, 244, 32, 4, 4, 0x0290, 0x0007, -2, 2, 0x1000, dbreaka0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(62, 248, 32, 4, 4, 0x0291, 0x0007, -2, 2, 0x1000, dbreaka1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(63, 252, 32, 4, 4, 0x02a0, 0x0007, -2, 2, 0x1000, dbreakc0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(64, 256, 32, 4, 4, 0x02a1, 0x0007, -2, 2, 0x1000, dbreakc1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(65, 260, 32, 4, 4, 0x02b1, 0x0007, -2, 2, 0x1000, epc1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(66, 264, 32, 4, 4, 0x02b2, 0x0007, -2, 2, 0x1000, epc2,
+          0, 0, 0, 0, 0, 0)
+  XTREG(67, 268, 32, 4, 4, 0x02b3, 0x0007, -2, 2, 0x1000, epc3,
+          0, 0, 0, 0, 0, 0)
+  XTREG(68, 272, 32, 4, 4, 0x02b4, 0x0007, -2, 2, 0x1000, epc4,
+          0, 0, 0, 0, 0, 0)
+  XTREG(69, 276, 32, 4, 4, 0x02b5, 0x0007, -2, 2, 0x1000, epc5,
+          0, 0, 0, 0, 0, 0)
+  XTREG(70, 280, 32, 4, 4, 0x02b6, 0x0007, -2, 2, 0x1000, epc6,
+          0, 0, 0, 0, 0, 0)
+  XTREG(71, 284, 32, 4, 4, 0x02b7, 0x0007, -2, 2, 0x1000, epc7,
+          0, 0, 0, 0, 0, 0)
+  XTREG(72, 288, 32, 4, 4, 0x02c0, 0x0007, -2, 2, 0x1000, depc,
+          0, 0, 0, 0, 0, 0)
+  XTREG(73, 292, 19, 4, 4, 0x02c2, 0x0007, -2, 2, 0x1000, eps2,
+          0, 0, 0, 0, 0, 0)
+  XTREG(74, 296, 19, 4, 4, 0x02c3, 0x0007, -2, 2, 0x1000, eps3,
+          0, 0, 0, 0, 0, 0)
+  XTREG(75, 300, 19, 4, 4, 0x02c4, 0x0007, -2, 2, 0x1000, eps4,
+          0, 0, 0, 0, 0, 0)
+  XTREG(76, 304, 19, 4, 4, 0x02c5, 0x0007, -2, 2, 0x1000, eps5,
+          0, 0, 0, 0, 0, 0)
+  XTREG(77, 308, 19, 4, 4, 0x02c6, 0x0007, -2, 2, 0x1000, eps6,
+          0, 0, 0, 0, 0, 0)
+  XTREG(78, 312, 19, 4, 4, 0x02c7, 0x0007, -2, 2, 0x1000, eps7,
+          0, 0, 0, 0, 0, 0)
+  XTREG(79, 316, 32, 4, 4, 0x02d1, 0x0007, -2, 2, 0x1000, excsave1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(80, 320, 32, 4, 4, 0x02d2, 0x0007, -2, 2, 0x1000, excsave2,
+          0, 0, 0, 0, 0, 0)
+  XTREG(81, 324, 32, 4, 4, 0x02d3, 0x0007, -2, 2, 0x1000, excsave3,
+          0, 0, 0, 0, 0, 0)
+  XTREG(82, 328, 32, 4, 4, 0x02d4, 0x0007, -2, 2, 0x1000, excsave4,
+          0, 0, 0, 0, 0, 0)
+  XTREG(83, 332, 32, 4, 4, 0x02d5, 0x0007, -2, 2, 0x1000, excsave5,
+          0, 0, 0, 0, 0, 0)
+  XTREG(84, 336, 32, 4, 4, 0x02d6, 0x0007, -2, 2, 0x1000, excsave6,
+          0, 0, 0, 0, 0, 0)
+  XTREG(85, 340, 32, 4, 4, 0x02d7, 0x0007, -2, 2, 0x1000, excsave7,
+          0, 0, 0, 0, 0, 0)
+  XTREG(86, 344,  8, 4, 4, 0x02e0, 0x0007, -2, 2, 0x1000, cpenable,
+          0, 0, 0, 0, 0, 0)
+  XTREG(87, 348, 22, 4, 4, 0x02e2, 0x000b, -2, 2, 0x1000, interrupt,
+          0, 0, 0, 0, 0, 0)
+  XTREG(88, 352, 22, 4, 4, 0x02e2, 0x000d, -2, 2, 0x1000, intset,
+          0, 0, 0, 0, 0, 0)
+  XTREG(89, 356, 22, 4, 4, 0x02e3, 0x000d, -2, 2, 0x1000, intclear,
+          0, 0, 0, 0, 0, 0)
+  XTREG(90, 360, 22, 4, 4, 0x02e4, 0x0007, -2, 2, 0x1000, intenable,
+          0, 0, 0, 0, 0, 0)
+  XTREG(91, 364, 32, 4, 4, 0x02e7, 0x0007, -2, 2, 0x1000, vecbase,
+          0, 0, 0, 0, 0, 0)
+  XTREG(92, 368,  6, 4, 4, 0x02e8, 0x0007, -2, 2, 0x1000, exccause,
+          0, 0, 0, 0, 0, 0)
+  XTREG(93, 372, 12, 4, 4, 0x02e9, 0x0003, -2, 2, 0x1000, debugcause,
+          0, 0, 0, 0, 0, 0)
+  XTREG(94, 376, 32, 4, 4, 0x02ea, 0x000f, -2, 2, 0x1000, ccount,
+          0, 0, 0, 0, 0, 0)
+  XTREG(95, 380, 32, 4, 4, 0x02eb, 0x0003, -2, 2, 0x1000, prid,
+          0, 0, 0, 0, 0, 0)
+  XTREG(96, 384, 32, 4, 4, 0x02ec, 0x000f, -2, 2, 0x1000, icount,
+          0, 0, 0, 0, 0, 0)
+  XTREG(97, 388,  4, 4, 4, 0x02ed, 0x0007, -2, 2, 0x1000, icountlevel,
+          0, 0, 0, 0, 0, 0)
+  XTREG(98, 392, 32, 4, 4, 0x02ee, 0x0007, -2, 2, 0x1000, excvaddr,
+          0, 0, 0, 0, 0, 0)
+  XTREG(99, 396, 32, 4, 4, 0x02f0, 0x000f, -2, 2, 0x1000, ccompare0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(100, 400, 32, 4, 4, 0x02f1, 0x000f, -2, 2, 0x1000, ccompare1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(101, 404, 32, 4, 4, 0x02f2, 0x000f, -2, 2, 0x1000, ccompare2,
+          0, 0, 0, 0, 0, 0)
+  XTREG(102, 408, 32, 4, 4, 0x02f4, 0x0007, -2, 2, 0x1000, misc0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(103, 412, 32, 4, 4, 0x02f5, 0x0007, -2, 2, 0x1000, misc1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(104, 416, 32, 4, 4, 0x0000, 0x0006, -2, 8, 0x0100, a0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(105, 420, 32, 4, 4, 0x0001, 0x0006, -2, 8, 0x0100, a1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(106, 424, 32, 4, 4, 0x0002, 0x0006, -2, 8, 0x0100, a2,
+          0, 0, 0, 0, 0, 0)
+  XTREG(107, 428, 32, 4, 4, 0x0003, 0x0006, -2, 8, 0x0100, a3,
+          0, 0, 0, 0, 0, 0)
+  XTREG(108, 432, 32, 4, 4, 0x0004, 0x0006, -2, 8, 0x0100, a4,
+          0, 0, 0, 0, 0, 0)
+  XTREG(109, 436, 32, 4, 4, 0x0005, 0x0006, -2, 8, 0x0100, a5,
+          0, 0, 0, 0, 0, 0)
+  XTREG(110, 440, 32, 4, 4, 0x0006, 0x0006, -2, 8, 0x0100, a6,
+          0, 0, 0, 0, 0, 0)
+  XTREG(111, 444, 32, 4, 4, 0x0007, 0x0006, -2, 8, 0x0100, a7,
+          0, 0, 0, 0, 0, 0)
+  XTREG(112, 448, 32, 4, 4, 0x0008, 0x0006, -2, 8, 0x0100, a8,
+          0, 0, 0, 0, 0, 0)
+  XTREG(113, 452, 32, 4, 4, 0x0009, 0x0006, -2, 8, 0x0100, a9,
+          0, 0, 0, 0, 0, 0)
+  XTREG(114, 456, 32, 4, 4, 0x000a, 0x0006, -2, 8, 0x0100, a10,
+          0, 0, 0, 0, 0, 0)
+  XTREG(115, 460, 32, 4, 4, 0x000b, 0x0006, -2, 8, 0x0100, a11,
+          0, 0, 0, 0, 0, 0)
+  XTREG(116, 464, 32, 4, 4, 0x000c, 0x0006, -2, 8, 0x0100, a12,
+          0, 0, 0, 0, 0, 0)
+  XTREG(117, 468, 32, 4, 4, 0x000d, 0x0006, -2, 8, 0x0100, a13,
+          0, 0, 0, 0, 0, 0)
+  XTREG(118, 472, 32, 4, 4, 0x000e, 0x0006, -2, 8, 0x0100, a14,
+          0, 0, 0, 0, 0, 0)
+  XTREG(119, 476, 32, 4, 4, 0x000f, 0x0006, -2, 8, 0x0100, a15,
+          0, 0, 0, 0, 0, 0)
diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c
index 9e18984..c8ba74e 100644
--- a/target-xtensa/helper.c
+++ b/target-xtensa/helper.c
@@ -107,6 +107,174 @@ static const XtensaConfig core_config[] = {
             [0] = 0,
         },
         .clock_freq_khz = 912000,
+    }, {
+        .name = "dc232b",
+        .options = -1 ^
+            (XTENSA_OPTION_BIT(XTENSA_OPTION_HW_ALIGNMENT) |
+             XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) |
+             XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION)),
+        .gdb_regmap = {
+            .num_regs = 120,
+            .num_core_regs = 52,
+            .reg = {
+#include "gdb-config-dc232b.c"
+            }
+        },
+        .nareg = 32,
+        .ndepc = 1,
+        .excm_level = 3,
+        .vecbase = 0xd0000000,
+        .exception_vector = {
+            [EXC_RESET] = 0xfe000000,
+            [EXC_WINDOW_OVERFLOW4] = 0xd0000000,
+            [EXC_WINDOW_UNDERFLOW4] = 0xd0000040,
+            [EXC_WINDOW_OVERFLOW8] = 0xd0000080,
+            [EXC_WINDOW_UNDERFLOW8] = 0xd00000c0,
+            [EXC_WINDOW_OVERFLOW12] = 0xd0000100,
+            [EXC_WINDOW_UNDERFLOW12] = 0xd0000140,
+            [EXC_KERNEL] = 0xd0000300,
+            [EXC_USER] = 0xd0000340,
+            [EXC_DOUBLE] = 0xd00003c0,
+        },
+        .ninterrupt = 22,
+        .nlevel = 6,
+        .interrupt_vector = {
+            0,
+            0,
+            0xd0000180,
+            0xd00001c0,
+            0xd0000200,
+            0xd0000240,
+            0xd0000280,
+            0xd00002c0,
+        },
+        .level_mask = {
+            [1] = 0x1f80ff,
+            [2] = 0x000100,
+            [3] = 0x200e00,
+            [4] = 0x001000,
+            [5] = 0x002000,
+            [6] = 0x000000,
+            [7] = 0x004000,
+        },
+        .inttype_mask = {
+            [INTTYPE_EDGE] = 0x3f8000,
+            [INTTYPE_NMI] = 0x4000,
+            [INTTYPE_SOFTWARE] = 0x880,
+        },
+        .interrupt = {
+            [0] = {
+                .level = 1,
+                .inttype = INTTYPE_LEVEL,
+            },
+            [1] = {
+                .level = 1,
+                .inttype = INTTYPE_LEVEL,
+            },
+            [2] = {
+                .level = 1,
+                .inttype = INTTYPE_LEVEL,
+            },
+            [3] = {
+                .level = 1,
+                .inttype = INTTYPE_LEVEL,
+            },
+            [4] = {
+                .level = 1,
+                .inttype = INTTYPE_LEVEL,
+            },
+            [5] = {
+                .level = 1,
+                .inttype = INTTYPE_LEVEL,
+            },
+            [6] = {
+                .level = 1,
+                .inttype = INTTYPE_TIMER,
+            },
+            [7] = {
+                .level = 1,
+                .inttype = INTTYPE_SOFTWARE,
+            },
+            [8] = {
+                .level = 2,
+                .inttype = INTTYPE_LEVEL,
+            },
+            [9] = {
+                .level = 3,
+                .inttype = INTTYPE_LEVEL,
+            },
+            [10] = {
+                .level = 3,
+                .inttype = INTTYPE_TIMER,
+            },
+            [11] = {
+                .level = 3,
+                .inttype = INTTYPE_SOFTWARE,
+            },
+            [12] = {
+                .level = 4,
+                .inttype = INTTYPE_LEVEL,
+            },
+            [13] = {
+                .level = 5,
+                .inttype = INTTYPE_TIMER,
+            },
+            [14] = {
+                .level = 7,
+                .inttype = INTTYPE_NMI,
+            },
+            [15] = {
+                .level = 1,
+                .inttype = INTTYPE_EDGE,
+            },
+            [16] = {
+                .level = 1,
+                .inttype = INTTYPE_EDGE,
+            },
+            [17] = {
+                .level = 1,
+                .inttype = INTTYPE_EDGE,
+            },
+            [18] = {
+                .level = 1,
+                .inttype = INTTYPE_EDGE,
+            },
+            [19] = {
+                .level = 1,
+                .inttype = INTTYPE_EDGE,
+            },
+            [20] = {
+                .level = 1,
+                .inttype = INTTYPE_EDGE,
+            },
+            [21] = {
+                .level = 3,
+                .inttype = INTTYPE_EDGE,
+            },
+        },
+        .nccompare = 3,
+        .timerint = {
+            [0] = 6,
+            [1] = 10,
+            [2] = 13,
+        },
+        .clock_freq_khz = 912000,
+        .itlb = {
+            .nways = 7,
+            .way_size = {
+                4, 4, 4, 4, 4, 2, 2,
+            },
+            .varway56 = false,
+            .nrefillentries = 16,
+        },
+        .dtlb = {
+            .nways = 10,
+            .way_size = {
+                4, 4, 4, 4, 4, 2, 2, 1, 1, 1,
+            },
+            .varway56 = false,
+            .nrefillentries = 16,
+        },
     },
 };
 
commit 4dd85b6b638c40e68fbc5b6046b27d0ef3627d7c
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Tue Sep 6 03:55:54 2011 +0400

    target-xtensa: implement boolean option
    
    See ISA, 4.3.9
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index 14d62fa..339075d 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -110,6 +110,7 @@ enum {
     LEND = 1,
     LCOUNT = 2,
     SAR = 3,
+    BR = 4,
     LITBASE = 5,
     SCOMPARE1 = 12,
     WINDOW_BASE = 72,
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index 20a6834..93a807e 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -76,6 +76,7 @@ static const char * const sregnames[256] = {
     [LEND] = "LEND",
     [LCOUNT] = "LCOUNT",
     [SAR] = "SAR",
+    [BR] = "BR",
     [LITBASE] = "LITBASE",
     [SCOMPARE1] = "SCOMPARE1",
     [WINDOW_BASE] = "WINDOW_BASE",
@@ -434,6 +435,11 @@ static void gen_wsr_sar(DisasContext *dc, uint32_t sr, TCGv_i32 s)
     dc->sar_m32_5bit = false;
 }
 
+static void gen_wsr_br(DisasContext *dc, uint32_t sr, TCGv_i32 s)
+{
+    tcg_gen_andi_i32(cpu_SR[sr], s, 0xffff);
+}
+
 static void gen_wsr_litbase(DisasContext *dc, uint32_t sr, TCGv_i32 s)
 {
     tcg_gen_andi_i32(cpu_SR[sr], s, 0xfffff001);
@@ -536,6 +542,7 @@ static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s)
         [LBEG] = gen_wsr_lbeg,
         [LEND] = gen_wsr_lend,
         [SAR] = gen_wsr_sar,
+        [BR] = gen_wsr_br,
         [LITBASE] = gen_wsr_litbase,
         [WINDOW_BASE] = gen_wsr_windowbase,
         [WINDOW_START] = gen_wsr_windowstart,
@@ -974,23 +981,28 @@ static void disas_xtensa_insn(DisasContext *dc)
                     break;
 
                 case 8: /*ANY4p*/
-                    HAS_OPTION(XTENSA_OPTION_BOOLEAN);
-                    TBD();
-                    break;
-
                 case 9: /*ALL4p*/
-                    HAS_OPTION(XTENSA_OPTION_BOOLEAN);
-                    TBD();
-                    break;
-
                 case 10: /*ANY8p*/
-                    HAS_OPTION(XTENSA_OPTION_BOOLEAN);
-                    TBD();
-                    break;
-
                 case 11: /*ALL8p*/
                     HAS_OPTION(XTENSA_OPTION_BOOLEAN);
-                    TBD();
+                    {
+                        const unsigned shift = (RRR_R & 2) ? 8 : 4;
+                        TCGv_i32 mask = tcg_const_i32(
+                                ((1 << shift) - 1) << RRR_S);
+                        TCGv_i32 tmp = tcg_temp_new_i32();
+
+                        tcg_gen_and_i32(tmp, cpu_SR[BR], mask);
+                        if (RRR_R & 1) { /*ALL*/
+                            tcg_gen_addi_i32(tmp, tmp, 1 << RRR_S);
+                        } else { /*ANY*/
+                            tcg_gen_add_i32(tmp, tmp, mask);
+                        }
+                        tcg_gen_shri_i32(tmp, tmp, RRR_S + shift);
+                        tcg_gen_deposit_i32(cpu_SR[BR], cpu_SR[BR],
+                                tmp, RRR_T, 1);
+                        tcg_temp_free(mask);
+                        tcg_temp_free(tmp);
+                    }
                     break;
 
                 default: /*reserved*/
@@ -1339,7 +1351,9 @@ static void disas_xtensa_insn(DisasContext *dc)
             break;
 
         case 2: /*RST2*/
-            gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
+            if (OP2 >= 8) {
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
+            }
 
             if (OP2 >= 12) {
                 HAS_OPTION(XTENSA_OPTION_32_BIT_IDIV);
@@ -1350,6 +1364,42 @@ static void disas_xtensa_insn(DisasContext *dc)
             }
 
             switch (OP2) {
+#define BOOLEAN_LOGIC(fn, r, s, t) \
+                do { \
+                    HAS_OPTION(XTENSA_OPTION_BOOLEAN); \
+                    TCGv_i32 tmp1 = tcg_temp_new_i32(); \
+                    TCGv_i32 tmp2 = tcg_temp_new_i32(); \
+                    \
+                    tcg_gen_shri_i32(tmp1, cpu_SR[BR], s); \
+                    tcg_gen_shri_i32(tmp2, cpu_SR[BR], t); \
+                    tcg_gen_##fn##_i32(tmp1, tmp1, tmp2); \
+                    tcg_gen_deposit_i32(cpu_SR[BR], cpu_SR[BR], tmp1, r, 1); \
+                    tcg_temp_free(tmp1); \
+                    tcg_temp_free(tmp2); \
+                } while (0)
+
+            case 0: /*ANDBp*/
+                BOOLEAN_LOGIC(and, RRR_R, RRR_S, RRR_T);
+                break;
+
+            case 1: /*ANDBCp*/
+                BOOLEAN_LOGIC(andc, RRR_R, RRR_S, RRR_T);
+                break;
+
+            case 2: /*ORBp*/
+                BOOLEAN_LOGIC(or, RRR_R, RRR_S, RRR_T);
+                break;
+
+            case 3: /*ORBCp*/
+                BOOLEAN_LOGIC(orc, RRR_R, RRR_S, RRR_T);
+                break;
+
+            case 4: /*XORBp*/
+                BOOLEAN_LOGIC(xor, RRR_R, RRR_S, RRR_T);
+                break;
+
+#undef BOOLEAN_LOGIC
+
             case 8: /*MULLi*/
                 HAS_OPTION(XTENSA_OPTION_32_BIT_IMUL);
                 tcg_gen_mul_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
@@ -1536,13 +1586,21 @@ static void disas_xtensa_insn(DisasContext *dc)
                 break;
 
             case 12: /*MOVFp*/
-                HAS_OPTION(XTENSA_OPTION_BOOLEAN);
-                TBD();
-                break;
-
             case 13: /*MOVTp*/
                 HAS_OPTION(XTENSA_OPTION_BOOLEAN);
-                TBD();
+                gen_window_check2(dc, RRR_R, RRR_S);
+                {
+                    int label = gen_new_label();
+                    TCGv_i32 tmp = tcg_temp_new_i32();
+
+                    tcg_gen_andi_i32(tmp, cpu_SR[BR], 1 << RRR_T);
+                    tcg_gen_brcondi_i32(
+                            OP2 & 1 ? TCG_COND_EQ : TCG_COND_NE,
+                            tmp, 0, label);
+                    tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_S]);
+                    gen_set_label(label);
+                    tcg_temp_free(tmp);
+                }
                 break;
 
             case 14: /*RUR*/
@@ -1954,13 +2012,16 @@ static void disas_xtensa_insn(DisasContext *dc)
             case 1: /*B1*/
                 switch (BRI8_R) {
                 case 0: /*BFp*/
-                    HAS_OPTION(XTENSA_OPTION_BOOLEAN);
-                    TBD();
-                    break;
-
                 case 1: /*BTp*/
                     HAS_OPTION(XTENSA_OPTION_BOOLEAN);
-                    TBD();
+                    {
+                        TCGv_i32 tmp = tcg_temp_new_i32();
+                        tcg_gen_andi_i32(tmp, cpu_SR[BR], 1 << RRI8_S);
+                        gen_brcondi(dc,
+                                BRI8_R == 1 ? TCG_COND_NE : TCG_COND_EQ,
+                                tmp, 0, 4 + RRI8_IMM8_SE);
+                        tcg_temp_free(tmp);
+                    }
                     break;
 
                 case 8: /*LOOP*/
commit b67ea0cd74417b42482499c29feb90914fbf8097
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Tue Sep 6 03:55:53 2011 +0400

    target-xtensa: implement memory protection options
    
    - TLB opcode group;
    - region protection option (ISA, 4.6.3);
    - region translation option (ISA, 4.6.4);
    - MMU option (ISA, 4.6.5).
    
    Cache control attribute bits are not used by this implementation.
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index 93e17d1..14d62fa 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -114,6 +114,10 @@ enum {
     SCOMPARE1 = 12,
     WINDOW_BASE = 72,
     WINDOW_START = 73,
+    PTEVADDR = 83,
+    RASID = 90,
+    ITLBCFG = 91,
+    DTLBCFG = 92,
     EPC1 = 177,
     DEPC = 192,
     EPS2 = 194,
@@ -154,6 +158,9 @@ enum {
 #define MAX_NLEVEL 6
 #define MAX_NNMI 1
 #define MAX_NCCOMPARE 3
+#define MAX_TLB_WAY_SIZE 8
+
+#define REGION_PAGE_MASK 0xe0000000
 
 enum {
     /* Static vectors */
@@ -214,6 +221,21 @@ typedef enum {
     INTTYPE_MAX
 } interrupt_type;
 
+typedef struct xtensa_tlb_entry {
+    uint32_t vaddr;
+    uint32_t paddr;
+    uint8_t asid;
+    uint8_t attr;
+    bool variable;
+} xtensa_tlb_entry;
+
+typedef struct xtensa_tlb {
+    unsigned nways;
+    const unsigned way_size[10];
+    bool varway56;
+    unsigned nrefillentries;
+} xtensa_tlb;
+
 typedef struct XtensaGdbReg {
     int targno;
     int type;
@@ -248,6 +270,9 @@ typedef struct XtensaConfig {
     unsigned nccompare;
     uint32_t timerint[MAX_NCCOMPARE];
     uint32_t clock_freq_khz;
+
+    xtensa_tlb itlb;
+    xtensa_tlb dtlb;
 } XtensaConfig;
 
 typedef struct CPUXtensaState {
@@ -258,6 +283,10 @@ typedef struct CPUXtensaState {
     uint32_t uregs[256];
     uint32_t phys_regs[MAX_NAREG];
 
+    xtensa_tlb_entry itlb[7][MAX_TLB_WAY_SIZE];
+    xtensa_tlb_entry dtlb[10][MAX_TLB_WAY_SIZE];
+    unsigned autorefill_idx;
+
     int pending_irq_level; /* level of last raised IRQ */
     void **irq_inputs;
     QEMUTimer *ccompare_timer;
@@ -287,12 +316,29 @@ int cpu_xtensa_signal_handler(int host_signum, void *pinfo, void *puc);
 void xtensa_cpu_list(FILE *f, fprintf_function cpu_fprintf);
 void xtensa_sync_window_from_phys(CPUState *env);
 void xtensa_sync_phys_from_window(CPUState *env);
+uint32_t xtensa_tlb_get_addr_mask(const CPUState *env, bool dtlb, uint32_t way);
+void split_tlb_entry_spec_way(const CPUState *env, uint32_t v, bool dtlb,
+        uint32_t *vpn, uint32_t wi, uint32_t *ei);
+int xtensa_tlb_lookup(const CPUState *env, uint32_t addr, bool dtlb,
+        uint32_t *pwi, uint32_t *pei, uint8_t *pring);
+void xtensa_tlb_set_entry(CPUState *env, bool dtlb,
+        unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte);
+int xtensa_get_physical_addr(CPUState *env,
+        uint32_t vaddr, int is_write, int mmu_idx,
+        uint32_t *paddr, uint32_t *page_size, unsigned *access);
+
 
 #define XTENSA_OPTION_BIT(opt) (((uint64_t)1) << (opt))
 
+static inline bool xtensa_option_bits_enabled(const XtensaConfig *config,
+        uint64_t opt)
+{
+    return (config->options & opt) != 0;
+}
+
 static inline bool xtensa_option_enabled(const XtensaConfig *config, int opt)
 {
-    return (config->options & XTENSA_OPTION_BIT(opt)) != 0;
+    return xtensa_option_bits_enabled(config, XTENSA_OPTION_BIT(opt));
 }
 
 static inline int xtensa_get_cintlevel(const CPUState *env)
@@ -323,6 +369,14 @@ static inline int xtensa_get_cring(const CPUState *env)
     }
 }
 
+static inline xtensa_tlb_entry *xtensa_tlb_get_entry(CPUState *env,
+        bool dtlb, unsigned wi, unsigned ei)
+{
+    return dtlb ?
+        env->dtlb[wi] + ei :
+        env->itlb[wi] + ei;
+}
+
 /* MMU modes definitions */
 #define MMU_MODE0_SUFFIX _ring0
 #define MMU_MODE1_SUFFIX _ring1
diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c
index 11c318d..9e18984 100644
--- a/target-xtensa/helper.c
+++ b/target-xtensa/helper.c
@@ -38,6 +38,8 @@
         a1, a2, a3, a4, a5, a6) \
     { .targno = (no), .type = (typ), .group = (grp) },
 
+static void reset_mmu(CPUState *env);
+
 void cpu_reset(CPUXtensaState *env)
 {
     env->exception_taken = 0;
@@ -48,6 +50,7 @@ void cpu_reset(CPUXtensaState *env)
     env->sregs[VECBASE] = env->config->vecbase;
 
     env->pending_irq_level = 0;
+    reset_mmu(env);
 }
 
 static const XtensaConfig core_config[] = {
@@ -150,7 +153,19 @@ void xtensa_cpu_list(FILE *f, fprintf_function cpu_fprintf)
 
 target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
 {
-    return addr;
+    uint32_t paddr;
+    uint32_t page_size;
+    unsigned access;
+
+    if (xtensa_get_physical_addr(env, addr, 0, 0,
+                &paddr, &page_size, &access) == 0) {
+        return paddr;
+    }
+    if (xtensa_get_physical_addr(env, addr, 2, 0,
+                &paddr, &page_size, &access) == 0) {
+        return paddr;
+    }
+    return ~0;
 }
 
 static uint32_t relocated_vector(CPUState *env, uint32_t vector)
@@ -255,3 +270,326 @@ void do_interrupt(CPUState *env)
     }
     check_interrupts(env);
 }
+
+static void reset_tlb_mmu_all_ways(CPUState *env,
+        const xtensa_tlb *tlb, xtensa_tlb_entry entry[][MAX_TLB_WAY_SIZE])
+{
+    unsigned wi, ei;
+
+    for (wi = 0; wi < tlb->nways; ++wi) {
+        for (ei = 0; ei < tlb->way_size[wi]; ++ei) {
+            entry[wi][ei].asid = 0;
+            entry[wi][ei].variable = true;
+        }
+    }
+}
+
+static void reset_tlb_mmu_ways56(CPUState *env,
+        const xtensa_tlb *tlb, xtensa_tlb_entry entry[][MAX_TLB_WAY_SIZE])
+{
+    if (!tlb->varway56) {
+        static const xtensa_tlb_entry way5[] = {
+            {
+                .vaddr = 0xd0000000,
+                .paddr = 0,
+                .asid = 1,
+                .attr = 7,
+                .variable = false,
+            }, {
+                .vaddr = 0xd8000000,
+                .paddr = 0,
+                .asid = 1,
+                .attr = 3,
+                .variable = false,
+            }
+        };
+        static const xtensa_tlb_entry way6[] = {
+            {
+                .vaddr = 0xe0000000,
+                .paddr = 0xf0000000,
+                .asid = 1,
+                .attr = 7,
+                .variable = false,
+            }, {
+                .vaddr = 0xf0000000,
+                .paddr = 0xf0000000,
+                .asid = 1,
+                .attr = 3,
+                .variable = false,
+            }
+        };
+        memcpy(entry[5], way5, sizeof(way5));
+        memcpy(entry[6], way6, sizeof(way6));
+    } else {
+        uint32_t ei;
+        for (ei = 0; ei < 8; ++ei) {
+            entry[6][ei].vaddr = ei << 29;
+            entry[6][ei].paddr = ei << 29;
+            entry[6][ei].asid = 1;
+            entry[6][ei].attr = 2;
+        }
+    }
+}
+
+static void reset_tlb_region_way0(CPUState *env,
+        xtensa_tlb_entry entry[][MAX_TLB_WAY_SIZE])
+{
+    unsigned ei;
+
+    for (ei = 0; ei < 8; ++ei) {
+        entry[0][ei].vaddr = ei << 29;
+        entry[0][ei].paddr = ei << 29;
+        entry[0][ei].asid = 1;
+        entry[0][ei].attr = 2;
+        entry[0][ei].variable = true;
+    }
+}
+
+static void reset_mmu(CPUState *env)
+{
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+        env->sregs[RASID] = 0x04030201;
+        env->sregs[ITLBCFG] = 0;
+        env->sregs[DTLBCFG] = 0;
+        env->autorefill_idx = 0;
+        reset_tlb_mmu_all_ways(env, &env->config->itlb, env->itlb);
+        reset_tlb_mmu_all_ways(env, &env->config->dtlb, env->dtlb);
+        reset_tlb_mmu_ways56(env, &env->config->itlb, env->itlb);
+        reset_tlb_mmu_ways56(env, &env->config->dtlb, env->dtlb);
+    } else {
+        reset_tlb_region_way0(env, env->itlb);
+        reset_tlb_region_way0(env, env->dtlb);
+    }
+}
+
+static unsigned get_ring(const CPUState *env, uint8_t asid)
+{
+    unsigned i;
+    for (i = 0; i < 4; ++i) {
+        if (((env->sregs[RASID] >> i * 8) & 0xff) == asid) {
+            return i;
+        }
+    }
+    return 0xff;
+}
+
+/*!
+ * Lookup xtensa TLB for the given virtual address.
+ * See ISA, 4.6.2.2
+ *
+ * \param pwi: [out] way index
+ * \param pei: [out] entry index
+ * \param pring: [out] access ring
+ * \return 0 if ok, exception cause code otherwise
+ */
+int xtensa_tlb_lookup(const CPUState *env, uint32_t addr, bool dtlb,
+        uint32_t *pwi, uint32_t *pei, uint8_t *pring)
+{
+    const xtensa_tlb *tlb = dtlb ?
+        &env->config->dtlb : &env->config->itlb;
+    const xtensa_tlb_entry (*entry)[MAX_TLB_WAY_SIZE] = dtlb ?
+        env->dtlb : env->itlb;
+
+    int nhits = 0;
+    unsigned wi;
+
+    for (wi = 0; wi < tlb->nways; ++wi) {
+        uint32_t vpn;
+        uint32_t ei;
+        split_tlb_entry_spec_way(env, addr, dtlb, &vpn, wi, &ei);
+        if (entry[wi][ei].vaddr == vpn && entry[wi][ei].asid) {
+            unsigned ring = get_ring(env, entry[wi][ei].asid);
+            if (ring < 4) {
+                if (++nhits > 1) {
+                    return dtlb ?
+                        LOAD_STORE_TLB_MULTI_HIT_CAUSE :
+                        INST_TLB_MULTI_HIT_CAUSE;
+                }
+                *pwi = wi;
+                *pei = ei;
+                *pring = ring;
+            }
+        }
+    }
+    return nhits ? 0 :
+        (dtlb ? LOAD_STORE_TLB_MISS_CAUSE : INST_TLB_MISS_CAUSE);
+}
+
+/*!
+ * Convert MMU ATTR to PAGE_{READ,WRITE,EXEC} mask.
+ * See ISA, 4.6.5.10
+ */
+static unsigned mmu_attr_to_access(uint32_t attr)
+{
+    unsigned access = 0;
+    if (attr < 12) {
+        access |= PAGE_READ;
+        if (attr & 0x1) {
+            access |= PAGE_EXEC;
+        }
+        if (attr & 0x2) {
+            access |= PAGE_WRITE;
+        }
+    } else if (attr == 13) {
+        access |= PAGE_READ | PAGE_WRITE;
+    }
+    return access;
+}
+
+/*!
+ * Convert region protection ATTR to PAGE_{READ,WRITE,EXEC} mask.
+ * See ISA, 4.6.3.3
+ */
+static unsigned region_attr_to_access(uint32_t attr)
+{
+    unsigned access = 0;
+    if ((attr < 6 && attr != 3) || attr == 14) {
+        access |= PAGE_READ | PAGE_WRITE;
+    }
+    if (attr > 0 && attr < 6) {
+        access |= PAGE_EXEC;
+    }
+    return access;
+}
+
+static bool is_access_granted(unsigned access, int is_write)
+{
+    switch (is_write) {
+    case 0:
+        return access & PAGE_READ;
+
+    case 1:
+        return access & PAGE_WRITE;
+
+    case 2:
+        return access & PAGE_EXEC;
+
+    default:
+        return 0;
+    }
+}
+
+static int autorefill_mmu(CPUState *env, uint32_t vaddr, bool dtlb,
+        uint32_t *wi, uint32_t *ei, uint8_t *ring);
+
+static int get_physical_addr_mmu(CPUState *env,
+        uint32_t vaddr, int is_write, int mmu_idx,
+        uint32_t *paddr, uint32_t *page_size, unsigned *access)
+{
+    bool dtlb = is_write != 2;
+    uint32_t wi;
+    uint32_t ei;
+    uint8_t ring;
+    int ret = xtensa_tlb_lookup(env, vaddr, dtlb, &wi, &ei, &ring);
+
+    if ((ret == INST_TLB_MISS_CAUSE || ret == LOAD_STORE_TLB_MISS_CAUSE) &&
+            (mmu_idx != 0 || ((vaddr ^ env->sregs[PTEVADDR]) & 0xffc00000)) &&
+            autorefill_mmu(env, vaddr, dtlb, &wi, &ei, &ring) == 0) {
+        ret = 0;
+    }
+    if (ret != 0) {
+        return ret;
+    }
+
+    const xtensa_tlb_entry *entry =
+        xtensa_tlb_get_entry(env, dtlb, wi, ei);
+
+    if (ring < mmu_idx) {
+        return dtlb ?
+            LOAD_STORE_PRIVILEGE_CAUSE :
+            INST_FETCH_PRIVILEGE_CAUSE;
+    }
+
+    *access = mmu_attr_to_access(entry->attr);
+    if (!is_access_granted(*access, is_write)) {
+        return dtlb ?
+            (is_write ?
+             STORE_PROHIBITED_CAUSE :
+             LOAD_PROHIBITED_CAUSE) :
+            INST_FETCH_PROHIBITED_CAUSE;
+    }
+
+    *paddr = entry->paddr | (vaddr & ~xtensa_tlb_get_addr_mask(env, dtlb, wi));
+    *page_size = ~xtensa_tlb_get_addr_mask(env, dtlb, wi) + 1;
+
+    return 0;
+}
+
+static int autorefill_mmu(CPUState *env, uint32_t vaddr, bool dtlb,
+        uint32_t *wi, uint32_t *ei, uint8_t *ring)
+{
+    uint32_t paddr;
+    uint32_t page_size;
+    unsigned access;
+    uint32_t pt_vaddr =
+        (env->sregs[PTEVADDR] | (vaddr >> 10)) & 0xfffffffc;
+    int ret = get_physical_addr_mmu(env, pt_vaddr, 0, 0,
+            &paddr, &page_size, &access);
+
+    qemu_log("%s: trying autorefill(%08x) -> %08x\n", __func__,
+            vaddr, ret ? ~0 : paddr);
+
+    if (ret == 0) {
+        uint32_t vpn;
+        uint32_t pte = ldl_phys(paddr);
+
+        *ring = (pte >> 4) & 0x3;
+        *wi = (++env->autorefill_idx) & 0x3;
+        split_tlb_entry_spec_way(env, vaddr, dtlb, &vpn, *wi, ei);
+        xtensa_tlb_set_entry(env, dtlb, *wi, *ei, vpn, pte);
+        qemu_log("%s: autorefill(%08x): %08x -> %08x\n",
+                __func__, vaddr, vpn, pte);
+    }
+    return ret;
+}
+
+static int get_physical_addr_region(CPUState *env,
+        uint32_t vaddr, int is_write, int mmu_idx,
+        uint32_t *paddr, uint32_t *page_size, unsigned *access)
+{
+    bool dtlb = is_write != 2;
+    uint32_t wi = 0;
+    uint32_t ei = (vaddr >> 29) & 0x7;
+    const xtensa_tlb_entry *entry =
+        xtensa_tlb_get_entry(env, dtlb, wi, ei);
+
+    *access = region_attr_to_access(entry->attr);
+    if (!is_access_granted(*access, is_write)) {
+        return dtlb ?
+            (is_write ?
+             STORE_PROHIBITED_CAUSE :
+             LOAD_PROHIBITED_CAUSE) :
+            INST_FETCH_PROHIBITED_CAUSE;
+    }
+
+    *paddr = entry->paddr | (vaddr & ~REGION_PAGE_MASK);
+    *page_size = ~REGION_PAGE_MASK + 1;
+
+    return 0;
+}
+
+/*!
+ * Convert virtual address to physical addr.
+ * MMU may issue pagewalk and change xtensa autorefill TLB way entry.
+ *
+ * \return 0 if ok, exception cause code otherwise
+ */
+int xtensa_get_physical_addr(CPUState *env,
+        uint32_t vaddr, int is_write, int mmu_idx,
+        uint32_t *paddr, uint32_t *page_size, unsigned *access)
+{
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+        return get_physical_addr_mmu(env, vaddr, is_write, mmu_idx,
+                paddr, page_size, access);
+    } else if (xtensa_option_bits_enabled(env->config,
+                XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) |
+                XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION))) {
+        return get_physical_addr_region(env, vaddr, is_write, mmu_idx,
+                paddr, page_size, access);
+    } else {
+        *paddr = vaddr;
+        *page_size = TARGET_PAGE_SIZE;
+        *access = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+        return 0;
+    }
+}
diff --git a/target-xtensa/helpers.h b/target-xtensa/helpers.h
index 28689c3..09ab332 100644
--- a/target-xtensa/helpers.h
+++ b/target-xtensa/helpers.h
@@ -22,4 +22,11 @@ DEF_HELPER_2(timer_irq, void, i32, i32)
 DEF_HELPER_1(advance_ccount, void, i32)
 DEF_HELPER_1(check_interrupts, void, env)
 
+DEF_HELPER_1(wsr_rasid, void, i32)
+DEF_HELPER_2(rtlb0, i32, i32, i32)
+DEF_HELPER_2(rtlb1, i32, i32, i32)
+DEF_HELPER_2(itlb, void, i32, i32)
+DEF_HELPER_2(ptlb, i32, i32, i32)
+DEF_HELPER_3(wtlb, void, i32, i32, i32)
+
 #include "def-helper.h"
diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c
index 0047fa3..d02706d 100644
--- a/target-xtensa/op_helper.c
+++ b/target-xtensa/op_helper.c
@@ -70,13 +70,32 @@ static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
     }
 }
 
-void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+void tlb_fill(target_ulong vaddr, int is_write, int mmu_idx, void *retaddr)
 {
-    tlb_set_page(cpu_single_env,
-            addr & ~(TARGET_PAGE_SIZE - 1),
-            addr & ~(TARGET_PAGE_SIZE - 1),
-            PAGE_READ | PAGE_WRITE | PAGE_EXEC,
-            mmu_idx, TARGET_PAGE_SIZE);
+    CPUState *saved_env = env;
+
+    env = cpu_single_env;
+    {
+        uint32_t paddr;
+        uint32_t page_size;
+        unsigned access;
+        int ret = xtensa_get_physical_addr(env, vaddr, is_write, mmu_idx,
+                &paddr, &page_size, &access);
+
+        qemu_log("%s(%08x, %d, %d) -> %08x, ret = %d\n", __func__,
+                vaddr, is_write, mmu_idx, paddr, ret);
+
+        if (ret == 0) {
+            tlb_set_page(env,
+                    vaddr & TARGET_PAGE_MASK,
+                    paddr & TARGET_PAGE_MASK,
+                    access, mmu_idx, page_size);
+        } else {
+            do_restore_state(retaddr);
+            HELPER(exception_cause_vaddr)(env->pc, ret, vaddr);
+        }
+    }
+    env = saved_env;
 }
 
 void HELPER(exception)(uint32_t excp)
@@ -384,3 +403,273 @@ void HELPER(check_interrupts)(CPUState *env)
 {
     check_interrupts(env);
 }
+
+void HELPER(wsr_rasid)(uint32_t v)
+{
+    v = (v & 0xffffff00) | 0x1;
+    if (v != env->sregs[RASID]) {
+        env->sregs[RASID] = v;
+        tlb_flush(env, 1);
+    }
+}
+
+static uint32_t get_page_size(const CPUState *env, bool dtlb, uint32_t way)
+{
+    uint32_t tlbcfg = env->sregs[dtlb ? DTLBCFG : ITLBCFG];
+
+    switch (way) {
+    case 4:
+        return (tlbcfg >> 16) & 0x3;
+
+    case 5:
+        return (tlbcfg >> 20) & 0x1;
+
+    case 6:
+        return (tlbcfg >> 24) & 0x1;
+
+    default:
+        return 0;
+    }
+}
+
+/*!
+ * Get bit mask for the virtual address bits translated by the TLB way
+ */
+uint32_t xtensa_tlb_get_addr_mask(const CPUState *env, bool dtlb, uint32_t way)
+{
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+        bool varway56 = dtlb ?
+            env->config->dtlb.varway56 :
+            env->config->itlb.varway56;
+
+        switch (way) {
+        case 4:
+            return 0xfff00000 << get_page_size(env, dtlb, way) * 2;
+
+        case 5:
+            if (varway56) {
+                return 0xf8000000 << get_page_size(env, dtlb, way);
+            } else {
+                return 0xf8000000;
+            }
+
+        case 6:
+            if (varway56) {
+                return 0xf0000000 << (1 - get_page_size(env, dtlb, way));
+            } else {
+                return 0xf0000000;
+            }
+
+        default:
+            return 0xfffff000;
+        }
+    } else {
+        return REGION_PAGE_MASK;
+    }
+}
+
+/*!
+ * Get bit mask for the 'VPN without index' field.
+ * See ISA, 4.6.5.6, data format for RxTLB0
+ */
+static uint32_t get_vpn_mask(const CPUState *env, bool dtlb, uint32_t way)
+{
+    if (way < 4) {
+        bool is32 = (dtlb ?
+                env->config->dtlb.nrefillentries :
+                env->config->itlb.nrefillentries) == 32;
+        return is32 ? 0xffff8000 : 0xffffc000;
+    } else if (way == 4) {
+        return xtensa_tlb_get_addr_mask(env, dtlb, way) << 2;
+    } else if (way <= 6) {
+        uint32_t mask = xtensa_tlb_get_addr_mask(env, dtlb, way);
+        bool varway56 = dtlb ?
+            env->config->dtlb.varway56 :
+            env->config->itlb.varway56;
+
+        if (varway56) {
+            return mask << (way == 5 ? 2 : 3);
+        } else {
+            return mask << 1;
+        }
+    } else {
+        return 0xfffff000;
+    }
+}
+
+/*!
+ * Split virtual address into VPN (with index) and entry index
+ * for the given TLB way
+ */
+void split_tlb_entry_spec_way(const CPUState *env, uint32_t v, bool dtlb,
+        uint32_t *vpn, uint32_t wi, uint32_t *ei)
+{
+    bool varway56 = dtlb ?
+        env->config->dtlb.varway56 :
+        env->config->itlb.varway56;
+
+    if (!dtlb) {
+        wi &= 7;
+    }
+
+    if (wi < 4) {
+        bool is32 = (dtlb ?
+                env->config->dtlb.nrefillentries :
+                env->config->itlb.nrefillentries) == 32;
+        *ei = (v >> 12) & (is32 ? 0x7 : 0x3);
+    } else {
+        switch (wi) {
+        case 4:
+            {
+                uint32_t eibase = 20 + get_page_size(env, dtlb, wi) * 2;
+                *ei = (v >> eibase) & 0x3;
+            }
+            break;
+
+        case 5:
+            if (varway56) {
+                uint32_t eibase = 27 + get_page_size(env, dtlb, wi);
+                *ei = (v >> eibase) & 0x3;
+            } else {
+                *ei = (v >> 27) & 0x1;
+            }
+            break;
+
+        case 6:
+            if (varway56) {
+                uint32_t eibase = 29 - get_page_size(env, dtlb, wi);
+                *ei = (v >> eibase) & 0x7;
+            } else {
+                *ei = (v >> 28) & 0x1;
+            }
+            break;
+
+        default:
+            *ei = 0;
+            break;
+        }
+    }
+    *vpn = v & xtensa_tlb_get_addr_mask(env, dtlb, wi);
+}
+
+/*!
+ * Split TLB address into TLB way, entry index and VPN (with index).
+ * See ISA, 4.6.5.5 - 4.6.5.8 for the TLB addressing format
+ */
+static void split_tlb_entry_spec(uint32_t v, bool dtlb,
+        uint32_t *vpn, uint32_t *wi, uint32_t *ei)
+{
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+        *wi = v & (dtlb ? 0xf : 0x7);
+        split_tlb_entry_spec_way(env, v, dtlb, vpn, *wi, ei);
+    } else {
+        *vpn = v & REGION_PAGE_MASK;
+        *wi = 0;
+        *ei = (v >> 29) & 0x7;
+    }
+}
+
+static xtensa_tlb_entry *get_tlb_entry(uint32_t v, bool dtlb, uint32_t *pwi)
+{
+    uint32_t vpn;
+    uint32_t wi;
+    uint32_t ei;
+
+    split_tlb_entry_spec(v, dtlb, &vpn, &wi, &ei);
+    if (pwi) {
+        *pwi = wi;
+    }
+    return xtensa_tlb_get_entry(env, dtlb, wi, ei);
+}
+
+uint32_t HELPER(rtlb0)(uint32_t v, uint32_t dtlb)
+{
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+        uint32_t wi;
+        const xtensa_tlb_entry *entry = get_tlb_entry(v, dtlb, &wi);
+        return (entry->vaddr & get_vpn_mask(env, dtlb, wi)) | entry->asid;
+    } else {
+        return v & REGION_PAGE_MASK;
+    }
+}
+
+uint32_t HELPER(rtlb1)(uint32_t v, uint32_t dtlb)
+{
+    const xtensa_tlb_entry *entry = get_tlb_entry(v, dtlb, NULL);
+    return entry->paddr | entry->attr;
+}
+
+void HELPER(itlb)(uint32_t v, uint32_t dtlb)
+{
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+        uint32_t wi;
+        xtensa_tlb_entry *entry = get_tlb_entry(v, dtlb, &wi);
+        if (entry->variable && entry->asid) {
+            tlb_flush_page(env, entry->vaddr);
+            entry->asid = 0;
+        }
+    }
+}
+
+uint32_t HELPER(ptlb)(uint32_t v, uint32_t dtlb)
+{
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+        uint32_t wi;
+        uint32_t ei;
+        uint8_t ring;
+        int res = xtensa_tlb_lookup(env, v, dtlb, &wi, &ei, &ring);
+
+        switch (res) {
+        case 0:
+            if (ring >= xtensa_get_ring(env)) {
+                return (v & 0xfffff000) | wi | (dtlb ? 0x10 : 0x8);
+            }
+            break;
+
+        case INST_TLB_MULTI_HIT_CAUSE:
+        case LOAD_STORE_TLB_MULTI_HIT_CAUSE:
+            HELPER(exception_cause_vaddr)(env->pc, res, v);
+            break;
+        }
+        return 0;
+    } else {
+        return (v & REGION_PAGE_MASK) | 0x1;
+    }
+}
+
+void xtensa_tlb_set_entry(CPUState *env, bool dtlb,
+        unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte)
+{
+    xtensa_tlb_entry *entry = xtensa_tlb_get_entry(env, dtlb, wi, ei);
+
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+        if (entry->variable) {
+            if (entry->asid) {
+                tlb_flush_page(env, entry->vaddr);
+            }
+            entry->vaddr = vpn;
+            entry->paddr = pte & xtensa_tlb_get_addr_mask(env, dtlb, wi);
+            entry->asid = (env->sregs[RASID] >> ((pte >> 1) & 0x18)) & 0xff;
+            entry->attr = pte & 0xf;
+        } else {
+            qemu_log("%s %d, %d, %d trying to set immutable entry\n",
+                    __func__, dtlb, wi, ei);
+        }
+    } else {
+        tlb_flush_page(env, entry->vaddr);
+        if (xtensa_option_enabled(env->config,
+                    XTENSA_OPTION_REGION_TRANSLATION)) {
+            entry->paddr = pte & REGION_PAGE_MASK;
+        }
+        entry->attr = pte & 0xf;
+    }
+}
+
+void HELPER(wtlb)(uint32_t p, uint32_t v, uint32_t dtlb)
+{
+    uint32_t vpn;
+    uint32_t wi;
+    uint32_t ei;
+    split_tlb_entry_spec(v, dtlb, &vpn, &wi, &ei);
+    xtensa_tlb_set_entry(env, dtlb, wi, ei, vpn, p);
+}
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index bd10ae5..20a6834 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -80,6 +80,10 @@ static const char * const sregnames[256] = {
     [SCOMPARE1] = "SCOMPARE1",
     [WINDOW_BASE] = "WINDOW_BASE",
     [WINDOW_START] = "WINDOW_START",
+    [PTEVADDR] = "PTEVADDR",
+    [RASID] = "RASID",
+    [ITLBCFG] = "ITLBCFG",
+    [DTLBCFG] = "DTLBCFG",
     [EPC1] = "EPC1",
     [EPC1 + 1] = "EPC2",
     [EPC1 + 2] = "EPC3",
@@ -161,6 +165,11 @@ void xtensa_translate_init(void)
 #include "helpers.h"
 }
 
+static inline bool option_bits_enabled(DisasContext *dc, uint64_t opt)
+{
+    return xtensa_option_bits_enabled(dc->config, opt);
+}
+
 static inline bool option_enabled(DisasContext *dc, int opt)
 {
     return xtensa_option_enabled(dc->config, opt);
@@ -379,11 +388,19 @@ static void gen_rsr_ccount(DisasContext *dc, TCGv_i32 d, uint32_t sr)
     tcg_gen_mov_i32(d, cpu_SR[sr]);
 }
 
+static void gen_rsr_ptevaddr(DisasContext *dc, TCGv_i32 d, uint32_t sr)
+{
+    tcg_gen_shri_i32(d, cpu_SR[EXCVADDR], 10);
+    tcg_gen_or_i32(d, d, cpu_SR[sr]);
+    tcg_gen_andi_i32(d, d, 0xfffffffc);
+}
+
 static void gen_rsr(DisasContext *dc, TCGv_i32 d, uint32_t sr)
 {
     static void (* const rsr_handler[256])(DisasContext *dc,
             TCGv_i32 d, uint32_t sr) = {
         [CCOUNT] = gen_rsr_ccount,
+        [PTEVADDR] = gen_rsr_ptevaddr,
     };
 
     if (sregnames[sr]) {
@@ -436,6 +453,23 @@ static void gen_wsr_windowstart(DisasContext *dc, uint32_t sr, TCGv_i32 v)
     reset_used_window(dc);
 }
 
+static void gen_wsr_ptevaddr(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+    tcg_gen_andi_i32(cpu_SR[sr], v, 0xffc00000);
+}
+
+static void gen_wsr_rasid(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+    gen_helper_wsr_rasid(v);
+    /* This can change tb->flags, so exit tb */
+    gen_jumpi_check_loop_end(dc, -1);
+}
+
+static void gen_wsr_tlbcfg(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+    tcg_gen_andi_i32(cpu_SR[sr], v, 0x01130000);
+}
+
 static void gen_wsr_intset(DisasContext *dc, uint32_t sr, TCGv_i32 v)
 {
     tcg_gen_andi_i32(cpu_SR[sr], v,
@@ -505,6 +539,10 @@ static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s)
         [LITBASE] = gen_wsr_litbase,
         [WINDOW_BASE] = gen_wsr_windowbase,
         [WINDOW_START] = gen_wsr_windowstart,
+        [PTEVADDR] = gen_wsr_ptevaddr,
+        [RASID] = gen_wsr_rasid,
+        [ITLBCFG] = gen_wsr_tlbcfg,
+        [DTLBCFG] = gen_wsr_tlbcfg,
         [INTSET] = gen_wsr_intset,
         [INTCLEAR] = gen_wsr_intclear,
         [INTENABLE] = gen_wsr_intenable,
@@ -585,14 +623,16 @@ static void gen_window_check3(DisasContext *dc, unsigned r1, unsigned r2,
 
 static void disas_xtensa_insn(DisasContext *dc)
 {
-#define HAS_OPTION(opt) do { \
-        if (!option_enabled(dc, opt)) { \
-            qemu_log("Option %d is not enabled %s:%d\n", \
-                    (opt), __FILE__, __LINE__); \
+#define HAS_OPTION_BITS(opt) do { \
+        if (!option_bits_enabled(dc, opt)) { \
+            qemu_log("Option is not enabled %s:%d\n", \
+                    __FILE__, __LINE__); \
             goto invalid_opcode; \
         } \
     } while (0)
 
+#define HAS_OPTION(opt) HAS_OPTION_BITS(XTENSA_OPTION_BIT(opt))
+
 #define TBD() qemu_log("TBD(pc = %08x): %s:%d\n", dc->pc, __FILE__, __LINE__)
 #define RESERVED() do { \
         qemu_log("RESERVED(pc = %08x, %02x%02x%02x): %s:%d\n", \
@@ -1055,7 +1095,48 @@ static void disas_xtensa_insn(DisasContext *dc)
                 break;
 
             case 5: /*TLB*/
-                TBD();
+                HAS_OPTION_BITS(
+                        XTENSA_OPTION_BIT(XTENSA_OPTION_MMU) |
+                        XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) |
+                        XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION));
+                gen_check_privilege(dc);
+                gen_window_check2(dc, RRR_S, RRR_T);
+                {
+                    TCGv_i32 dtlb = tcg_const_i32((RRR_R & 8) != 0);
+
+                    switch (RRR_R & 7) {
+                    case 3: /*RITLB0*/ /*RDTLB0*/
+                        gen_helper_rtlb0(cpu_R[RRR_T], cpu_R[RRR_S], dtlb);
+                        break;
+
+                    case 4: /*IITLB*/ /*IDTLB*/
+                        gen_helper_itlb(cpu_R[RRR_S], dtlb);
+                        /* This could change memory mapping, so exit tb */
+                        gen_jumpi_check_loop_end(dc, -1);
+                        break;
+
+                    case 5: /*PITLB*/ /*PDTLB*/
+                        tcg_gen_movi_i32(cpu_pc, dc->pc);
+                        gen_helper_ptlb(cpu_R[RRR_T], cpu_R[RRR_S], dtlb);
+                        break;
+
+                    case 6: /*WITLB*/ /*WDTLB*/
+                        gen_helper_wtlb(cpu_R[RRR_T], cpu_R[RRR_S], dtlb);
+                        /* This could change memory mapping, so exit tb */
+                        gen_jumpi_check_loop_end(dc, -1);
+                        break;
+
+                    case 7: /*RITLB1*/ /*RDTLB1*/
+                        gen_helper_rtlb1(cpu_R[RRR_T], cpu_R[RRR_S], dtlb);
+                        break;
+
+                    default:
+                        tcg_temp_free(dtlb);
+                        RESERVED();
+                        break;
+                    }
+                    tcg_temp_free(dtlb);
+                }
                 break;
 
             case 6: /*RT0*/
commit ccfcaba6fd9f69a9322af1911302e71127bee1e0
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Tue Sep 6 03:55:52 2011 +0400

    target-xtensa: add gdb support
    
    Specific xtensa processor overlay for GDB contains register map in
    the gdb/xtensa-config.c. This description is used by the GDB to e.g.
    parse 'g' response packets and it may be reused in the qemu's gdbstub
    (only XTREG definitions for non-pseudoregisters are needed).
    
    Currently mainline GDB does not support operations with privileged SRs
    (see http://sourceware.org/ml/gdb/2011-07/msg00075.html). This support
    may be enabled, see NUM_CORE_REGS comment in the gdbstub.c
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/gdbstub.c b/gdbstub.c
index 3b87c27..9330885 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1541,6 +1541,94 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
     }
     return 4;
 }
+#elif defined(TARGET_XTENSA)
+
+/* Use num_core_regs to see only non-privileged registers in an unmodified gdb.
+ * Use num_regs to see all registers. gdb modification is required for that:
+ * reset bit 0 in the 'flags' field of the registers definitions in the
+ * gdb/xtensa-config.c inside gdb source tree or inside gdb overlay.
+ */
+#define NUM_CORE_REGS (env->config->gdb_regmap.num_regs)
+#define num_g_regs NUM_CORE_REGS
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n;
+
+    if (n < 0 || n >= env->config->gdb_regmap.num_regs) {
+        return 0;
+    }
+
+    switch (reg->type) {
+    case 9: /*pc*/
+        GET_REG32(env->pc);
+        break;
+
+    case 1: /*ar*/
+        xtensa_sync_phys_from_window(env);
+        GET_REG32(env->phys_regs[(reg->targno & 0xff) % env->config->nareg]);
+        break;
+
+    case 2: /*SR*/
+        GET_REG32(env->sregs[reg->targno & 0xff]);
+        break;
+
+    case 3: /*UR*/
+        GET_REG32(env->uregs[reg->targno & 0xff]);
+        break;
+
+    case 8: /*a*/
+        GET_REG32(env->regs[reg->targno & 0x0f]);
+        break;
+
+    default:
+        qemu_log("%s from reg %d of unsupported type %d\n",
+                __func__, n, reg->type);
+        return 0;
+    }
+}
+
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    uint32_t tmp;
+    const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n;
+
+    if (n < 0 || n >= env->config->gdb_regmap.num_regs) {
+        return 0;
+    }
+
+    tmp = ldl_p(mem_buf);
+
+    switch (reg->type) {
+    case 9: /*pc*/
+        env->pc = tmp;
+        break;
+
+    case 1: /*ar*/
+        env->phys_regs[(reg->targno & 0xff) % env->config->nareg] = tmp;
+        xtensa_sync_window_from_phys(env);
+        break;
+
+    case 2: /*SR*/
+        env->sregs[reg->targno & 0xff] = tmp;
+        break;
+
+    case 3: /*UR*/
+        env->uregs[reg->targno & 0xff] = tmp;
+        break;
+
+    case 8: /*a*/
+        env->regs[reg->targno & 0x0f] = tmp;
+        break;
+
+    default:
+        qemu_log("%s to reg %d of unsupported type %d\n",
+                __func__, n, reg->type);
+        return 0;
+    }
+
+    return 4;
+}
 #else
 
 #define NUM_CORE_REGS 0
@@ -1557,7 +1645,9 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
 
 #endif
 
+#if !defined(TARGET_XTENSA)
 static int num_g_regs = NUM_CORE_REGS;
+#endif
 
 #ifdef GDB_CORE_XML
 /* Encode data using the encoding for 'x' packets.  */
@@ -1654,6 +1744,7 @@ static int gdb_write_register(CPUState *env, uint8_t *mem_buf, int reg)
     return 0;
 }
 
+#if !defined(TARGET_XTENSA)
 /* Register a supplemental set of CPU registers.  If g_pos is nonzero it
    specifies the first register number and these registers are included in
    a standard "g" packet.  Direction is relative to gdb, i.e. get_reg is
@@ -1693,6 +1784,7 @@ void gdb_register_coprocessor(CPUState * env,
         }
     }
 }
+#endif
 
 #ifndef CONFIG_USER_ONLY
 static const int xlat_gdb_type[] = {
@@ -1818,6 +1910,8 @@ static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
     s->c_cpu->psw.addr = pc;
 #elif defined (TARGET_LM32)
     s->c_cpu->pc = pc;
+#elif defined(TARGET_XTENSA)
+    s->c_cpu->pc = pc;
 #endif
 }
 
@@ -1988,6 +2082,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
         break;
     case 'g':
         cpu_synchronize_state(s->g_cpu);
+        env = s->g_cpu;
         len = 0;
         for (addr = 0; addr < num_g_regs; addr++) {
             reg_size = gdb_read_register(s->g_cpu, mem_buf + len, addr);
@@ -1998,6 +2093,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
         break;
     case 'G':
         cpu_synchronize_state(s->g_cpu);
+        env = s->g_cpu;
         registers = mem_buf;
         len = strlen(p) / 2;
         hextomem((uint8_t *)registers, p, len);
diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index c9094e9..93e17d1 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -214,9 +214,23 @@ typedef enum {
     INTTYPE_MAX
 } interrupt_type;
 
+typedef struct XtensaGdbReg {
+    int targno;
+    int type;
+    int group;
+} XtensaGdbReg;
+
+typedef struct XtensaGdbRegmap {
+    int num_regs;
+    int num_core_regs;
+    /* PC + a + ar + sr + ur */
+    XtensaGdbReg reg[1 + 16 + 64 + 256 + 256];
+} XtensaGdbRegmap;
+
 typedef struct XtensaConfig {
     const char *name;
     uint64_t options;
+    XtensaGdbRegmap gdb_regmap;
     unsigned nareg;
     int excm_level;
     int ndepc;
diff --git a/target-xtensa/gdb-config-sample-xtensa-core.c b/target-xtensa/gdb-config-sample-xtensa-core.c
new file mode 100644
index 0000000..bfbd7be
--- /dev/null
+++ b/target-xtensa/gdb-config-sample-xtensa-core.c
@@ -0,0 +1,375 @@
+/* Configuration for the Xtensa architecture for GDB, the GNU debugger.
+
+   Copyright (c) 2003-2010 Tensilica Inc.
+
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   "Software"), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+
+   The above copyright notice and this permission notice shall be included
+   in all copies or substantial portions of the Software.
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+   CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+   TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+  XTREG(0,   0, 32, 4, 4, 0x0020, 0x0006, -2, 9, 0x0100, pc,
+          0, 0, 0, 0, 0, 0)
+  XTREG(1,   4, 32, 4, 4, 0x0100, 0x0006, -2, 1, 0x0002, ar0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(2,   8, 32, 4, 4, 0x0101, 0x0006, -2, 1, 0x0002, ar1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(3,  12, 32, 4, 4, 0x0102, 0x0006, -2, 1, 0x0002, ar2,
+          0, 0, 0, 0, 0, 0)
+  XTREG(4,  16, 32, 4, 4, 0x0103, 0x0006, -2, 1, 0x0002, ar3,
+          0, 0, 0, 0, 0, 0)
+  XTREG(5,  20, 32, 4, 4, 0x0104, 0x0006, -2, 1, 0x0002, ar4,
+          0, 0, 0, 0, 0, 0)
+  XTREG(6,  24, 32, 4, 4, 0x0105, 0x0006, -2, 1, 0x0002, ar5,
+          0, 0, 0, 0, 0, 0)
+  XTREG(7,  28, 32, 4, 4, 0x0106, 0x0006, -2, 1, 0x0002, ar6,
+          0, 0, 0, 0, 0, 0)
+  XTREG(8,  32, 32, 4, 4, 0x0107, 0x0006, -2, 1, 0x0002, ar7,
+          0, 0, 0, 0, 0, 0)
+  XTREG(9,  36, 32, 4, 4, 0x0108, 0x0006, -2, 1, 0x0002, ar8,
+          0, 0, 0, 0, 0, 0)
+  XTREG(10,  40, 32, 4, 4, 0x0109, 0x0006, -2, 1, 0x0002, ar9,
+          0, 0, 0, 0, 0, 0)
+  XTREG(11,  44, 32, 4, 4, 0x010a, 0x0006, -2, 1, 0x0002, ar10,
+          0, 0, 0, 0, 0, 0)
+  XTREG(12,  48, 32, 4, 4, 0x010b, 0x0006, -2, 1, 0x0002, ar11,
+          0, 0, 0, 0, 0, 0)
+  XTREG(13,  52, 32, 4, 4, 0x010c, 0x0006, -2, 1, 0x0002, ar12,
+          0, 0, 0, 0, 0, 0)
+  XTREG(14,  56, 32, 4, 4, 0x010d, 0x0006, -2, 1, 0x0002, ar13,
+          0, 0, 0, 0, 0, 0)
+  XTREG(15,  60, 32, 4, 4, 0x010e, 0x0006, -2, 1, 0x0002, ar14,
+          0, 0, 0, 0, 0, 0)
+  XTREG(16,  64, 32, 4, 4, 0x010f, 0x0006, -2, 1, 0x0002, ar15,
+          0, 0, 0, 0, 0, 0)
+  XTREG(17,  68, 32, 4, 4, 0x0110, 0x0006, -2, 1, 0x0002, ar16,
+          0, 0, 0, 0, 0, 0)
+  XTREG(18,  72, 32, 4, 4, 0x0111, 0x0006, -2, 1, 0x0002, ar17,
+          0, 0, 0, 0, 0, 0)
+  XTREG(19,  76, 32, 4, 4, 0x0112, 0x0006, -2, 1, 0x0002, ar18,
+          0, 0, 0, 0, 0, 0)
+  XTREG(20,  80, 32, 4, 4, 0x0113, 0x0006, -2, 1, 0x0002, ar19,
+          0, 0, 0, 0, 0, 0)
+  XTREG(21,  84, 32, 4, 4, 0x0114, 0x0006, -2, 1, 0x0002, ar20,
+          0, 0, 0, 0, 0, 0)
+  XTREG(22,  88, 32, 4, 4, 0x0115, 0x0006, -2, 1, 0x0002, ar21,
+          0, 0, 0, 0, 0, 0)
+  XTREG(23,  92, 32, 4, 4, 0x0116, 0x0006, -2, 1, 0x0002, ar22,
+          0, 0, 0, 0, 0, 0)
+  XTREG(24,  96, 32, 4, 4, 0x0117, 0x0006, -2, 1, 0x0002, ar23,
+          0, 0, 0, 0, 0, 0)
+  XTREG(25, 100, 32, 4, 4, 0x0118, 0x0006, -2, 1, 0x0002, ar24,
+          0, 0, 0, 0, 0, 0)
+  XTREG(26, 104, 32, 4, 4, 0x0119, 0x0006, -2, 1, 0x0002, ar25,
+          0, 0, 0, 0, 0, 0)
+  XTREG(27, 108, 32, 4, 4, 0x011a, 0x0006, -2, 1, 0x0002, ar26,
+          0, 0, 0, 0, 0, 0)
+  XTREG(28, 112, 32, 4, 4, 0x011b, 0x0006, -2, 1, 0x0002, ar27,
+          0, 0, 0, 0, 0, 0)
+  XTREG(29, 116, 32, 4, 4, 0x011c, 0x0006, -2, 1, 0x0002, ar28,
+          0, 0, 0, 0, 0, 0)
+  XTREG(30, 120, 32, 4, 4, 0x011d, 0x0006, -2, 1, 0x0002, ar29,
+          0, 0, 0, 0, 0, 0)
+  XTREG(31, 124, 32, 4, 4, 0x011e, 0x0006, -2, 1, 0x0002, ar30,
+          0, 0, 0, 0, 0, 0)
+  XTREG(32, 128, 32, 4, 4, 0x011f, 0x0006, -2, 1, 0x0002, ar31,
+          0, 0, 0, 0, 0, 0)
+  XTREG(33, 132, 32, 4, 4, 0x0120, 0x0006, -2, 1, 0x0002, ar32,
+          0, 0, 0, 0, 0, 0)
+  XTREG(34, 136, 32, 4, 4, 0x0121, 0x0006, -2, 1, 0x0002, ar33,
+          0, 0, 0, 0, 0, 0)
+  XTREG(35, 140, 32, 4, 4, 0x0122, 0x0006, -2, 1, 0x0002, ar34,
+          0, 0, 0, 0, 0, 0)
+  XTREG(36, 144, 32, 4, 4, 0x0123, 0x0006, -2, 1, 0x0002, ar35,
+          0, 0, 0, 0, 0, 0)
+  XTREG(37, 148, 32, 4, 4, 0x0124, 0x0006, -2, 1, 0x0002, ar36,
+          0, 0, 0, 0, 0, 0)
+  XTREG(38, 152, 32, 4, 4, 0x0125, 0x0006, -2, 1, 0x0002, ar37,
+          0, 0, 0, 0, 0, 0)
+  XTREG(39, 156, 32, 4, 4, 0x0126, 0x0006, -2, 1, 0x0002, ar38,
+          0, 0, 0, 0, 0, 0)
+  XTREG(40, 160, 32, 4, 4, 0x0127, 0x0006, -2, 1, 0x0002, ar39,
+          0, 0, 0, 0, 0, 0)
+  XTREG(41, 164, 32, 4, 4, 0x0128, 0x0006, -2, 1, 0x0002, ar40,
+          0, 0, 0, 0, 0, 0)
+  XTREG(42, 168, 32, 4, 4, 0x0129, 0x0006, -2, 1, 0x0002, ar41,
+          0, 0, 0, 0, 0, 0)
+  XTREG(43, 172, 32, 4, 4, 0x012a, 0x0006, -2, 1, 0x0002, ar42,
+          0, 0, 0, 0, 0, 0)
+  XTREG(44, 176, 32, 4, 4, 0x012b, 0x0006, -2, 1, 0x0002, ar43,
+          0, 0, 0, 0, 0, 0)
+  XTREG(45, 180, 32, 4, 4, 0x012c, 0x0006, -2, 1, 0x0002, ar44,
+          0, 0, 0, 0, 0, 0)
+  XTREG(46, 184, 32, 4, 4, 0x012d, 0x0006, -2, 1, 0x0002, ar45,
+          0, 0, 0, 0, 0, 0)
+  XTREG(47, 188, 32, 4, 4, 0x012e, 0x0006, -2, 1, 0x0002, ar46,
+          0, 0, 0, 0, 0, 0)
+  XTREG(48, 192, 32, 4, 4, 0x012f, 0x0006, -2, 1, 0x0002, ar47,
+          0, 0, 0, 0, 0, 0)
+  XTREG(49, 196, 32, 4, 4, 0x0130, 0x0006, -2, 1, 0x0002, ar48,
+          0, 0, 0, 0, 0, 0)
+  XTREG(50, 200, 32, 4, 4, 0x0131, 0x0006, -2, 1, 0x0002, ar49,
+          0, 0, 0, 0, 0, 0)
+  XTREG(51, 204, 32, 4, 4, 0x0132, 0x0006, -2, 1, 0x0002, ar50,
+          0, 0, 0, 0, 0, 0)
+  XTREG(52, 208, 32, 4, 4, 0x0133, 0x0006, -2, 1, 0x0002, ar51,
+          0, 0, 0, 0, 0, 0)
+  XTREG(53, 212, 32, 4, 4, 0x0134, 0x0006, -2, 1, 0x0002, ar52,
+          0, 0, 0, 0, 0, 0)
+  XTREG(54, 216, 32, 4, 4, 0x0135, 0x0006, -2, 1, 0x0002, ar53,
+          0, 0, 0, 0, 0, 0)
+  XTREG(55, 220, 32, 4, 4, 0x0136, 0x0006, -2, 1, 0x0002, ar54,
+          0, 0, 0, 0, 0, 0)
+  XTREG(56, 224, 32, 4, 4, 0x0137, 0x0006, -2, 1, 0x0002, ar55,
+          0, 0, 0, 0, 0, 0)
+  XTREG(57, 228, 32, 4, 4, 0x0138, 0x0006, -2, 1, 0x0002, ar56,
+          0, 0, 0, 0, 0, 0)
+  XTREG(58, 232, 32, 4, 4, 0x0139, 0x0006, -2, 1, 0x0002, ar57,
+          0, 0, 0, 0, 0, 0)
+  XTREG(59, 236, 32, 4, 4, 0x013a, 0x0006, -2, 1, 0x0002, ar58,
+          0, 0, 0, 0, 0, 0)
+  XTREG(60, 240, 32, 4, 4, 0x013b, 0x0006, -2, 1, 0x0002, ar59,
+          0, 0, 0, 0, 0, 0)
+  XTREG(61, 244, 32, 4, 4, 0x013c, 0x0006, -2, 1, 0x0002, ar60,
+          0, 0, 0, 0, 0, 0)
+  XTREG(62, 248, 32, 4, 4, 0x013d, 0x0006, -2, 1, 0x0002, ar61,
+          0, 0, 0, 0, 0, 0)
+  XTREG(63, 252, 32, 4, 4, 0x013e, 0x0006, -2, 1, 0x0002, ar62,
+          0, 0, 0, 0, 0, 0)
+  XTREG(64, 256, 32, 4, 4, 0x013f, 0x0006, -2, 1, 0x0002, ar63,
+          0, 0, 0, 0, 0, 0)
+  XTREG(65, 260, 32, 4, 4, 0x0200, 0x0006, -2, 2, 0x1100, lbeg,
+          0, 0, 0, 0, 0, 0)
+  XTREG(66, 264, 32, 4, 4, 0x0201, 0x0006, -2, 2, 0x1100, lend,
+          0, 0, 0, 0, 0, 0)
+  XTREG(67, 268, 32, 4, 4, 0x0202, 0x0006, -2, 2, 0x1100, lcount,
+          0, 0, 0, 0, 0, 0)
+  XTREG(68, 272,  6, 4, 4, 0x0203, 0x0006, -2, 2, 0x1100, sar,
+          0, 0, 0, 0, 0, 0)
+  XTREG(69, 276, 32, 4, 4, 0x0205, 0x0006, -2, 2, 0x1100, litbase,
+          0, 0, 0, 0, 0, 0)
+  XTREG(70, 280,  4, 4, 4, 0x0248, 0x0006, -2, 2, 0x1002, windowbase,
+          0, 0, 0, 0, 0, 0)
+  XTREG(71, 284, 16, 4, 4, 0x0249, 0x0006, -2, 2, 0x1002, windowstart,
+          0, 0, 0, 0, 0, 0)
+  XTREG(72, 288, 32, 4, 4, 0x02b0, 0x0002, -2, 2, 0x1000, sr176,
+          0, 0, 0, 0, 0, 0)
+  XTREG(73, 292, 32, 4, 4, 0x02d0, 0x0002, -2, 2, 0x1000, sr208,
+          0, 0, 0, 0, 0, 0)
+  XTREG(74, 296, 19, 4, 4, 0x02e6, 0x0006, -2, 2, 0x1100, ps,
+          0, 0, 0, 0, 0, 0)
+  XTREG(75, 300, 32, 4, 4, 0x03e7, 0x0006, -2, 3, 0x0110, threadptr,
+          0, 0, 0, 0, 0, 0)
+  XTREG(76, 304, 32, 4, 4, 0x020c, 0x0006, -1, 2, 0x1100, scompare1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(77, 308, 32, 4, 4, 0x0327, 0x000e, -1, 3, 0x0210, expstate,
+          0, 0, 0, 0, 0, 0)
+  XTREG(78, 312, 32, 4, 4, 0x0300, 0x0006,  2, 3, 0x0210, stage1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(79, 316, 32, 4, 4, 0x0301, 0x0006,  2, 3, 0x0210, stage2,
+          0, 0, 0, 0, 0, 0)
+  XTREG(80, 320, 32, 4, 4, 0x0302, 0x0006,  2, 3, 0x0210, input_align_reg,
+          0, 0, 0, 0, 0, 0)
+  XTREG(81, 324,  6, 4, 4, 0x0303, 0x0006,  2, 3, 0x0210, input_align_reg_pos,
+          0, 0, 0, 0, 0, 0)
+  XTREG(82, 328, 32, 4, 4, 0x0304, 0x0006,  2, 3, 0x0210, data_reg,
+          0, 0, 0, 0, 0, 0)
+  XTREG(83, 332,  7, 4, 4, 0x0305, 0x0006,  2, 3, 0x0210, data_reg_pos,
+          0, 0, 0, 0, 0, 0)
+  XTREG(84, 336, 32, 4, 4, 0x0306, 0x0006,  2, 3, 0x0210, crc_reg,
+          0, 0, 0, 0, 0, 0)
+  XTREG(85, 340, 32, 4, 4, 0x0307, 0x0006,  2, 3, 0x0210, pol_reg00,
+          0, 0, 0, 0, 0, 0)
+  XTREG(86, 344, 32, 4, 4, 0x0308, 0x0006,  2, 3, 0x0210, pol_reg01,
+          0, 0, 0, 0, 0, 0)
+  XTREG(87, 348, 32, 4, 4, 0x0309, 0x0006,  2, 3, 0x0210, pol_reg02,
+          0, 0, 0, 0, 0, 0)
+  XTREG(88, 352, 32, 4, 4, 0x030a, 0x0006,  2, 3, 0x0210, pol_reg03,
+          0, 0, 0, 0, 0, 0)
+  XTREG(89, 356, 32, 4, 4, 0x030b, 0x0006,  2, 3, 0x0210, pol_reg04,
+          0, 0, 0, 0, 0, 0)
+  XTREG(90, 360, 32, 4, 4, 0x030c, 0x0006,  2, 3, 0x0210, pol_reg05,
+          0, 0, 0, 0, 0, 0)
+  XTREG(91, 364, 32, 4, 4, 0x030d, 0x0006,  2, 3, 0x0210, pol_reg06,
+          0, 0, 0, 0, 0, 0)
+  XTREG(92, 368, 32, 4, 4, 0x030e, 0x0006,  2, 3, 0x0210, pol_reg07,
+          0, 0, 0, 0, 0, 0)
+  XTREG(93, 372, 32, 4, 4, 0x030f, 0x0006,  2, 3, 0x0210, pol_reg08,
+          0, 0, 0, 0, 0, 0)
+  XTREG(94, 376, 32, 4, 4, 0x0310, 0x0006,  2, 3, 0x0210, pol_reg09,
+          0, 0, 0, 0, 0, 0)
+  XTREG(95, 380, 32, 4, 4, 0x0311, 0x0006,  2, 3, 0x0210, pol_reg10,
+          0, 0, 0, 0, 0, 0)
+  XTREG(96, 384, 32, 4, 4, 0x0312, 0x0006,  2, 3, 0x0210, pol_reg11,
+          0, 0, 0, 0, 0, 0)
+  XTREG(97, 388, 32, 4, 4, 0x0313, 0x0006,  2, 3, 0x0210, pol_reg12,
+          0, 0, 0, 0, 0, 0)
+  XTREG(98, 392, 32, 4, 4, 0x0314, 0x0006,  2, 3, 0x0210, pol_reg13,
+          0, 0, 0, 0, 0, 0)
+  XTREG(99, 396, 32, 4, 4, 0x0315, 0x0006,  2, 3, 0x0210, pol_reg14,
+          0, 0, 0, 0, 0, 0)
+  XTREG(100, 400, 32, 4, 4, 0x0316, 0x0006,  2, 3, 0x0210, pol_reg15,
+          0, 0, 0, 0, 0, 0)
+  XTREG(101, 404, 32, 4, 4, 0x0317, 0x0006,  2, 3, 0x0210, pol_reg16,
+          0, 0, 0, 0, 0, 0)
+  XTREG(102, 408, 32, 4, 4, 0x0318, 0x0006,  2, 3, 0x0210, pol_reg17,
+          0, 0, 0, 0, 0, 0)
+  XTREG(103, 412, 32, 4, 4, 0x0319, 0x0006,  2, 3, 0x0210, pol_reg18,
+          0, 0, 0, 0, 0, 0)
+  XTREG(104, 416, 32, 4, 4, 0x031a, 0x0006,  2, 3, 0x0210, pol_reg19,
+          0, 0, 0, 0, 0, 0)
+  XTREG(105, 420, 32, 4, 4, 0x031b, 0x0006,  2, 3, 0x0210, pol_reg20,
+          0, 0, 0, 0, 0, 0)
+  XTREG(106, 424, 32, 4, 4, 0x031c, 0x0006,  2, 3, 0x0210, pol_reg21,
+          0, 0, 0, 0, 0, 0)
+  XTREG(107, 428, 32, 4, 4, 0x031d, 0x0006,  2, 3, 0x0210, pol_reg22,
+          0, 0, 0, 0, 0, 0)
+  XTREG(108, 432, 32, 4, 4, 0x031e, 0x0006,  2, 3, 0x0210, pol_reg23,
+          0, 0, 0, 0, 0, 0)
+  XTREG(109, 436, 32, 4, 4, 0x031f, 0x0006,  2, 3, 0x0210, pol_reg24,
+          0, 0, 0, 0, 0, 0)
+  XTREG(110, 440, 32, 4, 4, 0x0320, 0x0006,  2, 3, 0x0210, pol_reg25,
+          0, 0, 0, 0, 0, 0)
+  XTREG(111, 444, 32, 4, 4, 0x0321, 0x0006,  2, 3, 0x0210, pol_reg26,
+          0, 0, 0, 0, 0, 0)
+  XTREG(112, 448, 32, 4, 4, 0x0322, 0x0006,  2, 3, 0x0210, pol_reg27,
+          0, 0, 0, 0, 0, 0)
+  XTREG(113, 452, 32, 4, 4, 0x0323, 0x0006,  2, 3, 0x0210, pol_reg28,
+          0, 0, 0, 0, 0, 0)
+  XTREG(114, 456, 32, 4, 4, 0x0324, 0x0006,  2, 3, 0x0210, pol_reg29,
+          0, 0, 0, 0, 0, 0)
+  XTREG(115, 460, 32, 4, 4, 0x0325, 0x0006,  2, 3, 0x0210, pol_reg30,
+          0, 0, 0, 0, 0, 0)
+  XTREG(116, 464, 32, 4, 4, 0x0326, 0x0006,  2, 3, 0x0210, pol_reg31,
+          0, 0, 0, 0, 0, 0)
+  XTREG(117, 468, 32, 4, 4, 0x0259, 0x000d, -2, 2, 0x1000, mmid,
+          0, 0, 0, 0, 0, 0)
+  XTREG(118, 472,  2, 4, 4, 0x0260, 0x0007, -2, 2, 0x1000, ibreakenable,
+          0, 0, 0, 0, 0, 0)
+  XTREG(119, 476,  6, 4, 4, 0x0263, 0x0007, -2, 2, 0x1000, atomctl,
+          0, 0, 0, 0, 0, 0)
+  XTREG(120, 480, 32, 4, 4, 0x0268, 0x0007, -2, 2, 0x1000, ddr,
+          0, 0, 0, 0, 0, 0)
+  XTREG(121, 484, 32, 4, 4, 0x0280, 0x0007, -2, 2, 0x1000, ibreaka0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(122, 488, 32, 4, 4, 0x0281, 0x0007, -2, 2, 0x1000, ibreaka1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(123, 492, 32, 4, 4, 0x0290, 0x0007, -2, 2, 0x1000, dbreaka0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(124, 496, 32, 4, 4, 0x0291, 0x0007, -2, 2, 0x1000, dbreaka1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(125, 500, 32, 4, 4, 0x02a0, 0x0007, -2, 2, 0x1000, dbreakc0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(126, 504, 32, 4, 4, 0x02a1, 0x0007, -2, 2, 0x1000, dbreakc1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(127, 508, 32, 4, 4, 0x02b1, 0x0007, -2, 2, 0x1000, epc1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(128, 512, 32, 4, 4, 0x02b2, 0x0007, -2, 2, 0x1000, epc2,
+          0, 0, 0, 0, 0, 0)
+  XTREG(129, 516, 32, 4, 4, 0x02b3, 0x0007, -2, 2, 0x1000, epc3,
+          0, 0, 0, 0, 0, 0)
+  XTREG(130, 520, 32, 4, 4, 0x02b4, 0x0007, -2, 2, 0x1000, epc4,
+          0, 0, 0, 0, 0, 0)
+  XTREG(131, 524, 32, 4, 4, 0x02b5, 0x0007, -2, 2, 0x1000, epc5,
+          0, 0, 0, 0, 0, 0)
+  XTREG(132, 528, 32, 4, 4, 0x02b6, 0x0007, -2, 2, 0x1000, epc6,
+          0, 0, 0, 0, 0, 0)
+  XTREG(133, 532, 32, 4, 4, 0x02c0, 0x0007, -2, 2, 0x1000, depc,
+          0, 0, 0, 0, 0, 0)
+  XTREG(134, 536, 19, 4, 4, 0x02c2, 0x0007, -2, 2, 0x1000, eps2,
+          0, 0, 0, 0, 0, 0)
+  XTREG(135, 540, 19, 4, 4, 0x02c3, 0x0007, -2, 2, 0x1000, eps3,
+          0, 0, 0, 0, 0, 0)
+  XTREG(136, 544, 19, 4, 4, 0x02c4, 0x0007, -2, 2, 0x1000, eps4,
+          0, 0, 0, 0, 0, 0)
+  XTREG(137, 548, 19, 4, 4, 0x02c5, 0x0007, -2, 2, 0x1000, eps5,
+          0, 0, 0, 0, 0, 0)
+  XTREG(138, 552, 19, 4, 4, 0x02c6, 0x0007, -2, 2, 0x1000, eps6,
+          0, 0, 0, 0, 0, 0)
+  XTREG(139, 556, 32, 4, 4, 0x02d1, 0x0007, -2, 2, 0x1000, excsave1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(140, 560, 32, 4, 4, 0x02d2, 0x0007, -2, 2, 0x1000, excsave2,
+          0, 0, 0, 0, 0, 0)
+  XTREG(141, 564, 32, 4, 4, 0x02d3, 0x0007, -2, 2, 0x1000, excsave3,
+          0, 0, 0, 0, 0, 0)
+  XTREG(142, 568, 32, 4, 4, 0x02d4, 0x0007, -2, 2, 0x1000, excsave4,
+          0, 0, 0, 0, 0, 0)
+  XTREG(143, 572, 32, 4, 4, 0x02d5, 0x0007, -2, 2, 0x1000, excsave5,
+          0, 0, 0, 0, 0, 0)
+  XTREG(144, 576, 32, 4, 4, 0x02d6, 0x0007, -2, 2, 0x1000, excsave6,
+          0, 0, 0, 0, 0, 0)
+  XTREG(145, 580,  4, 4, 4, 0x02e0, 0x0007, -2, 2, 0x1000, cpenable,
+          0, 0, 0, 0, 0, 0)
+  XTREG(146, 584, 13, 4, 4, 0x02e2, 0x000b, -2, 2, 0x1000, interrupt,
+          0, 0, 0, 0, 0, 0)
+  XTREG(147, 588, 13, 4, 4, 0x02e2, 0x000d, -2, 2, 0x1000, intset,
+          0, 0, 0, 0, 0, 0)
+  XTREG(148, 592, 13, 4, 4, 0x02e3, 0x000d, -2, 2, 0x1000, intclear,
+          0, 0, 0, 0, 0, 0)
+  XTREG(149, 596, 13, 4, 4, 0x02e4, 0x0007, -2, 2, 0x1000, intenable,
+          0, 0, 0, 0, 0, 0)
+  XTREG(150, 600, 32, 4, 4, 0x02e7, 0x0007, -2, 2, 0x1000, vecbase,
+          0, 0, 0, 0, 0, 0)
+  XTREG(151, 604,  6, 4, 4, 0x02e8, 0x0007, -2, 2, 0x1000, exccause,
+          0, 0, 0, 0, 0, 0)
+  XTREG(152, 608, 12, 4, 4, 0x02e9, 0x0003, -2, 2, 0x1000, debugcause,
+          0, 0, 0, 0, 0, 0)
+  XTREG(153, 612, 32, 4, 4, 0x02ea, 0x000f, -2, 2, 0x1000, ccount,
+          0, 0, 0, 0, 0, 0)
+  XTREG(154, 616, 32, 4, 4, 0x02eb, 0x0003, -2, 2, 0x1000, prid,
+          0, 0, 0, 0, 0, 0)
+  XTREG(155, 620, 32, 4, 4, 0x02ec, 0x000f, -2, 2, 0x1000, icount,
+          0, 0, 0, 0, 0, 0)
+  XTREG(156, 624,  4, 4, 4, 0x02ed, 0x0007, -2, 2, 0x1000, icountlevel,
+          0, 0, 0, 0, 0, 0)
+  XTREG(157, 628, 32, 4, 4, 0x02ee, 0x0007, -2, 2, 0x1000, excvaddr,
+          0, 0, 0, 0, 0, 0)
+  XTREG(158, 632, 32, 4, 4, 0x02f0, 0x000f, -2, 2, 0x1000, ccompare0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(159, 636, 32, 4, 4, 0x02f1, 0x000f, -2, 2, 0x1000, ccompare1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(160, 640, 32, 4, 4, 0x0000, 0x0006, -2, 8, 0x0100, a0,
+          0, 0, 0, 0, 0, 0)
+  XTREG(161, 644, 32, 4, 4, 0x0001, 0x0006, -2, 8, 0x0100, a1,
+          0, 0, 0, 0, 0, 0)
+  XTREG(162, 648, 32, 4, 4, 0x0002, 0x0006, -2, 8, 0x0100, a2,
+          0, 0, 0, 0, 0, 0)
+  XTREG(163, 652, 32, 4, 4, 0x0003, 0x0006, -2, 8, 0x0100, a3,
+          0, 0, 0, 0, 0, 0)
+  XTREG(164, 656, 32, 4, 4, 0x0004, 0x0006, -2, 8, 0x0100, a4,
+          0, 0, 0, 0, 0, 0)
+  XTREG(165, 660, 32, 4, 4, 0x0005, 0x0006, -2, 8, 0x0100, a5,
+          0, 0, 0, 0, 0, 0)
+  XTREG(166, 664, 32, 4, 4, 0x0006, 0x0006, -2, 8, 0x0100, a6,
+          0, 0, 0, 0, 0, 0)
+  XTREG(167, 668, 32, 4, 4, 0x0007, 0x0006, -2, 8, 0x0100, a7,
+          0, 0, 0, 0, 0, 0)
+  XTREG(168, 672, 32, 4, 4, 0x0008, 0x0006, -2, 8, 0x0100, a8,
+          0, 0, 0, 0, 0, 0)
+  XTREG(169, 676, 32, 4, 4, 0x0009, 0x0006, -2, 8, 0x0100, a9,
+          0, 0, 0, 0, 0, 0)
+  XTREG(170, 680, 32, 4, 4, 0x000a, 0x0006, -2, 8, 0x0100, a10,
+          0, 0, 0, 0, 0, 0)
+  XTREG(171, 684, 32, 4, 4, 0x000b, 0x0006, -2, 8, 0x0100, a11,
+          0, 0, 0, 0, 0, 0)
+  XTREG(172, 688, 32, 4, 4, 0x000c, 0x0006, -2, 8, 0x0100, a12,
+          0, 0, 0, 0, 0, 0)
+  XTREG(173, 692, 32, 4, 4, 0x000d, 0x0006, -2, 8, 0x0100, a13,
+          0, 0, 0, 0, 0, 0)
+  XTREG(174, 696, 32, 4, 4, 0x000e, 0x0006, -2, 8, 0x0100, a14,
+          0, 0, 0, 0, 0, 0)
+  XTREG(175, 700, 32, 4, 4, 0x000f, 0x0006, -2, 8, 0x0100, a15,
+          0, 0, 0, 0, 0, 0)
diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c
index dacb379..11c318d 100644
--- a/target-xtensa/helper.c
+++ b/target-xtensa/helper.c
@@ -34,6 +34,10 @@
 #include "hw/loader.h"
 #endif
 
+#define XTREG(idx, ofs, bi, sz, al, no, flags, cp, typ, grp, name, \
+        a1, a2, a3, a4, a5, a6) \
+    { .targno = (no), .type = (typ), .group = (grp) },
+
 void cpu_reset(CPUXtensaState *env)
 {
     env->exception_taken = 0;
@@ -52,6 +56,13 @@ static const XtensaConfig core_config[] = {
         .options = -1 ^
             (XTENSA_OPTION_BIT(XTENSA_OPTION_HW_ALIGNMENT) |
              XTENSA_OPTION_BIT(XTENSA_OPTION_MMU)),
+        .gdb_regmap = {
+            .num_regs = 176,
+            .num_core_regs = 117,
+            .reg = {
+#include "gdb-config-sample-xtensa-core.c"
+            }
+        },
         .nareg = 64,
         .ndepc = 1,
         .excm_level = 16,
commit 97836ceed39bb1be9a72c9d7c122657d569731d9
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Tue Sep 6 03:55:51 2011 +0400

    target-xtensa: implement relocatable vectors
    
    See ISA, 4.4.3 for details.
    
    Vector addresses recorded in core configuration are absolute values that
    correspond to default VECBASE value.
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index 37f8b7f..c9094e9 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -123,6 +123,7 @@ enum {
     INTCLEAR = 227,
     INTENABLE = 228,
     PS = 230,
+    VECBASE = 231,
     EXCCAUSE = 232,
     CCOUNT = 234,
     PRID = 235,
@@ -219,6 +220,7 @@ typedef struct XtensaConfig {
     unsigned nareg;
     int excm_level;
     int ndepc;
+    uint32_t vecbase;
     uint32_t exception_vector[EXC_MAX];
     unsigned ninterrupt;
     unsigned nlevel;
diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c
index c24a38a..dacb379 100644
--- a/target-xtensa/helper.c
+++ b/target-xtensa/helper.c
@@ -41,6 +41,7 @@ void cpu_reset(CPUXtensaState *env)
     env->sregs[LITBASE] &= ~1;
     env->sregs[PS] = xtensa_option_enabled(env->config,
             XTENSA_OPTION_INTERRUPT) ? 0x1f : 0x10;
+    env->sregs[VECBASE] = env->config->vecbase;
 
     env->pending_irq_level = 0;
 }
@@ -54,6 +55,7 @@ static const XtensaConfig core_config[] = {
         .nareg = 64,
         .ndepc = 1,
         .excm_level = 16,
+        .vecbase = 0x5fff8400,
         .exception_vector = {
             [EXC_RESET] = 0x5fff8000,
             [EXC_WINDOW_OVERFLOW4] = 0x5fff8400,
@@ -140,6 +142,16 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
     return addr;
 }
 
+static uint32_t relocated_vector(CPUState *env, uint32_t vector)
+{
+    if (xtensa_option_enabled(env->config,
+                XTENSA_OPTION_RELOCATABLE_VECTOR)) {
+        return vector - env->config->vecbase + env->sregs[VECBASE];
+    } else {
+        return vector;
+    }
+}
+
 /*!
  * Handle penging IRQ.
  * For the high priority interrupt jump to the corresponding interrupt vector.
@@ -160,7 +172,8 @@ static void handle_interrupt(CPUState *env)
             env->sregs[EPS2 + level - 2] = env->sregs[PS];
             env->sregs[PS] =
                 (env->sregs[PS] & ~PS_INTLEVEL) | level | PS_EXCM;
-            env->pc = env->config->interrupt_vector[level];
+            env->pc = relocated_vector(env,
+                    env->config->interrupt_vector[level]);
         } else {
             env->sregs[EXCCAUSE] = LEVEL1_INTERRUPT_CAUSE;
 
@@ -212,7 +225,8 @@ void do_interrupt(CPUState *env)
                 __func__, env->exception_index,
                 env->pc, env->regs[0], env->sregs[PS], env->sregs[CCOUNT]);
         if (env->config->exception_vector[env->exception_index]) {
-            env->pc = env->config->exception_vector[env->exception_index];
+            env->pc = relocated_vector(env,
+                    env->config->exception_vector[env->exception_index]);
             env->exception_taken = 1;
         } else {
             qemu_log("%s(pc = %08x) bad exception_index: %d\n",
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index d08b0ca..bd10ae5 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -106,6 +106,7 @@ static const char * const sregnames[256] = {
     [INTCLEAR] = "INTCLEAR",
     [INTENABLE] = "INTENABLE",
     [PS] = "PS",
+    [VECBASE] = "VECBASE",
     [EXCCAUSE] = "EXCCAUSE",
     [CCOUNT] = "CCOUNT",
     [PRID] = "PRID",
commit f3df4c04d83b7f2f319ca8025c895b74aa7eab8d
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Tue Sep 6 03:55:50 2011 +0400

    target-xtensa: implement CPENABLE and PRID SRs
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/xtensa_sample.c b/hw/xtensa_sample.c
index 0aeb7c8..31a6f70 100644
--- a/hw/xtensa_sample.c
+++ b/hw/xtensa_sample.c
@@ -55,6 +55,7 @@ static void xtensa_init(ram_addr_t ram_size,
             exit(1);
         }
         qemu_register_reset(xtensa_sample_reset, env);
+        env->sregs[PRID] = n;
     }
 
     ram = g_malloc(sizeof(*ram));
diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index 474466c..37f8b7f 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -118,12 +118,14 @@ enum {
     DEPC = 192,
     EPS2 = 194,
     EXCSAVE1 = 209,
+    CPENABLE = 224,
     INTSET = 226,
     INTCLEAR = 227,
     INTENABLE = 228,
     PS = 230,
     EXCCAUSE = 232,
     CCOUNT = 234,
+    PRID = 235,
     EXCVADDR = 238,
     CCOMPARE = 240,
 };
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index cee1f1c..d08b0ca 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -101,12 +101,14 @@ static const char * const sregnames[256] = {
     [EXCSAVE1 + 4] = "EXCSAVE5",
     [EXCSAVE1 + 5] = "EXCSAVE6",
     [EXCSAVE1 + 6] = "EXCSAVE7",
+    [CPENABLE] = "CPENABLE",
     [INTSET] = "INTSET",
     [INTCLEAR] = "INTCLEAR",
     [INTENABLE] = "INTENABLE",
     [PS] = "PS",
     [EXCCAUSE] = "EXCCAUSE",
     [CCOUNT] = "CCOUNT",
+    [PRID] = "PRID",
     [EXCVADDR] = "EXCVADDR",
     [CCOMPARE] = "CCOMPARE0",
     [CCOMPARE + 1] = "CCOMPARE1",
@@ -476,6 +478,10 @@ static void gen_wsr_ps(DisasContext *dc, uint32_t sr, TCGv_i32 v)
     gen_jumpi_check_loop_end(dc, -1);
 }
 
+static void gen_wsr_prid(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+}
+
 static void gen_wsr_ccompare(DisasContext *dc, uint32_t sr, TCGv_i32 v)
 {
     uint32_t id = sr - CCOMPARE;
@@ -502,6 +508,7 @@ static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s)
         [INTCLEAR] = gen_wsr_intclear,
         [INTENABLE] = gen_wsr_intenable,
         [PS] = gen_wsr_ps,
+        [PRID] = gen_wsr_prid,
         [CCOMPARE] = gen_wsr_ccompare,
         [CCOMPARE + 1] = gen_wsr_ccompare,
         [CCOMPARE + 2] = gen_wsr_ccompare,
commit 772177c194e5ea113945a9b5c15a6ab47bb84006
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Tue Sep 6 03:55:49 2011 +0400

    target-xtensa: implement accurate window check
    
    See ISA, 4.7.1.3 for details.
    
    Window check is inserted before commands that push "used register
    watermark" beyond its current level. Used register watermark is reset on
    instructions that change WINDOW_BASE/WINDOW_START SRs.
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index d75e780..cee1f1c 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -60,6 +60,7 @@ typedef struct DisasContext {
     TCGv_i32 sar_m32;
 
     uint32_t ccount_delta;
+    unsigned used_window;
 } DisasContext;
 
 static TCGv_ptr cpu_env;
@@ -225,6 +226,11 @@ static void gen_advance_ccount(DisasContext *dc)
     }
 }
 
+static void reset_used_window(DisasContext *dc)
+{
+    dc->used_window = 0;
+}
+
 static void gen_exception(DisasContext *dc, int excp)
 {
     TCGv_i32 tmp = tcg_const_i32(excp);
@@ -418,6 +424,13 @@ static void gen_wsr_litbase(DisasContext *dc, uint32_t sr, TCGv_i32 s)
 static void gen_wsr_windowbase(DisasContext *dc, uint32_t sr, TCGv_i32 v)
 {
     gen_helper_wsr_windowbase(v);
+    reset_used_window(dc);
+}
+
+static void gen_wsr_windowstart(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+    tcg_gen_mov_i32(cpu_SR[sr], v);
+    reset_used_window(dc);
 }
 
 static void gen_wsr_intset(DisasContext *dc, uint32_t sr, TCGv_i32 v)
@@ -457,6 +470,7 @@ static void gen_wsr_ps(DisasContext *dc, uint32_t sr, TCGv_i32 v)
         mask |= PS_RING;
     }
     tcg_gen_andi_i32(cpu_SR[sr], v, mask);
+    reset_used_window(dc);
     gen_helper_check_interrupts(cpu_env);
     /* This can change mmu index and tb->flags, so exit tb */
     gen_jumpi_check_loop_end(dc, -1);
@@ -483,6 +497,7 @@ static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s)
         [SAR] = gen_wsr_sar,
         [LITBASE] = gen_wsr_litbase,
         [WINDOW_BASE] = gen_wsr_windowbase,
+        [WINDOW_START] = gen_wsr_windowstart,
         [INTSET] = gen_wsr_intset,
         [INTCLEAR] = gen_wsr_intclear,
         [INTENABLE] = gen_wsr_intenable,
@@ -530,6 +545,36 @@ static void gen_waiti(DisasContext *dc, uint32_t imm4)
     tcg_temp_free(intlevel);
 }
 
+static void gen_window_check1(DisasContext *dc, unsigned r1)
+{
+    if (dc->tb->flags & XTENSA_TBFLAG_EXCM) {
+        return;
+    }
+    if (option_enabled(dc, XTENSA_OPTION_WINDOWED_REGISTER) &&
+            r1 / 4 > dc->used_window) {
+        TCGv_i32 pc = tcg_const_i32(dc->pc);
+        TCGv_i32 w = tcg_const_i32(r1 / 4);
+
+        dc->used_window = r1 / 4;
+        gen_advance_ccount(dc);
+        gen_helper_window_check(pc, w);
+
+        tcg_temp_free(w);
+        tcg_temp_free(pc);
+    }
+}
+
+static void gen_window_check2(DisasContext *dc, unsigned r1, unsigned r2)
+{
+    gen_window_check1(dc, r1 > r2 ? r1 : r2);
+}
+
+static void gen_window_check3(DisasContext *dc, unsigned r1, unsigned r2,
+        unsigned r3)
+{
+    gen_window_check2(dc, r1, r2 > r3 ? r2 : r3);
+}
+
 static void disas_xtensa_insn(DisasContext *dc)
 {
 #define HAS_OPTION(opt) do { \
@@ -659,6 +704,7 @@ static void disas_xtensa_insn(DisasContext *dc)
                         switch (CALLX_N) {
                         case 0: /*RET*/
                         case 2: /*JX*/
+                            gen_window_check1(dc, CALLX_S);
                             gen_jump(dc, cpu_R[CALLX_S]);
                             break;
 
@@ -680,6 +726,7 @@ static void disas_xtensa_insn(DisasContext *dc)
                         break;
 
                     case 3: /*CALLX*/
+                        gen_window_check2(dc, CALLX_S, CALLX_N << 2);
                         switch (CALLX_N) {
                         case 0: /*CALLX0*/
                             {
@@ -710,6 +757,7 @@ static void disas_xtensa_insn(DisasContext *dc)
 
                 case 1: /*MOVSPw*/
                     HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                    gen_window_check2(dc, RRR_T, RRR_S);
                     {
                         TCGv_i32 pc = tcg_const_i32(dc->pc);
                         gen_advance_ccount(dc);
@@ -863,6 +911,7 @@ static void disas_xtensa_insn(DisasContext *dc)
                 case 6: /*RSILx*/
                     HAS_OPTION(XTENSA_OPTION_INTERRUPT);
                     gen_check_privilege(dc);
+                    gen_window_check1(dc, RRR_T);
                     tcg_gen_mov_i32(cpu_R[RRR_T], cpu_SR[PS]);
                     tcg_gen_andi_i32(cpu_SR[PS], cpu_SR[PS], ~PS_INTLEVEL);
                     tcg_gen_ori_i32(cpu_SR[PS], cpu_SR[PS], RRR_S);
@@ -904,28 +953,34 @@ static void disas_xtensa_insn(DisasContext *dc)
                 break;
 
             case 1: /*AND*/
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
                 tcg_gen_and_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
                 break;
 
             case 2: /*OR*/
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
                 tcg_gen_or_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
                 break;
 
             case 3: /*XOR*/
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
                 tcg_gen_xor_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
                 break;
 
             case 4: /*ST1*/
                 switch (RRR_R) {
                 case 0: /*SSR*/
+                    gen_window_check1(dc, RRR_S);
                     gen_right_shift_sar(dc, cpu_R[RRR_S]);
                     break;
 
                 case 1: /*SSL*/
+                    gen_window_check1(dc, RRR_S);
                     gen_left_shift_sar(dc, cpu_R[RRR_S]);
                     break;
 
                 case 2: /*SSA8L*/
+                    gen_window_check1(dc, RRR_S);
                     {
                         TCGv_i32 tmp = tcg_temp_new_i32();
                         tcg_gen_shli_i32(tmp, cpu_R[RRR_S], 3);
@@ -935,6 +990,7 @@ static void disas_xtensa_insn(DisasContext *dc)
                     break;
 
                 case 3: /*SSA8B*/
+                    gen_window_check1(dc, RRR_S);
                     {
                         TCGv_i32 tmp = tcg_temp_new_i32();
                         tcg_gen_shli_i32(tmp, cpu_R[RRR_S], 3);
@@ -968,16 +1024,19 @@ static void disas_xtensa_insn(DisasContext *dc)
                                 RRR_T | ((RRR_T & 8) ? 0xfffffff0 : 0));
                         gen_helper_rotw(tmp);
                         tcg_temp_free(tmp);
+                        reset_used_window(dc);
                     }
                     break;
 
                 case 14: /*NSAu*/
                     HAS_OPTION(XTENSA_OPTION_MISC_OP);
+                    gen_window_check2(dc, RRR_S, RRR_T);
                     gen_helper_nsa(cpu_R[RRR_T], cpu_R[RRR_S]);
                     break;
 
                 case 15: /*NSAUu*/
                     HAS_OPTION(XTENSA_OPTION_MISC_OP);
+                    gen_window_check2(dc, RRR_S, RRR_T);
                     gen_helper_nsau(cpu_R[RRR_T], cpu_R[RRR_S]);
                     break;
 
@@ -992,6 +1051,7 @@ static void disas_xtensa_insn(DisasContext *dc)
                 break;
 
             case 6: /*RT0*/
+                gen_window_check2(dc, RRR_R, RRR_T);
                 switch (RRR_S) {
                 case 0: /*NEG*/
                     tcg_gen_neg_i32(cpu_R[RRR_R], cpu_R[RRR_T]);
@@ -1019,12 +1079,14 @@ static void disas_xtensa_insn(DisasContext *dc)
                 break;
 
             case 8: /*ADD*/
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
                 tcg_gen_add_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
                 break;
 
             case 9: /*ADD**/
             case 10:
             case 11:
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
                 {
                     TCGv_i32 tmp = tcg_temp_new_i32();
                     tcg_gen_shli_i32(tmp, cpu_R[RRR_S], OP2 - 8);
@@ -1034,12 +1096,14 @@ static void disas_xtensa_insn(DisasContext *dc)
                 break;
 
             case 12: /*SUB*/
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
                 tcg_gen_sub_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
                 break;
 
             case 13: /*SUB**/
             case 14:
             case 15:
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
                 {
                     TCGv_i32 tmp = tcg_temp_new_i32();
                     tcg_gen_shli_i32(tmp, cpu_R[RRR_S], OP2 - 12);
@@ -1054,17 +1118,20 @@ static void disas_xtensa_insn(DisasContext *dc)
             switch (OP2) {
             case 0: /*SLLI*/
             case 1:
+                gen_window_check2(dc, RRR_R, RRR_S);
                 tcg_gen_shli_i32(cpu_R[RRR_R], cpu_R[RRR_S],
                         32 - (RRR_T | ((OP2 & 1) << 4)));
                 break;
 
             case 2: /*SRAI*/
             case 3:
+                gen_window_check2(dc, RRR_R, RRR_T);
                 tcg_gen_sari_i32(cpu_R[RRR_R], cpu_R[RRR_T],
                         RRR_S | ((OP2 & 1) << 4));
                 break;
 
             case 4: /*SRLI*/
+                gen_window_check2(dc, RRR_R, RRR_T);
                 tcg_gen_shri_i32(cpu_R[RRR_R], cpu_R[RRR_T], RRR_S);
                 break;
 
@@ -1074,6 +1141,7 @@ static void disas_xtensa_insn(DisasContext *dc)
                     if (RSR_SR >= 64) {
                         gen_check_privilege(dc);
                     }
+                    gen_window_check1(dc, RRR_T);
                     tcg_gen_mov_i32(tmp, cpu_R[RRR_T]);
                     gen_rsr(dc, cpu_R[RRR_T], RSR_SR);
                     gen_wsr(dc, RSR_SR, tmp);
@@ -1100,6 +1168,7 @@ static void disas_xtensa_insn(DisasContext *dc)
 #define gen_shift(cmd) gen_shift_reg(cmd, cpu_SR[SAR])
 
             case 8: /*SRC*/
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
                 {
                     TCGv_i64 v = tcg_temp_new_i64();
                     tcg_gen_concat_i32_i64(v, cpu_R[RRR_T], cpu_R[RRR_S]);
@@ -1108,6 +1177,7 @@ static void disas_xtensa_insn(DisasContext *dc)
                 break;
 
             case 9: /*SRL*/
+                gen_window_check2(dc, RRR_R, RRR_T);
                 if (dc->sar_5bit) {
                     tcg_gen_shr_i32(cpu_R[RRR_R], cpu_R[RRR_T], cpu_SR[SAR]);
                 } else {
@@ -1118,6 +1188,7 @@ static void disas_xtensa_insn(DisasContext *dc)
                 break;
 
             case 10: /*SLL*/
+                gen_window_check2(dc, RRR_R, RRR_S);
                 if (dc->sar_m32_5bit) {
                     tcg_gen_shl_i32(cpu_R[RRR_R], cpu_R[RRR_S], dc->sar_m32);
                 } else {
@@ -1132,6 +1203,7 @@ static void disas_xtensa_insn(DisasContext *dc)
                 break;
 
             case 11: /*SRA*/
+                gen_window_check2(dc, RRR_R, RRR_T);
                 if (dc->sar_5bit) {
                     tcg_gen_sar_i32(cpu_R[RRR_R], cpu_R[RRR_T], cpu_SR[SAR]);
                 } else {
@@ -1145,6 +1217,7 @@ static void disas_xtensa_insn(DisasContext *dc)
 
             case 12: /*MUL16U*/
                 HAS_OPTION(XTENSA_OPTION_16_BIT_IMUL);
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
                 {
                     TCGv_i32 v1 = tcg_temp_new_i32();
                     TCGv_i32 v2 = tcg_temp_new_i32();
@@ -1158,6 +1231,7 @@ static void disas_xtensa_insn(DisasContext *dc)
 
             case 13: /*MUL16S*/
                 HAS_OPTION(XTENSA_OPTION_16_BIT_IMUL);
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
                 {
                     TCGv_i32 v1 = tcg_temp_new_i32();
                     TCGv_i32 v2 = tcg_temp_new_i32();
@@ -1176,6 +1250,8 @@ static void disas_xtensa_insn(DisasContext *dc)
             break;
 
         case 2: /*RST2*/
+            gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
+
             if (OP2 >= 12) {
                 HAS_OPTION(XTENSA_OPTION_32_BIT_IDIV);
                 int label = gen_new_label();
@@ -1260,6 +1336,7 @@ static void disas_xtensa_insn(DisasContext *dc)
                 if (RSR_SR >= 64) {
                     gen_check_privilege(dc);
                 }
+                gen_window_check1(dc, RRR_T);
                 gen_rsr(dc, cpu_R[RRR_T], RSR_SR);
                 if (!sregnames[RSR_SR]) {
                     TBD();
@@ -1270,6 +1347,7 @@ static void disas_xtensa_insn(DisasContext *dc)
                 if (RSR_SR >= 64) {
                     gen_check_privilege(dc);
                 }
+                gen_window_check1(dc, RRR_T);
                 gen_wsr(dc, RSR_SR, cpu_R[RRR_T]);
                 if (!sregnames[RSR_SR]) {
                     TBD();
@@ -1278,6 +1356,7 @@ static void disas_xtensa_insn(DisasContext *dc)
 
             case 2: /*SEXTu*/
                 HAS_OPTION(XTENSA_OPTION_MISC_OP);
+                gen_window_check2(dc, RRR_R, RRR_S);
                 {
                     int shift = 24 - RRR_T;
 
@@ -1296,6 +1375,7 @@ static void disas_xtensa_insn(DisasContext *dc)
 
             case 3: /*CLAMPSu*/
                 HAS_OPTION(XTENSA_OPTION_MISC_OP);
+                gen_window_check2(dc, RRR_R, RRR_S);
                 {
                     TCGv_i32 tmp1 = tcg_temp_new_i32();
                     TCGv_i32 tmp2 = tcg_temp_new_i32();
@@ -1323,6 +1403,7 @@ static void disas_xtensa_insn(DisasContext *dc)
             case 6: /*MINUu*/
             case 7: /*MAXUu*/
                 HAS_OPTION(XTENSA_OPTION_MISC_OP);
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
                 {
                     static const TCGCond cond[] = {
                         TCG_COND_LE,
@@ -1350,6 +1431,7 @@ static void disas_xtensa_insn(DisasContext *dc)
             case 9: /*MOVNEZ*/
             case 10: /*MOVLTZ*/
             case 11: /*MOVGEZ*/
+                gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
                 {
                     static const TCGCond cond[] = {
                         TCG_COND_NE,
@@ -1375,6 +1457,7 @@ static void disas_xtensa_insn(DisasContext *dc)
                 break;
 
             case 14: /*RUR*/
+                gen_window_check1(dc, RRR_R);
                 {
                     int st = (RRR_S << 4) + RRR_T;
                     if (uregnames[st]) {
@@ -1387,6 +1470,7 @@ static void disas_xtensa_insn(DisasContext *dc)
                 break;
 
             case 15: /*WUR*/
+                gen_window_check1(dc, RRR_T);
                 {
                     if (uregnames[RSR_SR]) {
                         tcg_gen_mov_i32(cpu_UR[RSR_SR], cpu_R[RRR_T]);
@@ -1402,6 +1486,7 @@ static void disas_xtensa_insn(DisasContext *dc)
 
         case 4: /*EXTUI*/
         case 5:
+            gen_window_check2(dc, RRR_R, RRR_T);
             {
                 int shiftimm = RRR_S | (OP1 << 4);
                 int maskimm = (1 << (OP2 + 1)) - 1;
@@ -1427,6 +1512,7 @@ static void disas_xtensa_insn(DisasContext *dc)
             break;
 
         case 9: /*LSC4*/
+            gen_window_check2(dc, RRR_S, RRR_T);
             switch (OP2) {
             case 0: /*L32E*/
                 HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
@@ -1475,6 +1561,7 @@ static void disas_xtensa_insn(DisasContext *dc)
         break;
 
     case 1: /*L32R*/
+        gen_window_check1(dc, RRR_T);
         {
             TCGv_i32 tmp = tcg_const_i32(
                     ((dc->tb->flags & XTENSA_TBFLAG_LITBASE) ?
@@ -1492,6 +1579,7 @@ static void disas_xtensa_insn(DisasContext *dc)
     case 2: /*LSAI*/
 #define gen_load_store(type, shift) do { \
             TCGv_i32 addr = tcg_temp_new_i32(); \
+            gen_window_check2(dc, RRI8_S, RRI8_T); \
             tcg_gen_addi_i32(addr, cpu_R[RRI8_S], RRI8_IMM8 << shift); \
             if (shift) { \
                 gen_load_store_alignment(dc, shift, addr, false); \
@@ -1628,6 +1716,7 @@ static void disas_xtensa_insn(DisasContext *dc)
 #undef gen_load_store
 
         case 10: /*MOVI*/
+            gen_window_check1(dc, RRI8_T);
             tcg_gen_movi_i32(cpu_R[RRI8_T],
                     RRI8_IMM8 | (RRI8_S << 8) |
                     ((RRI8_S & 0x8) ? 0xfffff000 : 0));
@@ -1635,6 +1724,7 @@ static void disas_xtensa_insn(DisasContext *dc)
 
 #define gen_load_store_no_hw_align(type) do { \
             TCGv_i32 addr = tcg_temp_local_new_i32(); \
+            gen_window_check2(dc, RRI8_S, RRI8_T); \
             tcg_gen_addi_i32(addr, cpu_R[RRI8_S], RRI8_IMM8 << 2); \
             gen_load_store_alignment(dc, 2, addr, true); \
             tcg_gen_qemu_##type(cpu_R[RRI8_T], addr, dc->cring); \
@@ -1647,15 +1737,18 @@ static void disas_xtensa_insn(DisasContext *dc)
             break;
 
         case 12: /*ADDI*/
+            gen_window_check2(dc, RRI8_S, RRI8_T);
             tcg_gen_addi_i32(cpu_R[RRI8_T], cpu_R[RRI8_S], RRI8_IMM8_SE);
             break;
 
         case 13: /*ADDMI*/
+            gen_window_check2(dc, RRI8_S, RRI8_T);
             tcg_gen_addi_i32(cpu_R[RRI8_T], cpu_R[RRI8_S], RRI8_IMM8_SE << 8);
             break;
 
         case 14: /*S32C1Iy*/
             HAS_OPTION(XTENSA_OPTION_MP_SYNCHRO);
+            gen_window_check2(dc, RRI8_S, RRI8_T);
             {
                 int label = gen_new_label();
                 TCGv_i32 tmp = tcg_temp_local_new_i32();
@@ -1709,6 +1802,7 @@ static void disas_xtensa_insn(DisasContext *dc)
         case 2: /*CALL8w*/
         case 3: /*CALL12w*/
             HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+            gen_window_check1(dc, CALL_N << 2);
             gen_callwi(dc, CALL_N,
                     (dc->pc & ~3) + (CALL_OFFSET_SE << 2) + 4, 0);
             break;
@@ -1722,6 +1816,7 @@ static void disas_xtensa_insn(DisasContext *dc)
             break;
 
         case 1: /*BZ*/
+            gen_window_check1(dc, BRI12_S);
             {
                 static const TCGCond cond[] = {
                     TCG_COND_EQ, /*BEQZ*/
@@ -1736,6 +1831,7 @@ static void disas_xtensa_insn(DisasContext *dc)
             break;
 
         case 2: /*BI0*/
+            gen_window_check1(dc, BRI8_S);
             {
                 static const TCGCond cond[] = {
                     TCG_COND_EQ, /*BEQI*/
@@ -1762,6 +1858,7 @@ static void disas_xtensa_insn(DisasContext *dc)
                     tcg_temp_free(imm);
                     tcg_temp_free(s);
                     tcg_temp_free(pc);
+                    reset_used_window(dc);
                 }
                 break;
 
@@ -1781,6 +1878,7 @@ static void disas_xtensa_insn(DisasContext *dc)
                 case 9: /*LOOPNEZ*/
                 case 10: /*LOOPGTZ*/
                     HAS_OPTION(XTENSA_OPTION_LOOP);
+                    gen_window_check1(dc, RRI8_S);
                     {
                         uint32_t lend = dc->pc + RRI8_IMM8 + 4;
                         TCGv_i32 tmp = tcg_const_i32(lend);
@@ -1812,6 +1910,7 @@ static void disas_xtensa_insn(DisasContext *dc)
 
             case 2: /*BLTUI*/
             case 3: /*BGEUI*/
+                gen_window_check1(dc, BRI8_S);
                 gen_brcondi(dc, BRI8_M == 2 ? TCG_COND_LTU : TCG_COND_GEU,
                         cpu_R[BRI8_S], B4CONSTU[BRI8_R], 4 + BRI8_IMM8_SE);
                 break;
@@ -1827,6 +1926,7 @@ static void disas_xtensa_insn(DisasContext *dc)
 
             switch (RRI8_R & 7) {
             case 0: /*BNONE*/ /*BANY*/
+                gen_window_check2(dc, RRI8_S, RRI8_T);
                 {
                     TCGv_i32 tmp = tcg_temp_new_i32();
                     tcg_gen_and_i32(tmp, cpu_R[RRI8_S], cpu_R[RRI8_T]);
@@ -1838,6 +1938,7 @@ static void disas_xtensa_insn(DisasContext *dc)
             case 1: /*BEQ*/ /*BNE*/
             case 2: /*BLT*/ /*BGE*/
             case 3: /*BLTU*/ /*BGEU*/
+                gen_window_check2(dc, RRI8_S, RRI8_T);
                 {
                     static const TCGCond cond[] = {
                         [1] = TCG_COND_EQ,
@@ -1853,6 +1954,7 @@ static void disas_xtensa_insn(DisasContext *dc)
                 break;
 
             case 4: /*BALL*/ /*BNALL*/
+                gen_window_check2(dc, RRI8_S, RRI8_T);
                 {
                     TCGv_i32 tmp = tcg_temp_new_i32();
                     tcg_gen_and_i32(tmp, cpu_R[RRI8_S], cpu_R[RRI8_T]);
@@ -1863,6 +1965,7 @@ static void disas_xtensa_insn(DisasContext *dc)
                 break;
 
             case 5: /*BBC*/ /*BBS*/
+                gen_window_check2(dc, RRI8_S, RRI8_T);
                 {
                     TCGv_i32 bit = tcg_const_i32(1);
                     TCGv_i32 tmp = tcg_temp_new_i32();
@@ -1877,6 +1980,7 @@ static void disas_xtensa_insn(DisasContext *dc)
 
             case 6: /*BBCI*/ /*BBSI*/
             case 7:
+                gen_window_check1(dc, RRI8_S);
                 {
                     TCGv_i32 tmp = tcg_temp_new_i32();
                     tcg_gen_andi_i32(tmp, cpu_R[RRI8_S],
@@ -1892,6 +1996,7 @@ static void disas_xtensa_insn(DisasContext *dc)
 
 #define gen_narrow_load_store(type) do { \
             TCGv_i32 addr = tcg_temp_new_i32(); \
+            gen_window_check2(dc, RRRN_S, RRRN_T); \
             tcg_gen_addi_i32(addr, cpu_R[RRRN_S], RRRN_R << 2); \
             gen_load_store_alignment(dc, 2, addr, false); \
             tcg_gen_qemu_##type(cpu_R[RRRN_T], addr, dc->cring); \
@@ -1908,14 +2013,17 @@ static void disas_xtensa_insn(DisasContext *dc)
 #undef gen_narrow_load_store
 
     case 10: /*ADD.Nn*/
+        gen_window_check3(dc, RRRN_R, RRRN_S, RRRN_T);
         tcg_gen_add_i32(cpu_R[RRRN_R], cpu_R[RRRN_S], cpu_R[RRRN_T]);
         break;
 
     case 11: /*ADDI.Nn*/
+        gen_window_check2(dc, RRRN_R, RRRN_S);
         tcg_gen_addi_i32(cpu_R[RRRN_R], cpu_R[RRRN_S], RRRN_T ? RRRN_T : -1);
         break;
 
     case 12: /*ST2n*/
+        gen_window_check1(dc, RRRN_S);
         if (RRRN_T < 8) { /*MOVI.Nn*/
             tcg_gen_movi_i32(cpu_R[RRRN_S],
                     RRRN_R | (RRRN_T << 4) |
@@ -1931,6 +2039,7 @@ static void disas_xtensa_insn(DisasContext *dc)
     case 13: /*ST3n*/
         switch (RRRN_R) {
         case 0: /*MOV.Nn*/
+            gen_window_check2(dc, RRRN_S, RRRN_T);
             tcg_gen_mov_i32(cpu_R[RRRN_T], cpu_R[RRRN_S]);
             break;
 
@@ -2034,6 +2143,7 @@ static void gen_intermediate_code_internal(
 
     init_litbase(&dc);
     init_sar_tracker(&dc);
+    reset_used_window(&dc);
 
     gen_icount_start();
 
commit b994e91b00cce463bfd306482dfe21630e11bf68
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Tue Sep 6 03:55:48 2011 +0400

    target-xtensa: implement interrupt option
    
    See ISA, 4.4.6 (interrupt option), 4.4.7 (high priority interrupt
    option) and 4.4.8 (timer interrupt option) for details.
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/xtensa_pic.c b/hw/xtensa_pic.c
index 91a5445..3033ae2 100644
--- a/hw/xtensa_pic.c
+++ b/hw/xtensa_pic.c
@@ -27,6 +27,8 @@
 
 #include "hw.h"
 #include "pc.h"
+#include "qemu-log.h"
+#include "qemu-timer.h"
 
 /* Stub functions for hardware that doesn't exist.  */
 void pic_info(Monitor *mon)
@@ -36,3 +38,97 @@ void pic_info(Monitor *mon)
 void irq_info(Monitor *mon)
 {
 }
+
+void xtensa_advance_ccount(CPUState *env, uint32_t d)
+{
+    uint32_t old_ccount = env->sregs[CCOUNT];
+
+    env->sregs[CCOUNT] += d;
+
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) {
+        int i;
+        for (i = 0; i < env->config->nccompare; ++i) {
+            if (env->sregs[CCOMPARE + i] - old_ccount <= d) {
+                xtensa_timer_irq(env, i, 1);
+            }
+        }
+    }
+}
+
+void check_interrupts(CPUState *env)
+{
+    int minlevel = xtensa_get_cintlevel(env);
+    uint32_t int_set_enabled = env->sregs[INTSET] & env->sregs[INTENABLE];
+    int level;
+
+    /* If the CPU is halted advance CCOUNT according to the vm_clock time
+     * elapsed since the moment when it was advanced last time.
+     */
+    if (env->halted) {
+        int64_t now = qemu_get_clock_ns(vm_clock);
+
+        xtensa_advance_ccount(env,
+                muldiv64(now - env->halt_clock,
+                    env->config->clock_freq_khz, 1000000));
+        env->halt_clock = now;
+    }
+    for (level = env->config->nlevel; level > minlevel; --level) {
+        if (env->config->level_mask[level] & int_set_enabled) {
+            env->pending_irq_level = level;
+            cpu_interrupt(env, CPU_INTERRUPT_HARD);
+            qemu_log_mask(CPU_LOG_INT,
+                    "%s level = %d, cintlevel = %d, "
+                    "pc = %08x, a0 = %08x, ps = %08x, "
+                    "intset = %08x, intenable = %08x, "
+                    "ccount = %08x\n",
+                    __func__, level, xtensa_get_cintlevel(env),
+                    env->pc, env->regs[0], env->sregs[PS],
+                    env->sregs[INTSET], env->sregs[INTENABLE],
+                    env->sregs[CCOUNT]);
+            return;
+        }
+    }
+    env->pending_irq_level = 0;
+    cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+}
+
+static void xtensa_set_irq(void *opaque, int irq, int active)
+{
+    CPUState *env = opaque;
+
+    if (irq >= env->config->ninterrupt) {
+        qemu_log("%s: bad IRQ %d\n", __func__, irq);
+    } else {
+        uint32_t irq_bit = 1 << irq;
+
+        if (active) {
+            env->sregs[INTSET] |= irq_bit;
+        } else if (env->config->interrupt[irq].inttype == INTTYPE_LEVEL) {
+            env->sregs[INTSET] &= ~irq_bit;
+        }
+
+        check_interrupts(env);
+    }
+}
+
+void xtensa_timer_irq(CPUState *env, uint32_t id, uint32_t active)
+{
+    qemu_set_irq(env->irq_inputs[env->config->timerint[id]], active);
+}
+
+static void xtensa_ccompare_cb(void *opaque)
+{
+    CPUState *env = opaque;
+    xtensa_advance_ccount(env, env->wake_ccount - env->sregs[CCOUNT]);
+}
+
+void xtensa_irq_init(CPUState *env)
+{
+    env->irq_inputs = (void **)qemu_allocate_irqs(
+            xtensa_set_irq, env, env->config->ninterrupt);
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT) &&
+            env->config->nccompare > 0) {
+        env->ccompare_timer =
+            qemu_new_timer_ns(vm_clock, &xtensa_ccompare_cb, env);
+    }
+}
diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index 1283fd9..474466c 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -116,10 +116,16 @@ enum {
     WINDOW_START = 73,
     EPC1 = 177,
     DEPC = 192,
+    EPS2 = 194,
     EXCSAVE1 = 209,
+    INTSET = 226,
+    INTCLEAR = 227,
+    INTENABLE = 228,
     PS = 230,
     EXCCAUSE = 232,
+    CCOUNT = 234,
     EXCVADDR = 238,
+    CCOMPARE = 240,
 };
 
 #define PS_INTLEVEL 0xf
@@ -141,6 +147,10 @@ enum {
 #define PS_WOE 0x40000
 
 #define MAX_NAREG 64
+#define MAX_NINTERRUPT 32
+#define MAX_NLEVEL 6
+#define MAX_NNMI 1
+#define MAX_NCCOMPARE 3
 
 enum {
     /* Static vectors */
@@ -190,6 +200,17 @@ enum {
     COPROCESSOR0_DISABLED = 32,
 };
 
+typedef enum {
+    INTTYPE_LEVEL,
+    INTTYPE_EDGE,
+    INTTYPE_NMI,
+    INTTYPE_SOFTWARE,
+    INTTYPE_TIMER,
+    INTTYPE_DEBUG,
+    INTTYPE_WRITE_ERR,
+    INTTYPE_MAX
+} interrupt_type;
+
 typedef struct XtensaConfig {
     const char *name;
     uint64_t options;
@@ -197,6 +218,18 @@ typedef struct XtensaConfig {
     int excm_level;
     int ndepc;
     uint32_t exception_vector[EXC_MAX];
+    unsigned ninterrupt;
+    unsigned nlevel;
+    uint32_t interrupt_vector[MAX_NLEVEL + MAX_NNMI + 1];
+    uint32_t level_mask[MAX_NLEVEL + MAX_NNMI + 1];
+    uint32_t inttype_mask[INTTYPE_MAX];
+    struct {
+        uint32_t level;
+        interrupt_type inttype;
+    } interrupt[MAX_NINTERRUPT];
+    unsigned nccompare;
+    uint32_t timerint[MAX_NCCOMPARE];
+    uint32_t clock_freq_khz;
 } XtensaConfig;
 
 typedef struct CPUXtensaState {
@@ -207,6 +240,12 @@ typedef struct CPUXtensaState {
     uint32_t uregs[256];
     uint32_t phys_regs[MAX_NAREG];
 
+    int pending_irq_level; /* level of last raised IRQ */
+    void **irq_inputs;
+    QEMUTimer *ccompare_timer;
+    uint32_t wake_ccount;
+    int64_t halt_clock;
+
     int exception_taken;
 
     CPU_COMMON
@@ -222,6 +261,10 @@ CPUXtensaState *cpu_xtensa_init(const char *cpu_model);
 void xtensa_translate_init(void);
 int cpu_xtensa_exec(CPUXtensaState *s);
 void do_interrupt(CPUXtensaState *s);
+void check_interrupts(CPUXtensaState *s);
+void xtensa_irq_init(CPUState *env);
+void xtensa_advance_ccount(CPUState *env, uint32_t d);
+void xtensa_timer_irq(CPUState *env, uint32_t id, uint32_t active);
 int cpu_xtensa_signal_handler(int host_signum, void *pinfo, void *puc);
 void xtensa_cpu_list(FILE *f, fprintf_function cpu_fprintf);
 void xtensa_sync_window_from_phys(CPUState *env);
@@ -298,7 +341,7 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
 
 static inline int cpu_has_work(CPUState *env)
 {
-    return 1;
+    return env->pending_irq_level;
 }
 
 static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c
index bcd6c77..c24a38a 100644
--- a/target-xtensa/helper.c
+++ b/target-xtensa/helper.c
@@ -39,7 +39,10 @@ void cpu_reset(CPUXtensaState *env)
     env->exception_taken = 0;
     env->pc = env->config->exception_vector[EXC_RESET];
     env->sregs[LITBASE] &= ~1;
-    env->sregs[PS] = 0x1f;
+    env->sregs[PS] = xtensa_option_enabled(env->config,
+            XTENSA_OPTION_INTERRUPT) ? 0x1f : 0x10;
+
+    env->pending_irq_level = 0;
 }
 
 static const XtensaConfig core_config[] = {
@@ -63,6 +66,31 @@ static const XtensaConfig core_config[] = {
             [EXC_USER] = 0x5fff863c,
             [EXC_DOUBLE] = 0x5fff865c,
         },
+        .ninterrupt = 13,
+        .nlevel = 6,
+        .interrupt_vector = {
+            0,
+            0,
+            0x5fff857c,
+            0x5fff859c,
+            0x5fff85bc,
+            0x5fff85dc,
+            0x5fff85fc,
+        },
+        .level_mask = {
+            [4] = 1,
+        },
+        .interrupt = {
+            [0] = {
+                .level = 4,
+                .inttype = INTTYPE_TIMER,
+            },
+        },
+        .nccompare = 1,
+        .timerint = {
+            [0] = 0,
+        },
+        .clock_freq_khz = 912000,
     },
 };
 
@@ -92,6 +120,7 @@ CPUXtensaState *cpu_xtensa_init(const char *cpu_model)
         xtensa_translate_init();
     }
 
+    xtensa_irq_init(env);
     qemu_init_vcpu(env);
     return env;
 }
@@ -111,8 +140,63 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
     return addr;
 }
 
+/*!
+ * Handle penging IRQ.
+ * For the high priority interrupt jump to the corresponding interrupt vector.
+ * For the level-1 interrupt convert it to either user, kernel or double
+ * exception with the 'level-1 interrupt' exception cause.
+ */
+static void handle_interrupt(CPUState *env)
+{
+    int level = env->pending_irq_level;
+
+    if (level > xtensa_get_cintlevel(env) &&
+            level <= env->config->nlevel &&
+            (env->config->level_mask[level] &
+             env->sregs[INTSET] &
+             env->sregs[INTENABLE])) {
+        if (level > 1) {
+            env->sregs[EPC1 + level - 1] = env->pc;
+            env->sregs[EPS2 + level - 2] = env->sregs[PS];
+            env->sregs[PS] =
+                (env->sregs[PS] & ~PS_INTLEVEL) | level | PS_EXCM;
+            env->pc = env->config->interrupt_vector[level];
+        } else {
+            env->sregs[EXCCAUSE] = LEVEL1_INTERRUPT_CAUSE;
+
+            if (env->sregs[PS] & PS_EXCM) {
+                if (env->config->ndepc) {
+                    env->sregs[DEPC] = env->pc;
+                } else {
+                    env->sregs[EPC1] = env->pc;
+                }
+                env->exception_index = EXC_DOUBLE;
+            } else {
+                env->sregs[EPC1] = env->pc;
+                env->exception_index =
+                    (env->sregs[PS] & PS_UM) ? EXC_USER : EXC_KERNEL;
+            }
+            env->sregs[PS] |= PS_EXCM;
+        }
+        env->exception_taken = 1;
+    }
+}
+
 void do_interrupt(CPUState *env)
 {
+    if (env->exception_index == EXC_IRQ) {
+        qemu_log_mask(CPU_LOG_INT,
+                "%s(EXC_IRQ) level = %d, cintlevel = %d, "
+                "pc = %08x, a0 = %08x, ps = %08x, "
+                "intset = %08x, intenable = %08x, "
+                "ccount = %08x\n",
+                __func__, env->pending_irq_level, xtensa_get_cintlevel(env),
+                env->pc, env->regs[0], env->sregs[PS],
+                env->sregs[INTSET], env->sregs[INTENABLE],
+                env->sregs[CCOUNT]);
+        handle_interrupt(env);
+    }
+
     switch (env->exception_index) {
     case EXC_WINDOW_OVERFLOW4:
     case EXC_WINDOW_UNDERFLOW4:
@@ -123,6 +207,10 @@ void do_interrupt(CPUState *env)
     case EXC_KERNEL:
     case EXC_USER:
     case EXC_DOUBLE:
+        qemu_log_mask(CPU_LOG_INT, "%s(%d) "
+                "pc = %08x, a0 = %08x, ps = %08x, ccount = %08x\n",
+                __func__, env->exception_index,
+                env->pc, env->regs[0], env->sregs[PS], env->sregs[CCOUNT]);
         if (env->config->exception_vector[env->exception_index]) {
             env->pc = env->config->exception_vector[env->exception_index];
             env->exception_taken = 1;
@@ -132,5 +220,13 @@ void do_interrupt(CPUState *env)
         }
         break;
 
+    case EXC_IRQ:
+        break;
+
+    default:
+        qemu_log("%s(pc = %08x) unknown exception_index: %d\n",
+                __func__, env->pc, env->exception_index);
+        break;
     }
+    check_interrupts(env);
 }
diff --git a/target-xtensa/helpers.h b/target-xtensa/helpers.h
index 6e02d26..28689c3 100644
--- a/target-xtensa/helpers.h
+++ b/target-xtensa/helpers.h
@@ -17,4 +17,9 @@ DEF_HELPER_1(wsr_lend, void, i32)
 DEF_HELPER_1(simcall, void, env)
 DEF_HELPER_0(dump_state, void)
 
+DEF_HELPER_2(waiti, void, i32, i32)
+DEF_HELPER_2(timer_irq, void, i32, i32)
+DEF_HELPER_1(advance_ccount, void, i32)
+DEF_HELPER_1(check_interrupts, void, env)
+
 #include "def-helper.h"
diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c
index d37f70d..0047fa3 100644
--- a/target-xtensa/op_helper.c
+++ b/target-xtensa/op_helper.c
@@ -338,3 +338,49 @@ void HELPER(dump_state)(void)
 {
     cpu_dump_state(env, stderr, fprintf, 0);
 }
+
+void HELPER(waiti)(uint32_t pc, uint32_t intlevel)
+{
+    env->pc = pc;
+    env->sregs[PS] = (env->sregs[PS] & ~PS_INTLEVEL) |
+        (intlevel << PS_INTLEVEL_SHIFT);
+    check_interrupts(env);
+    if (env->pending_irq_level) {
+        cpu_loop_exit(env);
+        return;
+    }
+
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) {
+        int i;
+        uint32_t wake_ccount = env->sregs[CCOUNT] - 1;
+
+        for (i = 0; i < env->config->nccompare; ++i) {
+            if (env->sregs[CCOMPARE + i] - env->sregs[CCOUNT] <
+                    wake_ccount - env->sregs[CCOUNT]) {
+                wake_ccount = env->sregs[CCOMPARE + i];
+            }
+        }
+        env->wake_ccount = wake_ccount;
+        qemu_mod_timer(env->ccompare_timer, qemu_get_clock_ns(vm_clock) +
+                muldiv64(wake_ccount - env->sregs[CCOUNT],
+                    1000000, env->config->clock_freq_khz));
+    }
+    env->halt_clock = qemu_get_clock_ns(vm_clock);
+    env->halted = 1;
+    HELPER(exception)(EXCP_HLT);
+}
+
+void HELPER(timer_irq)(uint32_t id, uint32_t active)
+{
+    xtensa_timer_irq(env, id, active);
+}
+
+void HELPER(advance_ccount)(uint32_t d)
+{
+    xtensa_advance_ccount(env, d);
+}
+
+void HELPER(check_interrupts)(CPUState *env)
+{
+    check_interrupts(env);
+}
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index 1598e27..d75e780 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -58,6 +58,8 @@ typedef struct DisasContext {
     bool sar_m32_5bit;
     bool sar_m32_allocated;
     TCGv_i32 sar_m32;
+
+    uint32_t ccount_delta;
 } DisasContext;
 
 static TCGv_ptr cpu_env;
@@ -78,11 +80,36 @@ static const char * const sregnames[256] = {
     [WINDOW_BASE] = "WINDOW_BASE",
     [WINDOW_START] = "WINDOW_START",
     [EPC1] = "EPC1",
+    [EPC1 + 1] = "EPC2",
+    [EPC1 + 2] = "EPC3",
+    [EPC1 + 3] = "EPC4",
+    [EPC1 + 4] = "EPC5",
+    [EPC1 + 5] = "EPC6",
+    [EPC1 + 6] = "EPC7",
     [DEPC] = "DEPC",
+    [EPS2] = "EPS2",
+    [EPS2 + 1] = "EPS3",
+    [EPS2 + 2] = "EPS4",
+    [EPS2 + 3] = "EPS5",
+    [EPS2 + 4] = "EPS6",
+    [EPS2 + 5] = "EPS7",
     [EXCSAVE1] = "EXCSAVE1",
+    [EXCSAVE1 + 1] = "EXCSAVE2",
+    [EXCSAVE1 + 2] = "EXCSAVE3",
+    [EXCSAVE1 + 3] = "EXCSAVE4",
+    [EXCSAVE1 + 4] = "EXCSAVE5",
+    [EXCSAVE1 + 5] = "EXCSAVE6",
+    [EXCSAVE1 + 6] = "EXCSAVE7",
+    [INTSET] = "INTSET",
+    [INTCLEAR] = "INTCLEAR",
+    [INTENABLE] = "INTENABLE",
     [PS] = "PS",
     [EXCCAUSE] = "EXCCAUSE",
+    [CCOUNT] = "CCOUNT",
     [EXCVADDR] = "EXCVADDR",
+    [CCOMPARE] = "CCOMPARE0",
+    [CCOMPARE + 1] = "CCOMPARE1",
+    [CCOMPARE + 2] = "CCOMPARE2",
 };
 
 static const char * const uregnames[256] = {
@@ -188,9 +215,20 @@ static void gen_left_shift_sar(DisasContext *dc, TCGv_i32 sa)
     tcg_temp_free(tmp);
 }
 
-static void gen_exception(int excp)
+static void gen_advance_ccount(DisasContext *dc)
+{
+    if (dc->ccount_delta > 0) {
+        TCGv_i32 tmp = tcg_const_i32(dc->ccount_delta);
+        dc->ccount_delta = 0;
+        gen_helper_advance_ccount(tmp);
+        tcg_temp_free(tmp);
+    }
+}
+
+static void gen_exception(DisasContext *dc, int excp)
 {
     TCGv_i32 tmp = tcg_const_i32(excp);
+    gen_advance_ccount(dc);
     gen_helper_exception(tmp);
     tcg_temp_free(tmp);
 }
@@ -199,6 +237,7 @@ static void gen_exception_cause(DisasContext *dc, uint32_t cause)
 {
     TCGv_i32 tpc = tcg_const_i32(dc->pc);
     TCGv_i32 tcause = tcg_const_i32(cause);
+    gen_advance_ccount(dc);
     gen_helper_exception_cause(tpc, tcause);
     tcg_temp_free(tpc);
     tcg_temp_free(tcause);
@@ -209,6 +248,7 @@ static void gen_exception_cause_vaddr(DisasContext *dc, uint32_t cause,
 {
     TCGv_i32 tpc = tcg_const_i32(dc->pc);
     TCGv_i32 tcause = tcg_const_i32(cause);
+    gen_advance_ccount(dc);
     gen_helper_exception_cause_vaddr(tpc, tcause, vaddr);
     tcg_temp_free(tpc);
     tcg_temp_free(tcause);
@@ -225,8 +265,9 @@ static void gen_jump_slot(DisasContext *dc, TCGv dest, int slot)
 {
     tcg_gen_mov_i32(cpu_pc, dest);
     if (dc->singlestep_enabled) {
-        gen_exception(EXCP_DEBUG);
+        gen_exception(dc, EXCP_DEBUG);
     } else {
+        gen_advance_ccount(dc);
         if (slot >= 0) {
             tcg_gen_goto_tb(slot);
             tcg_gen_exit_tb((tcg_target_long)dc->tb + slot);
@@ -323,10 +364,17 @@ static void gen_brcondi(DisasContext *dc, TCGCond cond,
     tcg_temp_free(tmp);
 }
 
+static void gen_rsr_ccount(DisasContext *dc, TCGv_i32 d, uint32_t sr)
+{
+    gen_advance_ccount(dc);
+    tcg_gen_mov_i32(d, cpu_SR[sr]);
+}
+
 static void gen_rsr(DisasContext *dc, TCGv_i32 d, uint32_t sr)
 {
     static void (* const rsr_handler[256])(DisasContext *dc,
             TCGv_i32 d, uint32_t sr) = {
+        [CCOUNT] = gen_rsr_ccount,
     };
 
     if (sregnames[sr]) {
@@ -372,6 +420,34 @@ static void gen_wsr_windowbase(DisasContext *dc, uint32_t sr, TCGv_i32 v)
     gen_helper_wsr_windowbase(v);
 }
 
+static void gen_wsr_intset(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+    tcg_gen_andi_i32(cpu_SR[sr], v,
+            dc->config->inttype_mask[INTTYPE_SOFTWARE]);
+    gen_helper_check_interrupts(cpu_env);
+    gen_jumpi_check_loop_end(dc, 0);
+}
+
+static void gen_wsr_intclear(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+    TCGv_i32 tmp = tcg_temp_new_i32();
+
+    tcg_gen_andi_i32(tmp, v,
+            dc->config->inttype_mask[INTTYPE_EDGE] |
+            dc->config->inttype_mask[INTTYPE_NMI] |
+            dc->config->inttype_mask[INTTYPE_SOFTWARE]);
+    tcg_gen_andc_i32(cpu_SR[INTSET], cpu_SR[INTSET], tmp);
+    tcg_temp_free(tmp);
+    gen_helper_check_interrupts(cpu_env);
+}
+
+static void gen_wsr_intenable(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+    tcg_gen_mov_i32(cpu_SR[sr], v);
+    gen_helper_check_interrupts(cpu_env);
+    gen_jumpi_check_loop_end(dc, 0);
+}
+
 static void gen_wsr_ps(DisasContext *dc, uint32_t sr, TCGv_i32 v)
 {
     uint32_t mask = PS_WOE | PS_CALLINC | PS_OWB |
@@ -381,10 +457,23 @@ static void gen_wsr_ps(DisasContext *dc, uint32_t sr, TCGv_i32 v)
         mask |= PS_RING;
     }
     tcg_gen_andi_i32(cpu_SR[sr], v, mask);
-    /* This can change mmu index, so exit tb */
+    gen_helper_check_interrupts(cpu_env);
+    /* This can change mmu index and tb->flags, so exit tb */
     gen_jumpi_check_loop_end(dc, -1);
 }
 
+static void gen_wsr_ccompare(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+    uint32_t id = sr - CCOMPARE;
+    if (id < dc->config->nccompare) {
+        uint32_t int_bit = 1 << dc->config->timerint[id];
+        gen_advance_ccount(dc);
+        tcg_gen_mov_i32(cpu_SR[sr], v);
+        tcg_gen_andi_i32(cpu_SR[INTSET], cpu_SR[INTSET], ~int_bit);
+        gen_helper_check_interrupts(cpu_env);
+    }
+}
+
 static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s)
 {
     static void (* const wsr_handler[256])(DisasContext *dc,
@@ -394,7 +483,13 @@ static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s)
         [SAR] = gen_wsr_sar,
         [LITBASE] = gen_wsr_litbase,
         [WINDOW_BASE] = gen_wsr_windowbase,
+        [INTSET] = gen_wsr_intset,
+        [INTCLEAR] = gen_wsr_intclear,
+        [INTENABLE] = gen_wsr_intenable,
         [PS] = gen_wsr_ps,
+        [CCOMPARE] = gen_wsr_ccompare,
+        [CCOMPARE + 1] = gen_wsr_ccompare,
+        [CCOMPARE + 2] = gen_wsr_ccompare,
     };
 
     if (sregnames[sr]) {
@@ -425,6 +520,16 @@ static void gen_load_store_alignment(DisasContext *dc, int shift,
     }
 }
 
+static void gen_waiti(DisasContext *dc, uint32_t imm4)
+{
+    TCGv_i32 pc = tcg_const_i32(dc->next_pc);
+    TCGv_i32 intlevel = tcg_const_i32(imm4);
+    gen_advance_ccount(dc);
+    gen_helper_waiti(pc, intlevel);
+    tcg_temp_free(pc);
+    tcg_temp_free(intlevel);
+}
+
 static void disas_xtensa_insn(DisasContext *dc)
 {
 #define HAS_OPTION(opt) do { \
@@ -561,6 +666,7 @@ static void disas_xtensa_insn(DisasContext *dc)
                             HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
                             {
                                 TCGv_i32 tmp = tcg_const_i32(dc->pc);
+                                gen_advance_ccount(dc);
                                 gen_helper_retw(tmp, tmp);
                                 gen_jump(dc, tmp);
                                 tcg_temp_free(tmp);
@@ -606,6 +712,7 @@ static void disas_xtensa_insn(DisasContext *dc)
                     HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
                     {
                         TCGv_i32 pc = tcg_const_i32(dc->pc);
+                        gen_advance_ccount(dc);
                         gen_helper_movsp(pc);
                         tcg_gen_mov_i32(cpu_R[RRR_T], cpu_R[RRR_S]);
                         tcg_temp_free(pc);
@@ -653,6 +760,7 @@ static void disas_xtensa_insn(DisasContext *dc)
                         case 0: /*RFEx*/
                             gen_check_privilege(dc);
                             tcg_gen_andi_i32(cpu_SR[PS], cpu_SR[PS], ~PS_EXCM);
+                            gen_helper_check_interrupts(cpu_env);
                             gen_jump(dc, cpu_SR[EPC1]);
                             break;
 
@@ -686,6 +794,7 @@ static void disas_xtensa_insn(DisasContext *dc)
                                 }
 
                                 gen_helper_restore_owb();
+                                gen_helper_check_interrupts(cpu_env);
                                 gen_jump(dc, cpu_SR[EPC1]);
 
                                 tcg_temp_free(tmp);
@@ -700,7 +809,16 @@ static void disas_xtensa_insn(DisasContext *dc)
 
                     case 1: /*RFIx*/
                         HAS_OPTION(XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT);
-                        TBD();
+                        if (RRR_S >= 2 && RRR_S <= dc->config->nlevel) {
+                            gen_check_privilege(dc);
+                            tcg_gen_mov_i32(cpu_SR[PS],
+                                    cpu_SR[EPS2 + RRR_S - 2]);
+                            gen_helper_check_interrupts(cpu_env);
+                            gen_jump(dc, cpu_SR[EPC1 + RRR_S - 1]);
+                        } else {
+                            qemu_log("RFI %d is illegal\n", RRR_S);
+                            gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE);
+                        }
                         break;
 
                     case 2: /*RFME*/
@@ -746,14 +864,16 @@ static void disas_xtensa_insn(DisasContext *dc)
                     HAS_OPTION(XTENSA_OPTION_INTERRUPT);
                     gen_check_privilege(dc);
                     tcg_gen_mov_i32(cpu_R[RRR_T], cpu_SR[PS]);
+                    tcg_gen_andi_i32(cpu_SR[PS], cpu_SR[PS], ~PS_INTLEVEL);
                     tcg_gen_ori_i32(cpu_SR[PS], cpu_SR[PS], RRR_S);
-                    tcg_gen_andi_i32(cpu_SR[PS], cpu_SR[PS],
-                            RRR_S | ~PS_INTLEVEL);
+                    gen_helper_check_interrupts(cpu_env);
+                    gen_jumpi_check_loop_end(dc, 0);
                     break;
 
                 case 7: /*WAITIx*/
                     HAS_OPTION(XTENSA_OPTION_INTERRUPT);
-                    TBD();
+                    gen_check_privilege(dc);
+                    gen_waiti(dc, RRR_S);
                     break;
 
                 case 8: /*ANY4p*/
@@ -1637,6 +1757,7 @@ static void disas_xtensa_insn(DisasContext *dc)
                     TCGv_i32 pc = tcg_const_i32(dc->pc);
                     TCGv_i32 s = tcg_const_i32(BRI12_S);
                     TCGv_i32 imm = tcg_const_i32(BRI12_IMM12);
+                    gen_advance_ccount(dc);
                     gen_helper_entry(pc, s, imm);
                     tcg_temp_free(imm);
                     tcg_temp_free(s);
@@ -1823,6 +1944,7 @@ static void disas_xtensa_insn(DisasContext *dc)
                 HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
                 {
                     TCGv_i32 tmp = tcg_const_i32(dc->pc);
+                    gen_advance_ccount(dc);
                     gen_helper_retw(tmp, tmp);
                     gen_jump(dc, tmp);
                     tcg_temp_free(tmp);
@@ -1876,7 +1998,7 @@ static void check_breakpoint(CPUState *env, DisasContext *dc)
         QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
             if (bp->pc == dc->pc) {
                 tcg_gen_movi_i32(cpu_pc, dc->pc);
-                gen_exception(EXCP_DEBUG);
+                gen_exception(dc, EXCP_DEBUG);
                 dc->is_jmp = DISAS_UPDATE;
              }
         }
@@ -1908,6 +2030,7 @@ static void gen_intermediate_code_internal(
     dc.lbeg = env->sregs[LBEG];
     dc.lend = env->sregs[LEND];
     dc.is_jmp = DISAS_NEXT;
+    dc.ccount_delta = 0;
 
     init_litbase(&dc);
     init_sar_tracker(&dc);
@@ -1917,7 +2040,7 @@ static void gen_intermediate_code_internal(
     if (env->singlestep_enabled && env->exception_taken) {
         env->exception_taken = 0;
         tcg_gen_movi_i32(cpu_pc, dc.pc);
-        gen_exception(EXCP_DEBUG);
+        gen_exception(&dc, EXCP_DEBUG);
     }
 
     do {
@@ -1940,11 +2063,17 @@ static void gen_intermediate_code_internal(
             tcg_gen_debug_insn_start(dc.pc);
         }
 
+        ++dc.ccount_delta;
+
+        if (insn_count + 1 == max_insns && (tb->cflags & CF_LAST_IO)) {
+            gen_io_start();
+        }
+
         disas_xtensa_insn(&dc);
         ++insn_count;
         if (env->singlestep_enabled) {
             tcg_gen_movi_i32(cpu_pc, dc.pc);
-            gen_exception(EXCP_DEBUG);
+            gen_exception(&dc, EXCP_DEBUG);
             break;
         }
     } while (dc.is_jmp == DISAS_NEXT &&
@@ -1955,6 +2084,10 @@ static void gen_intermediate_code_internal(
     reset_litbase(&dc);
     reset_sar_tracker(&dc);
 
+    if (tb->cflags & CF_LAST_IO) {
+        gen_io_end();
+    }
+
     if (dc.is_jmp == DISAS_NEXT) {
         gen_jumpi(&dc, dc.pc, 0);
     }
commit 1ddeaa5d4277af76679d02bc59b08657c357aee6
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Tue Sep 6 03:55:47 2011 +0400

    target-xtensa: implement SIMCALL
    
    Tensilica iss provides support for applications running in freestanding
    environment through SIMCALL command. It is used by Tensilica libc to
    access argc/argv, for file I/O, etc.
    
    Note that simcalls that accept buffer addresses expect virtual addresses.
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/Makefile.target b/Makefile.target
index 7833dcc..ca8eaf2 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -370,6 +370,7 @@ obj-alpha-y += vga.o cirrus_vga.o
 
 obj-xtensa-y += xtensa_pic.o
 obj-xtensa-y += xtensa_sample.o
+obj-xtensa-y += xtensa-semi.o
 
 main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
 
diff --git a/qemu-options.hx b/qemu-options.hx
index 552d41c..dfbabd0 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2396,11 +2396,11 @@ STEXI
 Set OpenBIOS nvram @var{variable} to given @var{value} (PPC, SPARC only).
 ETEXI
 DEF("semihosting", 0, QEMU_OPTION_semihosting,
-    "-semihosting    semihosting mode\n", QEMU_ARCH_ARM | QEMU_ARCH_M68K)
+    "-semihosting    semihosting mode\n", QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA)
 STEXI
 @item -semihosting
 @findex -semihosting
-Semihosting mode (ARM, M68K only).
+Semihosting mode (ARM, M68K, Xtensa only).
 ETEXI
 DEF("old-param", 0, QEMU_OPTION_old_param,
     "-old-param      old param mode\n", QEMU_ARCH_ARM)
diff --git a/target-xtensa/helpers.h b/target-xtensa/helpers.h
index b318c5a..6e02d26 100644
--- a/target-xtensa/helpers.h
+++ b/target-xtensa/helpers.h
@@ -14,6 +14,7 @@ DEF_HELPER_0(restore_owb, void)
 DEF_HELPER_1(movsp, void, i32)
 DEF_HELPER_1(wsr_lbeg, void, i32)
 DEF_HELPER_1(wsr_lend, void, i32)
+DEF_HELPER_1(simcall, void, env)
 DEF_HELPER_0(dump_state, void)
 
 #include "def-helper.h"
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index dd84dfc..1598e27 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -35,6 +35,7 @@
 #include "disas.h"
 #include "tcg-op.h"
 #include "qemu-log.h"
+#include "sysemu.h"
 
 #include "helpers.h"
 #define GEN_HELPER 1
@@ -726,7 +727,13 @@ static void disas_xtensa_insn(DisasContext *dc)
                         break;
 
                     case 1: /*SIMCALL*/
-                        TBD();
+                        if (semihosting_enabled) {
+                            gen_check_privilege(dc);
+                            gen_helper_simcall(cpu_env);
+                        } else {
+                            qemu_log("SIMCALL but semihosting is disabled\n");
+                            gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE);
+                        }
                         break;
 
                     default:
diff --git a/xtensa-semi.c b/xtensa-semi.c
new file mode 100644
index 0000000..ba0e828
--- /dev/null
+++ b/xtensa-semi.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stddef.h>
+#include "cpu.h"
+#include "dyngen-exec.h"
+#include "helpers.h"
+#include "qemu-log.h"
+
+enum {
+    TARGET_SYS_exit = 1,
+    TARGET_SYS_read = 3,
+    TARGET_SYS_write = 4,
+    TARGET_SYS_open = 5,
+    TARGET_SYS_close = 6,
+    TARGET_SYS_lseek = 19,
+    TARGET_SYS_select_one = 29,
+
+    TARGET_SYS_argc = 1000,
+    TARGET_SYS_argv_sz = 1001,
+    TARGET_SYS_argv = 1002,
+    TARGET_SYS_memset = 1004,
+};
+
+enum {
+    SELECT_ONE_READ   = 1,
+    SELECT_ONE_WRITE  = 2,
+    SELECT_ONE_EXCEPT = 3,
+};
+
+void HELPER(simcall)(CPUState *env)
+{
+    uint32_t *regs = env->regs;
+
+    switch (regs[2]) {
+    case TARGET_SYS_exit:
+        qemu_log("exit(%d) simcall\n", regs[3]);
+        exit(regs[3]);
+        break;
+
+    case TARGET_SYS_read:
+    case TARGET_SYS_write:
+        {
+            bool is_write = regs[2] == TARGET_SYS_write;
+            uint32_t fd = regs[3];
+            uint32_t vaddr = regs[4];
+            uint32_t len = regs[5];
+
+            while (len > 0) {
+                target_phys_addr_t paddr =
+                    cpu_get_phys_page_debug(env, vaddr);
+                uint32_t page_left =
+                    TARGET_PAGE_SIZE - (vaddr & (TARGET_PAGE_SIZE - 1));
+                uint32_t io_sz = page_left < len ? page_left : len;
+                target_phys_addr_t sz = io_sz;
+                void *buf = cpu_physical_memory_map(paddr, &sz, is_write);
+
+                if (buf) {
+                    vaddr += io_sz;
+                    len -= io_sz;
+                    regs[2] = is_write ?
+                        write(fd, buf, io_sz) :
+                        read(fd, buf, io_sz);
+                    regs[3] = errno;
+                    cpu_physical_memory_unmap(buf, sz, is_write, sz);
+                    if (regs[2] == -1) {
+                        break;
+                    }
+                } else {
+                    regs[2] = -1;
+                    regs[3] = EINVAL;
+                    break;
+                }
+            }
+        }
+        break;
+
+    case TARGET_SYS_open:
+        {
+            char name[1024];
+            int rc;
+            int i;
+
+            for (i = 0; i < ARRAY_SIZE(name); ++i) {
+                rc = cpu_memory_rw_debug(
+                        env, regs[3] + i, (uint8_t *)name + i, 1, 0);
+                if (rc != 0 || name[i] == 0) {
+                    break;
+                }
+            }
+
+            if (rc == 0 && i < ARRAY_SIZE(name)) {
+                regs[2] = open(name, regs[4], regs[5]);
+                regs[3] = errno;
+            } else {
+                regs[2] = -1;
+                regs[3] = EINVAL;
+            }
+        }
+        break;
+
+    case TARGET_SYS_close:
+        if (regs[3] < 3) {
+            regs[2] = regs[3] = 0;
+        } else {
+            regs[2] = close(regs[3]);
+            regs[3] = errno;
+        }
+        break;
+
+    case TARGET_SYS_lseek:
+        regs[2] = lseek(regs[3], (off_t)(int32_t)regs[4], regs[5]);
+        regs[3] = errno;
+        break;
+
+    case TARGET_SYS_select_one:
+        {
+            uint32_t fd = regs[3];
+            uint32_t rq = regs[4];
+            uint32_t target_tv = regs[5];
+            uint32_t target_tvv[2];
+
+            struct timeval tv = {0};
+            fd_set fdset;
+
+            FD_ZERO(&fdset);
+            FD_SET(fd, &fdset);
+
+            if (target_tv) {
+                cpu_memory_rw_debug(env, target_tv,
+                        (uint8_t *)target_tvv, sizeof(target_tvv), 0);
+                tv.tv_sec = (int32_t)tswap32(target_tvv[0]);
+                tv.tv_usec = (int32_t)tswap32(target_tvv[1]);
+            }
+            regs[2] = select(fd + 1,
+                    rq == SELECT_ONE_READ   ? &fdset : NULL,
+                    rq == SELECT_ONE_WRITE  ? &fdset : NULL,
+                    rq == SELECT_ONE_EXCEPT ? &fdset : NULL,
+                    target_tv ? &tv : NULL);
+            regs[3] = errno;
+        }
+        break;
+
+    case TARGET_SYS_argc:
+        regs[2] = 1;
+        regs[3] = 0;
+        break;
+
+    case TARGET_SYS_argv_sz:
+        regs[2] = 128;
+        regs[3] = 0;
+        break;
+
+    case TARGET_SYS_argv:
+        {
+            struct Argv {
+                uint32_t argptr[2];
+                char text[120];
+            } argv = {
+                {0, 0},
+                "test"
+            };
+
+            argv.argptr[0] = tswap32(regs[3] + offsetof(struct Argv, text));
+            cpu_memory_rw_debug(
+                    env, regs[3], (uint8_t *)&argv, sizeof(argv), 1);
+        }
+        break;
+
+    case TARGET_SYS_memset:
+        {
+            uint32_t base = regs[3];
+            uint32_t sz = regs[5];
+
+            while (sz) {
+                target_phys_addr_t len = sz;
+                void *buf = cpu_physical_memory_map(base, &len, 1);
+
+                if (buf && len) {
+                    memset(buf, regs[4], len);
+                    cpu_physical_memory_unmap(buf, len, 1, len);
+                } else {
+                    len = 1;
+                }
+                base += len;
+                sz -= len;
+            }
+            regs[2] = regs[3];
+            regs[3] = 0;
+        }
+        break;
+
+    default:
+        qemu_log("%s(%d): not implemented\n", __func__, regs[2]);
+        break;
+    }
+}
commit 5b4e481b041150fbc6eaef6205095077893a3781
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Tue Sep 6 03:55:46 2011 +0400

    target-xtensa: implement unaligned exception option
    
    See ISA, 4.4.4 for details.
    
    Correct (aligned as per ISA) address for unaligned access is generated
    in case this option is not enabled.
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c
index 074207f..bcd6c77 100644
--- a/target-xtensa/helper.c
+++ b/target-xtensa/helper.c
@@ -45,7 +45,9 @@ void cpu_reset(CPUXtensaState *env)
 static const XtensaConfig core_config[] = {
     {
         .name = "sample-xtensa-core",
-        .options = -1,
+        .options = -1 ^
+            (XTENSA_OPTION_BIT(XTENSA_OPTION_HW_ALIGNMENT) |
+             XTENSA_OPTION_BIT(XTENSA_OPTION_MMU)),
         .nareg = 64,
         .ndepc = 1,
         .excm_level = 16,
diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c
index 5e0f56f..d37f70d 100644
--- a/target-xtensa/op_helper.c
+++ b/target-xtensa/op_helper.c
@@ -30,6 +30,10 @@
 #include "helpers.h"
 #include "host-utils.h"
 
+static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
+        void *retaddr);
+
+#define ALIGNED_ONLY
 #define MMUSUFFIX _mmu
 
 #define SHIFT 0
@@ -44,6 +48,28 @@
 #define SHIFT 3
 #include "softmmu_template.h"
 
+static void do_restore_state(void *pc_ptr)
+{
+    TranslationBlock *tb;
+    uint32_t pc = (uint32_t)(intptr_t)pc_ptr;
+
+    tb = tb_find_pc(pc);
+    if (tb) {
+        cpu_restore_state(tb, env, pc);
+    }
+}
+
+static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
+        void *retaddr)
+{
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_UNALIGNED_EXCEPTION) &&
+            !xtensa_option_enabled(env->config, XTENSA_OPTION_HW_ALIGNMENT)) {
+        do_restore_state(retaddr);
+        HELPER(exception_cause_vaddr)(
+                env->pc, LOAD_STORE_ALIGNMENT_CAUSE, addr);
+    }
+}
+
 void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
 {
     tlb_set_page(cpu_single_env,
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index 07a737a..dd84dfc 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -203,6 +203,16 @@ static void gen_exception_cause(DisasContext *dc, uint32_t cause)
     tcg_temp_free(tcause);
 }
 
+static void gen_exception_cause_vaddr(DisasContext *dc, uint32_t cause,
+        TCGv_i32 vaddr)
+{
+    TCGv_i32 tpc = tcg_const_i32(dc->pc);
+    TCGv_i32 tcause = tcg_const_i32(cause);
+    gen_helper_exception_cause_vaddr(tpc, tcause, vaddr);
+    tcg_temp_free(tpc);
+    tcg_temp_free(tcause);
+}
+
 static void gen_check_privilege(DisasContext *dc)
 {
     if (dc->cring) {
@@ -397,6 +407,23 @@ static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s)
     }
 }
 
+static void gen_load_store_alignment(DisasContext *dc, int shift,
+        TCGv_i32 addr, bool no_hw_alignment)
+{
+    if (!option_enabled(dc, XTENSA_OPTION_UNALIGNED_EXCEPTION)) {
+        tcg_gen_andi_i32(addr, addr, ~0 << shift);
+    } else if (option_enabled(dc, XTENSA_OPTION_HW_ALIGNMENT) &&
+            no_hw_alignment) {
+        int label = gen_new_label();
+        TCGv_i32 tmp = tcg_temp_new_i32();
+        tcg_gen_andi_i32(tmp, addr, ~(~0 << shift));
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
+        gen_exception_cause_vaddr(dc, LOAD_STORE_ALIGNMENT_CAUSE, addr);
+        gen_set_label(label);
+        tcg_temp_free(tmp);
+    }
+}
+
 static void disas_xtensa_insn(DisasContext *dc)
 {
 #define HAS_OPTION(opt) do { \
@@ -1339,6 +1366,9 @@ static void disas_xtensa_insn(DisasContext *dc)
 #define gen_load_store(type, shift) do { \
             TCGv_i32 addr = tcg_temp_new_i32(); \
             tcg_gen_addi_i32(addr, cpu_R[RRI8_S], RRI8_IMM8 << shift); \
+            if (shift) { \
+                gen_load_store_alignment(dc, shift, addr, false); \
+            } \
             tcg_gen_qemu_##type(cpu_R[RRI8_T], addr, dc->cring); \
             tcg_temp_free(addr); \
         } while (0)
@@ -1468,6 +1498,7 @@ static void disas_xtensa_insn(DisasContext *dc)
         case 9: /*L16SI*/
             gen_load_store(ld16s, 1);
             break;
+#undef gen_load_store
 
         case 10: /*MOVI*/
             tcg_gen_movi_i32(cpu_R[RRI8_T],
@@ -1475,9 +1506,17 @@ static void disas_xtensa_insn(DisasContext *dc)
                     ((RRI8_S & 0x8) ? 0xfffff000 : 0));
             break;
 
+#define gen_load_store_no_hw_align(type) do { \
+            TCGv_i32 addr = tcg_temp_local_new_i32(); \
+            tcg_gen_addi_i32(addr, cpu_R[RRI8_S], RRI8_IMM8 << 2); \
+            gen_load_store_alignment(dc, 2, addr, true); \
+            tcg_gen_qemu_##type(cpu_R[RRI8_T], addr, dc->cring); \
+            tcg_temp_free(addr); \
+        } while (0)
+
         case 11: /*L32AIy*/
             HAS_OPTION(XTENSA_OPTION_MP_SYNCHRO);
-            gen_load_store(ld32u, 2); /*TODO acquire?*/
+            gen_load_store_no_hw_align(ld32u); /*TODO acquire?*/
             break;
 
         case 12: /*ADDI*/
@@ -1497,6 +1536,7 @@ static void disas_xtensa_insn(DisasContext *dc)
 
                 tcg_gen_mov_i32(tmp, cpu_R[RRI8_T]);
                 tcg_gen_addi_i32(addr, cpu_R[RRI8_S], RRI8_IMM8 << 2);
+                gen_load_store_alignment(dc, 2, addr, true);
                 tcg_gen_qemu_ld32u(cpu_R[RRI8_T], addr, dc->cring);
                 tcg_gen_brcond_i32(TCG_COND_NE, cpu_R[RRI8_T],
                         cpu_SR[SCOMPARE1], label);
@@ -1511,15 +1551,15 @@ static void disas_xtensa_insn(DisasContext *dc)
 
         case 15: /*S32RIy*/
             HAS_OPTION(XTENSA_OPTION_MP_SYNCHRO);
-            gen_load_store(st32, 2); /*TODO release?*/
+            gen_load_store_no_hw_align(st32); /*TODO release?*/
             break;
+#undef gen_load_store_no_hw_align
 
         default: /*reserved*/
             RESERVED();
             break;
         }
         break;
-#undef gen_load_store
 
     case 3: /*LSCIp*/
         HAS_OPTION(XTENSA_OPTION_COPROCESSOR);
@@ -1725,6 +1765,7 @@ static void disas_xtensa_insn(DisasContext *dc)
 #define gen_narrow_load_store(type) do { \
             TCGv_i32 addr = tcg_temp_new_i32(); \
             tcg_gen_addi_i32(addr, cpu_R[RRRN_S], RRRN_R << 2); \
+            gen_load_store_alignment(dc, 2, addr, false); \
             tcg_gen_qemu_##type(cpu_R[RRRN_T], addr, dc->cring); \
             tcg_temp_free(addr); \
         } while (0)
commit 6ad6dbf7916c59b6ae6dfe208dd64e0bf89dbf0a
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Tue Sep 6 03:55:45 2011 +0400

    target-xtensa: implement extended L32R
    
    See ISA, 4.3.3 for details.
    
    TB flag XTENSA_TBFLAG_LITBASE is used to track enable bit of LITBASE SR.
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index 97badf2..1283fd9 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -110,6 +110,7 @@ enum {
     LEND = 1,
     LCOUNT = 2,
     SAR = 3,
+    LITBASE = 5,
     SCOMPARE1 = 12,
     WINDOW_BASE = 72,
     WINDOW_START = 73,
@@ -274,6 +275,7 @@ static inline int cpu_mmu_index(CPUState *env)
 
 #define XTENSA_TBFLAG_RING_MASK 0x3
 #define XTENSA_TBFLAG_EXCM 0x4
+#define XTENSA_TBFLAG_LITBASE 0x8
 
 static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
         target_ulong *cs_base, int *flags)
@@ -285,6 +287,10 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
     if (env->sregs[PS] & PS_EXCM) {
         *flags |= XTENSA_TBFLAG_EXCM;
     }
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_EXTENDED_L32R) &&
+            (env->sregs[LITBASE] & 1)) {
+        *flags |= XTENSA_TBFLAG_LITBASE;
+    }
 }
 
 #include "cpu-all.h"
diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c
index 4f86934..074207f 100644
--- a/target-xtensa/helper.c
+++ b/target-xtensa/helper.c
@@ -38,6 +38,7 @@ void cpu_reset(CPUXtensaState *env)
 {
     env->exception_taken = 0;
     env->pc = env->config->exception_vector[EXC_RESET];
+    env->sregs[LITBASE] &= ~1;
     env->sregs[PS] = 0x1f;
 }
 
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index 8f45007..07a737a 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -49,6 +49,7 @@ typedef struct DisasContext {
     int ring;
     uint32_t lbeg;
     uint32_t lend;
+    TCGv_i32 litbase;
     int is_jmp;
     int singlestep_enabled;
 
@@ -71,6 +72,7 @@ static const char * const sregnames[256] = {
     [LEND] = "LEND",
     [LCOUNT] = "LCOUNT",
     [SAR] = "SAR",
+    [LITBASE] = "LITBASE",
     [SCOMPARE1] = "SCOMPARE1",
     [WINDOW_BASE] = "WINDOW_BASE",
     [WINDOW_START] = "WINDOW_START",
@@ -132,6 +134,21 @@ static inline bool option_enabled(DisasContext *dc, int opt)
     return xtensa_option_enabled(dc->config, opt);
 }
 
+static void init_litbase(DisasContext *dc)
+{
+    if (dc->tb->flags & XTENSA_TBFLAG_LITBASE) {
+        dc->litbase = tcg_temp_local_new_i32();
+        tcg_gen_andi_i32(dc->litbase, cpu_SR[LITBASE], 0xfffff000);
+    }
+}
+
+static void reset_litbase(DisasContext *dc)
+{
+    if (dc->tb->flags & XTENSA_TBFLAG_LITBASE) {
+        tcg_temp_free(dc->litbase);
+    }
+}
+
 static void init_sar_tracker(DisasContext *dc)
 {
     dc->sar_5bit = false;
@@ -332,6 +349,13 @@ static void gen_wsr_sar(DisasContext *dc, uint32_t sr, TCGv_i32 s)
     dc->sar_m32_5bit = false;
 }
 
+static void gen_wsr_litbase(DisasContext *dc, uint32_t sr, TCGv_i32 s)
+{
+    tcg_gen_andi_i32(cpu_SR[sr], s, 0xfffff001);
+    /* This can change tb->flags, so exit tb */
+    gen_jumpi_check_loop_end(dc, -1);
+}
+
 static void gen_wsr_windowbase(DisasContext *dc, uint32_t sr, TCGv_i32 v)
 {
     gen_helper_wsr_windowbase(v);
@@ -357,6 +381,7 @@ static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s)
         [LBEG] = gen_wsr_lbeg,
         [LEND] = gen_wsr_lend,
         [SAR] = gen_wsr_sar,
+        [LITBASE] = gen_wsr_litbase,
         [WINDOW_BASE] = gen_wsr_windowbase,
         [PS] = gen_wsr_ps,
     };
@@ -1298,11 +1323,13 @@ static void disas_xtensa_insn(DisasContext *dc)
     case 1: /*L32R*/
         {
             TCGv_i32 tmp = tcg_const_i32(
-                    (0xfffc0000 | (RI16_IMM16 << 2)) +
-                    ((dc->pc + 3) & ~3));
-
-            /* no ext L32R */
+                    ((dc->tb->flags & XTENSA_TBFLAG_LITBASE) ?
+                     0 : ((dc->pc + 3) & ~3)) +
+                    (0xfffc0000 | (RI16_IMM16 << 2)));
 
+            if (dc->tb->flags & XTENSA_TBFLAG_LITBASE) {
+                tcg_gen_add_i32(tmp, tmp, dc->litbase);
+            }
             tcg_gen_qemu_ld32u(cpu_R[RRR_T], tmp, dc->cring);
             tcg_temp_free(tmp);
         }
@@ -1834,6 +1861,7 @@ static void gen_intermediate_code_internal(
     dc.lend = env->sregs[LEND];
     dc.is_jmp = DISAS_NEXT;
 
+    init_litbase(&dc);
     init_sar_tracker(&dc);
 
     gen_icount_start();
@@ -1876,6 +1904,7 @@ static void gen_intermediate_code_internal(
             dc.pc < next_page_start &&
             gen_opc_ptr < gen_opc_end);
 
+    reset_litbase(&dc);
     reset_sar_tracker(&dc);
 
     if (dc.is_jmp == DISAS_NEXT) {
commit 797d780b1375b1af1d7713685589bfdec9908dc3
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Tue Sep 6 03:55:44 2011 +0400

    target-xtensa: implement loop option
    
    See ISA, 4.3.2 for details.
    
    Operations that change LEND SR value invalidate TBs at the old and at
    the new LEND. LEND value at TB compilation time is considered constant
    and loop instruction is generated based on this value.
    
    Invalidation may be avoided for the TB at the old LEND address, since
    looping code verifies actual LEND value.
    
    Invalidation may be avoided for the TB at the new LEND address if
    there's a way to associate LEND address with TB at compilation time and
    later verify that it doesn't change.
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index 7e662f5..97badf2 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -106,6 +106,9 @@ enum {
 };
 
 enum {
+    LBEG = 0,
+    LEND = 1,
+    LCOUNT = 2,
     SAR = 3,
     SCOMPARE1 = 12,
     WINDOW_BASE = 72,
diff --git a/target-xtensa/helpers.h b/target-xtensa/helpers.h
index 0971fde..b318c5a 100644
--- a/target-xtensa/helpers.h
+++ b/target-xtensa/helpers.h
@@ -12,6 +12,8 @@ DEF_HELPER_1(rotw, void, i32)
 DEF_HELPER_2(window_check, void, i32, i32)
 DEF_HELPER_0(restore_owb, void)
 DEF_HELPER_1(movsp, void, i32)
+DEF_HELPER_1(wsr_lbeg, void, i32)
+DEF_HELPER_1(wsr_lend, void, i32)
 DEF_HELPER_0(dump_state, void)
 
 #include "def-helper.h"
diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c
index 7c3fb88..5e0f56f 100644
--- a/target-xtensa/op_helper.c
+++ b/target-xtensa/op_helper.c
@@ -288,6 +288,26 @@ void HELPER(movsp)(uint32_t pc)
     }
 }
 
+void HELPER(wsr_lbeg)(uint32_t v)
+{
+    if (env->sregs[LBEG] != v) {
+        tb_invalidate_phys_page_range(
+                env->sregs[LEND] - 1, env->sregs[LEND], 0);
+        env->sregs[LBEG] = v;
+    }
+}
+
+void HELPER(wsr_lend)(uint32_t v)
+{
+    if (env->sregs[LEND] != v) {
+        tb_invalidate_phys_page_range(
+                env->sregs[LEND] - 1, env->sregs[LEND], 0);
+        env->sregs[LEND] = v;
+        tb_invalidate_phys_page_range(
+                env->sregs[LEND] - 1, env->sregs[LEND], 0);
+    }
+}
+
 void HELPER(dump_state)(void)
 {
     cpu_dump_state(env, stderr, fprintf, 0);
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index 7a2e07f..8f45007 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -47,6 +47,8 @@ typedef struct DisasContext {
     uint32_t next_pc;
     int cring;
     int ring;
+    uint32_t lbeg;
+    uint32_t lend;
     int is_jmp;
     int singlestep_enabled;
 
@@ -65,6 +67,9 @@ static TCGv_i32 cpu_UR[256];
 #include "gen-icount.h"
 
 static const char * const sregnames[256] = {
+    [LBEG] = "LBEG",
+    [LEND] = "LEND",
+    [LCOUNT] = "LCOUNT",
     [SAR] = "SAR",
     [SCOMPARE1] = "SCOMPARE1",
     [WINDOW_BASE] = "WINDOW_BASE",
@@ -247,13 +252,37 @@ static void gen_callwi(DisasContext *dc, int callinc, uint32_t dest, int slot)
     tcg_temp_free(tmp);
 }
 
+static bool gen_check_loop_end(DisasContext *dc, int slot)
+{
+    if (option_enabled(dc, XTENSA_OPTION_LOOP) &&
+            !(dc->tb->flags & XTENSA_TBFLAG_EXCM) &&
+            dc->next_pc == dc->lend) {
+        int label = gen_new_label();
+
+        tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_SR[LCOUNT], 0, label);
+        tcg_gen_subi_i32(cpu_SR[LCOUNT], cpu_SR[LCOUNT], 1);
+        gen_jumpi(dc, dc->lbeg, slot);
+        gen_set_label(label);
+        gen_jumpi(dc, dc->next_pc, -1);
+        return true;
+    }
+    return false;
+}
+
+static void gen_jumpi_check_loop_end(DisasContext *dc, int slot)
+{
+    if (!gen_check_loop_end(dc, slot)) {
+        gen_jumpi(dc, dc->next_pc, slot);
+    }
+}
+
 static void gen_brcond(DisasContext *dc, TCGCond cond,
         TCGv_i32 t0, TCGv_i32 t1, uint32_t offset)
 {
     int label = gen_new_label();
 
     tcg_gen_brcond_i32(cond, t0, t1, label);
-    gen_jumpi(dc, dc->next_pc, 0);
+    gen_jumpi_check_loop_end(dc, 0);
     gen_set_label(label);
     gen_jumpi(dc, dc->pc + offset, 1);
 }
@@ -283,6 +312,16 @@ static void gen_rsr(DisasContext *dc, TCGv_i32 d, uint32_t sr)
     }
 }
 
+static void gen_wsr_lbeg(DisasContext *dc, uint32_t sr, TCGv_i32 s)
+{
+    gen_helper_wsr_lbeg(s);
+}
+
+static void gen_wsr_lend(DisasContext *dc, uint32_t sr, TCGv_i32 s)
+{
+    gen_helper_wsr_lend(s);
+}
+
 static void gen_wsr_sar(DisasContext *dc, uint32_t sr, TCGv_i32 s)
 {
     tcg_gen_andi_i32(cpu_SR[sr], s, 0x3f);
@@ -308,13 +347,15 @@ static void gen_wsr_ps(DisasContext *dc, uint32_t sr, TCGv_i32 v)
     }
     tcg_gen_andi_i32(cpu_SR[sr], v, mask);
     /* This can change mmu index, so exit tb */
-    gen_jumpi(dc, dc->next_pc, -1);
+    gen_jumpi_check_loop_end(dc, -1);
 }
 
 static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s)
 {
     static void (* const wsr_handler[256])(DisasContext *dc,
             uint32_t sr, TCGv_i32 v) = {
+        [LBEG] = gen_wsr_lbeg,
+        [LEND] = gen_wsr_lend,
         [SAR] = gen_wsr_sar,
         [WINDOW_BASE] = gen_wsr_windowbase,
         [PS] = gen_wsr_ps,
@@ -1542,15 +1583,29 @@ static void disas_xtensa_insn(DisasContext *dc)
                     break;
 
                 case 8: /*LOOP*/
-                    TBD();
-                    break;
-
                 case 9: /*LOOPNEZ*/
-                    TBD();
-                    break;
-
                 case 10: /*LOOPGTZ*/
-                    TBD();
+                    HAS_OPTION(XTENSA_OPTION_LOOP);
+                    {
+                        uint32_t lend = dc->pc + RRI8_IMM8 + 4;
+                        TCGv_i32 tmp = tcg_const_i32(lend);
+
+                        tcg_gen_subi_i32(cpu_SR[LCOUNT], cpu_R[RRI8_S], 1);
+                        tcg_gen_movi_i32(cpu_SR[LBEG], dc->next_pc);
+                        gen_wsr_lend(dc, LEND, tmp);
+                        tcg_temp_free(tmp);
+
+                        if (BRI8_R > 8) {
+                            int label = gen_new_label();
+                            tcg_gen_brcondi_i32(
+                                    BRI8_R == 9 ? TCG_COND_NE : TCG_COND_GT,
+                                    cpu_R[RRI8_S], 0, label);
+                            gen_jumpi(dc, lend, 1);
+                            gen_set_label(label);
+                        }
+
+                        gen_jumpi(dc, dc->next_pc, 0);
+                    }
                     break;
 
                 default: /*reserved*/
@@ -1727,7 +1782,9 @@ static void disas_xtensa_insn(DisasContext *dc)
         break;
     }
 
+    gen_check_loop_end(dc, 0);
     dc->pc = dc->next_pc;
+
     return;
 
 invalid_opcode:
@@ -1773,6 +1830,8 @@ static void gen_intermediate_code_internal(
     dc.pc = pc_start;
     dc.ring = tb->flags & XTENSA_TBFLAG_RING_MASK;
     dc.cring = (tb->flags & XTENSA_TBFLAG_EXCM) ? 0 : dc.ring;
+    dc.lbeg = env->sregs[LBEG];
+    dc.lend = env->sregs[LEND];
     dc.is_jmp = DISAS_NEXT;
 
     init_sar_tracker(&dc);
commit 553e44f90645b7f2fc9cec7583844e24cd86019f
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Tue Sep 6 03:55:43 2011 +0400

    target-xtensa: implement windowed registers
    
    See ISA, 4.7.1 for details.
    
    Physical registers and currently visible window are separate fields in
    CPUEnv. Only current window is accessible to TCG. On operations that
    change window base helpers copy current window to and from physical
    registers.
    
    Window overflow check described in 4.7.1.3 is in separate patch.
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index cae6637..7e662f5 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -108,6 +108,8 @@ enum {
 enum {
     SAR = 3,
     SCOMPARE1 = 12,
+    WINDOW_BASE = 72,
+    WINDOW_START = 73,
     EPC1 = 177,
     DEPC = 192,
     EXCSAVE1 = 209,
@@ -134,6 +136,8 @@ enum {
 
 #define PS_WOE 0x40000
 
+#define MAX_NAREG 64
+
 enum {
     /* Static vectors */
     EXC_RESET,
@@ -185,6 +189,7 @@ enum {
 typedef struct XtensaConfig {
     const char *name;
     uint64_t options;
+    unsigned nareg;
     int excm_level;
     int ndepc;
     uint32_t exception_vector[EXC_MAX];
@@ -196,6 +201,7 @@ typedef struct CPUXtensaState {
     uint32_t pc;
     uint32_t sregs[256];
     uint32_t uregs[256];
+    uint32_t phys_regs[MAX_NAREG];
 
     int exception_taken;
 
@@ -214,6 +220,8 @@ int cpu_xtensa_exec(CPUXtensaState *s);
 void do_interrupt(CPUXtensaState *s);
 int cpu_xtensa_signal_handler(int host_signum, void *pinfo, void *puc);
 void xtensa_cpu_list(FILE *f, fprintf_function cpu_fprintf);
+void xtensa_sync_window_from_phys(CPUState *env);
+void xtensa_sync_phys_from_window(CPUState *env);
 
 #define XTENSA_OPTION_BIT(opt) (((uint64_t)1) << (opt))
 
diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c
index 44ebb9f..4f86934 100644
--- a/target-xtensa/helper.c
+++ b/target-xtensa/helper.c
@@ -45,6 +45,7 @@ static const XtensaConfig core_config[] = {
     {
         .name = "sample-xtensa-core",
         .options = -1,
+        .nareg = 64,
         .ndepc = 1,
         .excm_level = 16,
         .exception_vector = {
diff --git a/target-xtensa/helpers.h b/target-xtensa/helpers.h
index 6329c43..0971fde 100644
--- a/target-xtensa/helpers.h
+++ b/target-xtensa/helpers.h
@@ -5,5 +5,13 @@ DEF_HELPER_2(exception_cause, void, i32, i32)
 DEF_HELPER_3(exception_cause_vaddr, void, i32, i32, i32)
 DEF_HELPER_1(nsa, i32, i32)
 DEF_HELPER_1(nsau, i32, i32)
+DEF_HELPER_1(wsr_windowbase, void, i32)
+DEF_HELPER_3(entry, void, i32, i32, i32)
+DEF_HELPER_1(retw, i32, i32)
+DEF_HELPER_1(rotw, void, i32)
+DEF_HELPER_2(window_check, void, i32, i32)
+DEF_HELPER_0(restore_owb, void)
+DEF_HELPER_1(movsp, void, i32)
+DEF_HELPER_0(dump_state, void)
 
 #include "def-helper.h"
diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c
index 794a834..7c3fb88 100644
--- a/target-xtensa/op_helper.c
+++ b/target-xtensa/op_helper.c
@@ -100,3 +100,195 @@ uint32_t HELPER(nsau)(uint32_t v)
 {
     return v ? clz32(v) : 32;
 }
+
+static void copy_window_from_phys(CPUState *env,
+        uint32_t window, uint32_t phys, uint32_t n)
+{
+    assert(phys < env->config->nareg);
+    if (phys + n <= env->config->nareg) {
+        memcpy(env->regs + window, env->phys_regs + phys,
+                n * sizeof(uint32_t));
+    } else {
+        uint32_t n1 = env->config->nareg - phys;
+        memcpy(env->regs + window, env->phys_regs + phys,
+                n1 * sizeof(uint32_t));
+        memcpy(env->regs + window + n1, env->phys_regs,
+                (n - n1) * sizeof(uint32_t));
+    }
+}
+
+static void copy_phys_from_window(CPUState *env,
+        uint32_t phys, uint32_t window, uint32_t n)
+{
+    assert(phys < env->config->nareg);
+    if (phys + n <= env->config->nareg) {
+        memcpy(env->phys_regs + phys, env->regs + window,
+                n * sizeof(uint32_t));
+    } else {
+        uint32_t n1 = env->config->nareg - phys;
+        memcpy(env->phys_regs + phys, env->regs + window,
+                n1 * sizeof(uint32_t));
+        memcpy(env->phys_regs, env->regs + window + n1,
+                (n - n1) * sizeof(uint32_t));
+    }
+}
+
+
+static inline unsigned windowbase_bound(unsigned a, const CPUState *env)
+{
+    return a & (env->config->nareg / 4 - 1);
+}
+
+static inline unsigned windowstart_bit(unsigned a, const CPUState *env)
+{
+    return 1 << windowbase_bound(a, env);
+}
+
+void xtensa_sync_window_from_phys(CPUState *env)
+{
+    copy_window_from_phys(env, 0, env->sregs[WINDOW_BASE] * 4, 16);
+}
+
+void xtensa_sync_phys_from_window(CPUState *env)
+{
+    copy_phys_from_window(env, env->sregs[WINDOW_BASE] * 4, 0, 16);
+}
+
+static void rotate_window_abs(uint32_t position)
+{
+    xtensa_sync_phys_from_window(env);
+    env->sregs[WINDOW_BASE] = windowbase_bound(position, env);
+    xtensa_sync_window_from_phys(env);
+}
+
+static void rotate_window(uint32_t delta)
+{
+    rotate_window_abs(env->sregs[WINDOW_BASE] + delta);
+}
+
+void HELPER(wsr_windowbase)(uint32_t v)
+{
+    rotate_window_abs(v);
+}
+
+void HELPER(entry)(uint32_t pc, uint32_t s, uint32_t imm)
+{
+    int callinc = (env->sregs[PS] & PS_CALLINC) >> PS_CALLINC_SHIFT;
+    if (s > 3 || ((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) != 0) {
+        qemu_log("Illegal entry instruction(pc = %08x), PS = %08x\n",
+                pc, env->sregs[PS]);
+        HELPER(exception_cause)(pc, ILLEGAL_INSTRUCTION_CAUSE);
+    } else {
+        env->regs[(callinc << 2) | (s & 3)] = env->regs[s] - (imm << 3);
+        rotate_window(callinc);
+        env->sregs[WINDOW_START] |=
+            windowstart_bit(env->sregs[WINDOW_BASE], env);
+    }
+}
+
+void HELPER(window_check)(uint32_t pc, uint32_t w)
+{
+    uint32_t windowbase = windowbase_bound(env->sregs[WINDOW_BASE], env);
+    uint32_t windowstart = env->sregs[WINDOW_START];
+    uint32_t m, n;
+
+    if ((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) {
+        return;
+    }
+
+    for (n = 1; ; ++n) {
+        if (n > w) {
+            return;
+        }
+        if (windowstart & windowstart_bit(windowbase + n, env)) {
+            break;
+        }
+    }
+
+    m = windowbase_bound(windowbase + n, env);
+    rotate_window(n);
+    env->sregs[PS] = (env->sregs[PS] & ~PS_OWB) |
+        (windowbase << PS_OWB_SHIFT) | PS_EXCM;
+    env->sregs[EPC1] = env->pc = pc;
+
+    if (windowstart & windowstart_bit(m + 1, env)) {
+        HELPER(exception)(EXC_WINDOW_OVERFLOW4);
+    } else if (windowstart & windowstart_bit(m + 2, env)) {
+        HELPER(exception)(EXC_WINDOW_OVERFLOW8);
+    } else {
+        HELPER(exception)(EXC_WINDOW_OVERFLOW12);
+    }
+}
+
+uint32_t HELPER(retw)(uint32_t pc)
+{
+    int n = (env->regs[0] >> 30) & 0x3;
+    int m = 0;
+    uint32_t windowbase = windowbase_bound(env->sregs[WINDOW_BASE], env);
+    uint32_t windowstart = env->sregs[WINDOW_START];
+    uint32_t ret_pc = 0;
+
+    if (windowstart & windowstart_bit(windowbase - 1, env)) {
+        m = 1;
+    } else if (windowstart & windowstart_bit(windowbase - 2, env)) {
+        m = 2;
+    } else if (windowstart & windowstart_bit(windowbase - 3, env)) {
+        m = 3;
+    }
+
+    if (n == 0 || (m != 0 && m != n) ||
+            ((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) != 0) {
+        qemu_log("Illegal retw instruction(pc = %08x), "
+                "PS = %08x, m = %d, n = %d\n",
+                pc, env->sregs[PS], m, n);
+        HELPER(exception_cause)(pc, ILLEGAL_INSTRUCTION_CAUSE);
+    } else {
+        int owb = windowbase;
+
+        ret_pc = (pc & 0xc0000000) | (env->regs[0] & 0x3fffffff);
+
+        rotate_window(-n);
+        if (windowstart & windowstart_bit(env->sregs[WINDOW_BASE], env)) {
+            env->sregs[WINDOW_START] &= ~windowstart_bit(owb, env);
+        } else {
+            /* window underflow */
+            env->sregs[PS] = (env->sregs[PS] & ~PS_OWB) |
+                (windowbase << PS_OWB_SHIFT) | PS_EXCM;
+            env->sregs[EPC1] = env->pc = pc;
+
+            if (n == 1) {
+                HELPER(exception)(EXC_WINDOW_UNDERFLOW4);
+            } else if (n == 2) {
+                HELPER(exception)(EXC_WINDOW_UNDERFLOW8);
+            } else if (n == 3) {
+                HELPER(exception)(EXC_WINDOW_UNDERFLOW12);
+            }
+        }
+    }
+    return ret_pc;
+}
+
+void HELPER(rotw)(uint32_t imm4)
+{
+    rotate_window(imm4);
+}
+
+void HELPER(restore_owb)(void)
+{
+    rotate_window_abs((env->sregs[PS] & PS_OWB) >> PS_OWB_SHIFT);
+}
+
+void HELPER(movsp)(uint32_t pc)
+{
+    if ((env->sregs[WINDOW_START] &
+            (windowstart_bit(env->sregs[WINDOW_BASE] - 3, env) |
+             windowstart_bit(env->sregs[WINDOW_BASE] - 2, env) |
+             windowstart_bit(env->sregs[WINDOW_BASE] - 1, env))) == 0) {
+        HELPER(exception_cause)(pc, ALLOCA_CAUSE);
+    }
+}
+
+void HELPER(dump_state)(void)
+{
+    cpu_dump_state(env, stderr, fprintf, 0);
+}
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index bc04a10..7a2e07f 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -67,6 +67,8 @@ static TCGv_i32 cpu_UR[256];
 static const char * const sregnames[256] = {
     [SAR] = "SAR",
     [SCOMPARE1] = "SCOMPARE1",
+    [WINDOW_BASE] = "WINDOW_BASE",
+    [WINDOW_START] = "WINDOW_START",
     [EPC1] = "EPC1",
     [DEPC] = "DEPC",
     [EXCSAVE1] = "EXCSAVE1",
@@ -217,6 +219,34 @@ static void gen_jumpi(DisasContext *dc, uint32_t dest, int slot)
     tcg_temp_free(tmp);
 }
 
+static void gen_callw_slot(DisasContext *dc, int callinc, TCGv_i32 dest,
+        int slot)
+{
+    TCGv_i32 tcallinc = tcg_const_i32(callinc);
+
+    tcg_gen_deposit_i32(cpu_SR[PS], cpu_SR[PS],
+            tcallinc, PS_CALLINC_SHIFT, PS_CALLINC_LEN);
+    tcg_temp_free(tcallinc);
+    tcg_gen_movi_i32(cpu_R[callinc << 2],
+            (callinc << 30) | (dc->next_pc & 0x3fffffff));
+    gen_jump_slot(dc, dest, slot);
+}
+
+static void gen_callw(DisasContext *dc, int callinc, TCGv_i32 dest)
+{
+    gen_callw_slot(dc, callinc, dest, -1);
+}
+
+static void gen_callwi(DisasContext *dc, int callinc, uint32_t dest, int slot)
+{
+    TCGv_i32 tmp = tcg_const_i32(dest);
+    if (((dc->pc ^ dest) & TARGET_PAGE_MASK) != 0) {
+        slot = -1;
+    }
+    gen_callw_slot(dc, callinc, tmp, slot);
+    tcg_temp_free(tmp);
+}
+
 static void gen_brcond(DisasContext *dc, TCGCond cond,
         TCGv_i32 t0, TCGv_i32 t1, uint32_t offset)
 {
@@ -263,6 +293,11 @@ static void gen_wsr_sar(DisasContext *dc, uint32_t sr, TCGv_i32 s)
     dc->sar_m32_5bit = false;
 }
 
+static void gen_wsr_windowbase(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+    gen_helper_wsr_windowbase(v);
+}
+
 static void gen_wsr_ps(DisasContext *dc, uint32_t sr, TCGv_i32 v)
 {
     uint32_t mask = PS_WOE | PS_CALLINC | PS_OWB |
@@ -281,6 +316,7 @@ static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s)
     static void (* const wsr_handler[256])(DisasContext *dc,
             uint32_t sr, TCGv_i32 v) = {
         [SAR] = gen_wsr_sar,
+        [WINDOW_BASE] = gen_wsr_windowbase,
         [PS] = gen_wsr_ps,
     };
 
@@ -429,7 +465,12 @@ static void disas_xtensa_insn(DisasContext *dc)
 
                         case 1: /*RETWw*/
                             HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
-                            TBD();
+                            {
+                                TCGv_i32 tmp = tcg_const_i32(dc->pc);
+                                gen_helper_retw(tmp, tmp);
+                                gen_jump(dc, tmp);
+                                tcg_temp_free(tmp);
+                            }
                             break;
 
                         case 3: /*reserved*/
@@ -454,7 +495,13 @@ static void disas_xtensa_insn(DisasContext *dc)
                         case 2: /*CALLX8w*/
                         case 3: /*CALLX12w*/
                             HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
-                            TBD();
+                            {
+                                TCGv_i32 tmp = tcg_temp_new_i32();
+
+                                tcg_gen_mov_i32(tmp, cpu_R[CALLX_S]);
+                                gen_callw(dc, CALLX_N, tmp);
+                                tcg_temp_free(tmp);
+                            }
                             break;
                         }
                         break;
@@ -463,7 +510,12 @@ static void disas_xtensa_insn(DisasContext *dc)
 
                 case 1: /*MOVSPw*/
                     HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
-                    TBD();
+                    {
+                        TCGv_i32 pc = tcg_const_i32(dc->pc);
+                        gen_helper_movsp(pc);
+                        tcg_gen_mov_i32(cpu_R[RRR_T], cpu_R[RRR_S]);
+                        tcg_temp_free(pc);
+                    }
                     break;
 
                 case 2: /*SYNC*/
@@ -523,7 +575,27 @@ static void disas_xtensa_insn(DisasContext *dc)
                         case 4: /*RFWOw*/
                         case 5: /*RFWUw*/
                             HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
-                            TBD();
+                            gen_check_privilege(dc);
+                            {
+                                TCGv_i32 tmp = tcg_const_i32(1);
+
+                                tcg_gen_andi_i32(
+                                        cpu_SR[PS], cpu_SR[PS], ~PS_EXCM);
+                                tcg_gen_shl_i32(tmp, tmp, cpu_SR[WINDOW_BASE]);
+
+                                if (RRR_S == 4) {
+                                    tcg_gen_andc_i32(cpu_SR[WINDOW_START],
+                                            cpu_SR[WINDOW_START], tmp);
+                                } else {
+                                    tcg_gen_or_i32(cpu_SR[WINDOW_START],
+                                            cpu_SR[WINDOW_START], tmp);
+                                }
+
+                                gen_helper_restore_owb();
+                                gen_jump(dc, cpu_SR[EPC1]);
+
+                                tcg_temp_free(tmp);
+                            }
                             break;
 
                         default: /*reserved*/
@@ -670,7 +742,13 @@ static void disas_xtensa_insn(DisasContext *dc)
 
                 case 8: /*ROTWw*/
                     HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
-                    TBD();
+                    gen_check_privilege(dc);
+                    {
+                        TCGv_i32 tmp = tcg_const_i32(
+                                RRR_T | ((RRR_T & 8) ? 0xfffffff0 : 0));
+                        gen_helper_rotw(tmp);
+                        tcg_temp_free(tmp);
+                    }
                     break;
 
                 case 14: /*NSAu*/
@@ -1129,7 +1207,35 @@ static void disas_xtensa_insn(DisasContext *dc)
             break;
 
         case 9: /*LSC4*/
-            TBD();
+            switch (OP2) {
+            case 0: /*L32E*/
+                HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                gen_check_privilege(dc);
+                {
+                    TCGv_i32 addr = tcg_temp_new_i32();
+                    tcg_gen_addi_i32(addr, cpu_R[RRR_S],
+                            (0xffffffc0 | (RRR_R << 2)));
+                    tcg_gen_qemu_ld32u(cpu_R[RRR_T], addr, dc->ring);
+                    tcg_temp_free(addr);
+                }
+                break;
+
+            case 4: /*S32E*/
+                HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                gen_check_privilege(dc);
+                {
+                    TCGv_i32 addr = tcg_temp_new_i32();
+                    tcg_gen_addi_i32(addr, cpu_R[RRR_S],
+                            (0xffffffc0 | (RRR_R << 2)));
+                    tcg_gen_qemu_st32(cpu_R[RRR_T], addr, dc->ring);
+                    tcg_temp_free(addr);
+                }
+                break;
+
+            default:
+                RESERVED();
+                break;
+            }
             break;
 
         case 10: /*FP0*/
@@ -1368,7 +1474,8 @@ static void disas_xtensa_insn(DisasContext *dc)
         case 2: /*CALL8w*/
         case 3: /*CALL12w*/
             HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
-            TBD();
+            gen_callwi(dc, CALL_N,
+                    (dc->pc & ~3) + (CALL_OFFSET_SE << 2) + 4, 0);
             break;
         }
         break;
@@ -1411,7 +1518,15 @@ static void disas_xtensa_insn(DisasContext *dc)
             switch (BRI8_M) {
             case 0: /*ENTRYw*/
                 HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
-                TBD();
+                {
+                    TCGv_i32 pc = tcg_const_i32(dc->pc);
+                    TCGv_i32 s = tcg_const_i32(BRI12_S);
+                    TCGv_i32 imm = tcg_const_i32(BRI12_IMM12);
+                    gen_helper_entry(pc, s, imm);
+                    tcg_temp_free(imm);
+                    tcg_temp_free(s);
+                    tcg_temp_free(pc);
+                }
                 break;
 
             case 1: /*B1*/
@@ -1576,7 +1691,12 @@ static void disas_xtensa_insn(DisasContext *dc)
 
             case 1: /*RETW.Nn*/
                 HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
-                TBD();
+                {
+                    TCGv_i32 tmp = tcg_const_i32(dc->pc);
+                    gen_helper_retw(tmp, tmp);
+                    gen_jump(dc, tmp);
+                    tcg_temp_free(tmp);
+                }
                 break;
 
             case 2: /*BREAK.Nn*/
@@ -1750,6 +1870,13 @@ void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
         cpu_fprintf(f, "A%02d=%08x%c", i, env->regs[i],
                 (i % 4) == 3 ? '\n' : ' ');
     }
+
+    cpu_fprintf(f, "\n");
+
+    for (i = 0; i < env->config->nareg; ++i) {
+        cpu_fprintf(f, "AR%02d=%08x%c", i, env->phys_regs[i],
+                (i % 4) == 3 ? '\n' : ' ');
+    }
 }
 
 void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
commit f76ebf55cd971c82e867fea97741e48d2f14499d
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Tue Sep 6 03:55:42 2011 +0400

    target-xtensa: implement RST2 group (32 bit mul/div/rem)
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index dccd453..bc04a10 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -878,7 +878,82 @@ static void disas_xtensa_insn(DisasContext *dc)
             break;
 
         case 2: /*RST2*/
-            TBD();
+            if (OP2 >= 12) {
+                HAS_OPTION(XTENSA_OPTION_32_BIT_IDIV);
+                int label = gen_new_label();
+                tcg_gen_brcondi_i32(TCG_COND_NE, cpu_R[RRR_T], 0, label);
+                gen_exception_cause(dc, INTEGER_DIVIDE_BY_ZERO_CAUSE);
+                gen_set_label(label);
+            }
+
+            switch (OP2) {
+            case 8: /*MULLi*/
+                HAS_OPTION(XTENSA_OPTION_32_BIT_IMUL);
+                tcg_gen_mul_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
+                break;
+
+            case 10: /*MULUHi*/
+            case 11: /*MULSHi*/
+                HAS_OPTION(XTENSA_OPTION_32_BIT_IMUL);
+                {
+                    TCGv_i64 r = tcg_temp_new_i64();
+                    TCGv_i64 s = tcg_temp_new_i64();
+                    TCGv_i64 t = tcg_temp_new_i64();
+
+                    if (OP2 == 10) {
+                        tcg_gen_extu_i32_i64(s, cpu_R[RRR_S]);
+                        tcg_gen_extu_i32_i64(t, cpu_R[RRR_T]);
+                    } else {
+                        tcg_gen_ext_i32_i64(s, cpu_R[RRR_S]);
+                        tcg_gen_ext_i32_i64(t, cpu_R[RRR_T]);
+                    }
+                    tcg_gen_mul_i64(r, s, t);
+                    tcg_gen_shri_i64(r, r, 32);
+                    tcg_gen_trunc_i64_i32(cpu_R[RRR_R], r);
+
+                    tcg_temp_free_i64(r);
+                    tcg_temp_free_i64(s);
+                    tcg_temp_free_i64(t);
+                }
+                break;
+
+            case 12: /*QUOUi*/
+                tcg_gen_divu_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
+                break;
+
+            case 13: /*QUOSi*/
+            case 15: /*REMSi*/
+                {
+                    int label1 = gen_new_label();
+                    int label2 = gen_new_label();
+
+                    tcg_gen_brcondi_i32(TCG_COND_NE, cpu_R[RRR_S], 0x80000000,
+                            label1);
+                    tcg_gen_brcondi_i32(TCG_COND_NE, cpu_R[RRR_T], 0xffffffff,
+                            label1);
+                    tcg_gen_movi_i32(cpu_R[RRR_R],
+                            OP2 == 13 ? 0x80000000 : 0);
+                    tcg_gen_br(label2);
+                    gen_set_label(label1);
+                    if (OP2 == 13) {
+                        tcg_gen_div_i32(cpu_R[RRR_R],
+                                cpu_R[RRR_S], cpu_R[RRR_T]);
+                    } else {
+                        tcg_gen_rem_i32(cpu_R[RRR_R],
+                                cpu_R[RRR_S], cpu_R[RRR_T]);
+                    }
+                    gen_set_label(label2);
+                }
+                break;
+
+            case 14: /*REMUi*/
+                tcg_gen_remu_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
+                break;
+
+            default: /*reserved*/
+                RESERVED();
+                break;
+            }
             break;
 
         case 3: /*RST3*/
commit 40643d7c0fe4dc967ebc2f75e6758a4649776949
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Tue Sep 6 03:55:41 2011 +0400

    target-xtensa: implement exceptions
    
    - mark privileged opcodes with ring check;
    - make debug exception on exception handler entry.
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/cpu-exec.c b/cpu-exec.c
index d9278f3..aef66f2 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -489,6 +489,12 @@ int cpu_exec(CPUState *env)
                         do_interrupt(env);
                         next_tb = 0;
                     }
+#elif defined(TARGET_XTENSA)
+                    if (interrupt_request & CPU_INTERRUPT_HARD) {
+                        env->exception_index = EXC_IRQ;
+                        do_interrupt(env);
+                        next_tb = 0;
+                    }
 #endif
                    /* Don't use the cached interrupt_request value,
                       do_interrupt may have updated the EXITTB flag. */
diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index 939222c..cae6637 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -108,7 +108,12 @@ enum {
 enum {
     SAR = 3,
     SCOMPARE1 = 12,
+    EPC1 = 177,
+    DEPC = 192,
+    EXCSAVE1 = 209,
     PS = 230,
+    EXCCAUSE = 232,
+    EXCVADDR = 238,
 };
 
 #define PS_INTLEVEL 0xf
@@ -129,9 +134,60 @@ enum {
 
 #define PS_WOE 0x40000
 
+enum {
+    /* Static vectors */
+    EXC_RESET,
+    EXC_MEMORY_ERROR,
+
+    /* Dynamic vectors */
+    EXC_WINDOW_OVERFLOW4,
+    EXC_WINDOW_UNDERFLOW4,
+    EXC_WINDOW_OVERFLOW8,
+    EXC_WINDOW_UNDERFLOW8,
+    EXC_WINDOW_OVERFLOW12,
+    EXC_WINDOW_UNDERFLOW12,
+    EXC_IRQ,
+    EXC_KERNEL,
+    EXC_USER,
+    EXC_DOUBLE,
+    EXC_MAX
+};
+
+enum {
+    ILLEGAL_INSTRUCTION_CAUSE = 0,
+    SYSCALL_CAUSE,
+    INSTRUCTION_FETCH_ERROR_CAUSE,
+    LOAD_STORE_ERROR_CAUSE,
+    LEVEL1_INTERRUPT_CAUSE,
+    ALLOCA_CAUSE,
+    INTEGER_DIVIDE_BY_ZERO_CAUSE,
+    PRIVILEGED_CAUSE = 8,
+    LOAD_STORE_ALIGNMENT_CAUSE,
+
+    INSTR_PIF_DATA_ERROR_CAUSE = 12,
+    LOAD_STORE_PIF_DATA_ERROR_CAUSE,
+    INSTR_PIF_ADDR_ERROR_CAUSE,
+    LOAD_STORE_PIF_ADDR_ERROR_CAUSE,
+
+    INST_TLB_MISS_CAUSE,
+    INST_TLB_MULTI_HIT_CAUSE,
+    INST_FETCH_PRIVILEGE_CAUSE,
+    INST_FETCH_PROHIBITED_CAUSE = 20,
+    LOAD_STORE_TLB_MISS_CAUSE = 24,
+    LOAD_STORE_TLB_MULTI_HIT_CAUSE,
+    LOAD_STORE_PRIVILEGE_CAUSE,
+    LOAD_PROHIBITED_CAUSE = 28,
+    STORE_PROHIBITED_CAUSE,
+
+    COPROCESSOR0_DISABLED = 32,
+};
+
 typedef struct XtensaConfig {
     const char *name;
     uint64_t options;
+    int excm_level;
+    int ndepc;
+    uint32_t exception_vector[EXC_MAX];
 } XtensaConfig;
 
 typedef struct CPUXtensaState {
@@ -141,6 +197,8 @@ typedef struct CPUXtensaState {
     uint32_t sregs[256];
     uint32_t uregs[256];
 
+    int exception_taken;
+
     CPU_COMMON
 } CPUXtensaState;
 
@@ -164,6 +222,15 @@ static inline bool xtensa_option_enabled(const XtensaConfig *config, int opt)
     return (config->options & XTENSA_OPTION_BIT(opt)) != 0;
 }
 
+static inline int xtensa_get_cintlevel(const CPUState *env)
+{
+    int level = (env->sregs[PS] & PS_INTLEVEL) >> PS_INTLEVEL_SHIFT;
+    if ((env->sregs[PS] & PS_EXCM) && env->config->excm_level > level) {
+        level = env->config->excm_level;
+    }
+    return level;
+}
+
 static inline int xtensa_get_ring(const CPUState *env)
 {
     if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c
index 83b8a04..44ebb9f 100644
--- a/target-xtensa/helper.c
+++ b/target-xtensa/helper.c
@@ -36,7 +36,8 @@
 
 void cpu_reset(CPUXtensaState *env)
 {
-    env->pc = 0;
+    env->exception_taken = 0;
+    env->pc = env->config->exception_vector[EXC_RESET];
     env->sregs[PS] = 0x1f;
 }
 
@@ -44,6 +45,20 @@ static const XtensaConfig core_config[] = {
     {
         .name = "sample-xtensa-core",
         .options = -1,
+        .ndepc = 1,
+        .excm_level = 16,
+        .exception_vector = {
+            [EXC_RESET] = 0x5fff8000,
+            [EXC_WINDOW_OVERFLOW4] = 0x5fff8400,
+            [EXC_WINDOW_UNDERFLOW4] = 0x5fff8440,
+            [EXC_WINDOW_OVERFLOW8] = 0x5fff8480,
+            [EXC_WINDOW_UNDERFLOW8] = 0x5fff84c0,
+            [EXC_WINDOW_OVERFLOW12] = 0x5fff8500,
+            [EXC_WINDOW_UNDERFLOW12] = 0x5fff8540,
+            [EXC_KERNEL] = 0x5fff861c,
+            [EXC_USER] = 0x5fff863c,
+            [EXC_DOUBLE] = 0x5fff865c,
+        },
     },
 };
 
@@ -94,4 +109,24 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
 
 void do_interrupt(CPUState *env)
 {
+    switch (env->exception_index) {
+    case EXC_WINDOW_OVERFLOW4:
+    case EXC_WINDOW_UNDERFLOW4:
+    case EXC_WINDOW_OVERFLOW8:
+    case EXC_WINDOW_UNDERFLOW8:
+    case EXC_WINDOW_OVERFLOW12:
+    case EXC_WINDOW_UNDERFLOW12:
+    case EXC_KERNEL:
+    case EXC_USER:
+    case EXC_DOUBLE:
+        if (env->config->exception_vector[env->exception_index]) {
+            env->pc = env->config->exception_vector[env->exception_index];
+            env->exception_taken = 1;
+        } else {
+            qemu_log("%s(pc = %08x) bad exception_index: %d\n",
+                    __func__, env->pc, env->exception_index);
+        }
+        break;
+
+    }
 }
diff --git a/target-xtensa/helpers.h b/target-xtensa/helpers.h
index 976c8d8..6329c43 100644
--- a/target-xtensa/helpers.h
+++ b/target-xtensa/helpers.h
@@ -1,6 +1,8 @@
 #include "def-helper.h"
 
 DEF_HELPER_1(exception, void, i32)
+DEF_HELPER_2(exception_cause, void, i32, i32)
+DEF_HELPER_3(exception_cause_vaddr, void, i32, i32, i32)
 DEF_HELPER_1(nsa, i32, i32)
 DEF_HELPER_1(nsau, i32, i32)
 
diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c
index c1cfd2e..794a834 100644
--- a/target-xtensa/op_helper.c
+++ b/target-xtensa/op_helper.c
@@ -59,6 +59,35 @@ void HELPER(exception)(uint32_t excp)
     cpu_loop_exit(env);
 }
 
+void HELPER(exception_cause)(uint32_t pc, uint32_t cause)
+{
+    uint32_t vector;
+
+    env->pc = pc;
+    if (env->sregs[PS] & PS_EXCM) {
+        if (env->config->ndepc) {
+            env->sregs[DEPC] = pc;
+        } else {
+            env->sregs[EPC1] = pc;
+        }
+        vector = EXC_DOUBLE;
+    } else {
+        env->sregs[EPC1] = pc;
+        vector = (env->sregs[PS] & PS_UM) ? EXC_USER : EXC_KERNEL;
+    }
+
+    env->sregs[EXCCAUSE] = cause;
+    env->sregs[PS] |= PS_EXCM;
+
+    HELPER(exception)(vector);
+}
+
+void HELPER(exception_cause_vaddr)(uint32_t pc, uint32_t cause, uint32_t vaddr)
+{
+    env->sregs[EXCVADDR] = vaddr;
+    HELPER(exception_cause)(pc, cause);
+}
+
 uint32_t HELPER(nsa)(uint32_t v)
 {
     if (v & 0x80000000) {
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index 32fab09..dccd453 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -67,7 +67,12 @@ static TCGv_i32 cpu_UR[256];
 static const char * const sregnames[256] = {
     [SAR] = "SAR",
     [SCOMPARE1] = "SCOMPARE1",
+    [EPC1] = "EPC1",
+    [DEPC] = "DEPC",
+    [EXCSAVE1] = "EXCSAVE1",
     [PS] = "PS",
+    [EXCCAUSE] = "EXCCAUSE",
+    [EXCVADDR] = "EXCVADDR",
 };
 
 static const char * const uregnames[256] = {
@@ -165,6 +170,22 @@ static void gen_exception(int excp)
     tcg_temp_free(tmp);
 }
 
+static void gen_exception_cause(DisasContext *dc, uint32_t cause)
+{
+    TCGv_i32 tpc = tcg_const_i32(dc->pc);
+    TCGv_i32 tcause = tcg_const_i32(cause);
+    gen_helper_exception_cause(tpc, tcause);
+    tcg_temp_free(tpc);
+    tcg_temp_free(tcause);
+}
+
+static void gen_check_privilege(DisasContext *dc)
+{
+    if (dc->cring) {
+        gen_exception_cause(dc, PRIVILEGED_CAUSE);
+    }
+}
+
 static void gen_jump_slot(DisasContext *dc, TCGv dest, int slot)
 {
     tcg_gen_mov_i32(cpu_pc, dest);
@@ -392,7 +413,7 @@ static void disas_xtensa_insn(DisasContext *dc)
                 case 0: /*SNM0*/
                     switch (CALLX_M) {
                     case 0: /*ILL*/
-                        TBD();
+                        gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE);
                         break;
 
                     case 1: /*reserved*/
@@ -479,7 +500,52 @@ static void disas_xtensa_insn(DisasContext *dc)
                     break;
 
                 case 3: /*RFEIx*/
-                    TBD();
+                    switch (RRR_T) {
+                    case 0: /*RFETx*/
+                        HAS_OPTION(XTENSA_OPTION_EXCEPTION);
+                        switch (RRR_S) {
+                        case 0: /*RFEx*/
+                            gen_check_privilege(dc);
+                            tcg_gen_andi_i32(cpu_SR[PS], cpu_SR[PS], ~PS_EXCM);
+                            gen_jump(dc, cpu_SR[EPC1]);
+                            break;
+
+                        case 1: /*RFUEx*/
+                            RESERVED();
+                            break;
+
+                        case 2: /*RFDEx*/
+                            gen_check_privilege(dc);
+                            gen_jump(dc, cpu_SR[
+                                    dc->config->ndepc ? DEPC : EPC1]);
+                            break;
+
+                        case 4: /*RFWOw*/
+                        case 5: /*RFWUw*/
+                            HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                            TBD();
+                            break;
+
+                        default: /*reserved*/
+                            RESERVED();
+                            break;
+                        }
+                        break;
+
+                    case 1: /*RFIx*/
+                        HAS_OPTION(XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT);
+                        TBD();
+                        break;
+
+                    case 2: /*RFME*/
+                        TBD();
+                        break;
+
+                    default: /*reserved*/
+                        RESERVED();
+                        break;
+
+                    }
                     break;
 
                 case 4: /*BREAKx*/
@@ -489,12 +555,28 @@ static void disas_xtensa_insn(DisasContext *dc)
 
                 case 5: /*SYSCALLx*/
                     HAS_OPTION(XTENSA_OPTION_EXCEPTION);
-                    TBD();
+                    switch (RRR_S) {
+                    case 0: /*SYSCALLx*/
+                        gen_exception_cause(dc, SYSCALL_CAUSE);
+                        break;
+
+                    case 1: /*SIMCALL*/
+                        TBD();
+                        break;
+
+                    default:
+                        RESERVED();
+                        break;
+                    }
                     break;
 
                 case 6: /*RSILx*/
                     HAS_OPTION(XTENSA_OPTION_INTERRUPT);
-                    TBD();
+                    gen_check_privilege(dc);
+                    tcg_gen_mov_i32(cpu_R[RRR_T], cpu_SR[PS]);
+                    tcg_gen_ori_i32(cpu_SR[PS], cpu_SR[PS], RRR_S);
+                    tcg_gen_andi_i32(cpu_SR[PS], cpu_SR[PS],
+                            RRR_S | ~PS_INTLEVEL);
                     break;
 
                 case 7: /*WAITIx*/
@@ -691,6 +773,9 @@ static void disas_xtensa_insn(DisasContext *dc)
             case 6: /*XSR*/
                 {
                     TCGv_i32 tmp = tcg_temp_new_i32();
+                    if (RSR_SR >= 64) {
+                        gen_check_privilege(dc);
+                    }
                     tcg_gen_mov_i32(tmp, cpu_R[RRR_T]);
                     gen_rsr(dc, cpu_R[RRR_T], RSR_SR);
                     gen_wsr(dc, RSR_SR, tmp);
@@ -799,6 +884,9 @@ static void disas_xtensa_insn(DisasContext *dc)
         case 3: /*RST3*/
             switch (OP2) {
             case 0: /*RSR*/
+                if (RSR_SR >= 64) {
+                    gen_check_privilege(dc);
+                }
                 gen_rsr(dc, cpu_R[RRR_T], RSR_SR);
                 if (!sregnames[RSR_SR]) {
                     TBD();
@@ -806,6 +894,9 @@ static void disas_xtensa_insn(DisasContext *dc)
                 break;
 
             case 1: /*WSR*/
+                if (RSR_SR >= 64) {
+                    gen_check_privilege(dc);
+                }
                 gen_wsr(dc, RSR_SR, cpu_R[RRR_T]);
                 if (!sregnames[RSR_SR]) {
                     TBD();
@@ -1421,7 +1512,7 @@ static void disas_xtensa_insn(DisasContext *dc)
                 break;
 
             case 6: /*ILL.Nn*/
-                TBD();
+                gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE);
                 break;
 
             default: /*reserved*/
@@ -1493,6 +1584,12 @@ static void gen_intermediate_code_internal(
 
     gen_icount_start();
 
+    if (env->singlestep_enabled && env->exception_taken) {
+        env->exception_taken = 0;
+        tcg_gen_movi_i32(cpu_pc, dc.pc);
+        gen_exception(EXCP_DEBUG);
+    }
+
     do {
         check_breakpoint(env, &dc);
 
commit f0a548b93da07b6546e4f8178a93c47284a27d05
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Tue Sep 6 03:55:40 2011 +0400

    target-xtensa: add PS register and access control
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index ac9bbb4..939222c 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -108,8 +108,27 @@ enum {
 enum {
     SAR = 3,
     SCOMPARE1 = 12,
+    PS = 230,
 };
 
+#define PS_INTLEVEL 0xf
+#define PS_INTLEVEL_SHIFT 0
+
+#define PS_EXCM 0x10
+#define PS_UM 0x20
+
+#define PS_RING 0xc0
+#define PS_RING_SHIFT 6
+
+#define PS_OWB 0xf00
+#define PS_OWB_SHIFT 8
+
+#define PS_CALLINC 0x30000
+#define PS_CALLINC_SHIFT 16
+#define PS_CALLINC_LEN 2
+
+#define PS_WOE 0x40000
+
 typedef struct XtensaConfig {
     const char *name;
     uint64_t options;
@@ -145,17 +164,49 @@ static inline bool xtensa_option_enabled(const XtensaConfig *config, int opt)
     return (config->options & XTENSA_OPTION_BIT(opt)) != 0;
 }
 
+static inline int xtensa_get_ring(const CPUState *env)
+{
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+        return (env->sregs[PS] & PS_RING) >> PS_RING_SHIFT;
+    } else {
+        return 0;
+    }
+}
+
+static inline int xtensa_get_cring(const CPUState *env)
+{
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU) &&
+            (env->sregs[PS] & PS_EXCM) == 0) {
+        return (env->sregs[PS] & PS_RING) >> PS_RING_SHIFT;
+    } else {
+        return 0;
+    }
+}
+
+/* MMU modes definitions */
+#define MMU_MODE0_SUFFIX _ring0
+#define MMU_MODE1_SUFFIX _ring1
+#define MMU_MODE2_SUFFIX _ring2
+#define MMU_MODE3_SUFFIX _ring3
+
 static inline int cpu_mmu_index(CPUState *env)
 {
-    return 0;
+    return xtensa_get_cring(env);
 }
 
+#define XTENSA_TBFLAG_RING_MASK 0x3
+#define XTENSA_TBFLAG_EXCM 0x4
+
 static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
         target_ulong *cs_base, int *flags)
 {
     *pc = env->pc;
     *cs_base = 0;
     *flags = 0;
+    *flags |= xtensa_get_ring(env);
+    if (env->sregs[PS] & PS_EXCM) {
+        *flags |= XTENSA_TBFLAG_EXCM;
+    }
 }
 
 #include "cpu-all.h"
diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c
index c119fd0..83b8a04 100644
--- a/target-xtensa/helper.c
+++ b/target-xtensa/helper.c
@@ -37,6 +37,7 @@
 void cpu_reset(CPUXtensaState *env)
 {
     env->pc = 0;
+    env->sregs[PS] = 0x1f;
 }
 
 static const XtensaConfig core_config[] = {
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index 7d383b3..32fab09 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -45,6 +45,8 @@ typedef struct DisasContext {
     TranslationBlock *tb;
     uint32_t pc;
     uint32_t next_pc;
+    int cring;
+    int ring;
     int is_jmp;
     int singlestep_enabled;
 
@@ -65,6 +67,7 @@ static TCGv_i32 cpu_UR[256];
 static const char * const sregnames[256] = {
     [SAR] = "SAR",
     [SCOMPARE1] = "SCOMPARE1",
+    [PS] = "PS",
 };
 
 static const char * const uregnames[256] = {
@@ -239,11 +242,25 @@ static void gen_wsr_sar(DisasContext *dc, uint32_t sr, TCGv_i32 s)
     dc->sar_m32_5bit = false;
 }
 
+static void gen_wsr_ps(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+    uint32_t mask = PS_WOE | PS_CALLINC | PS_OWB |
+        PS_UM | PS_EXCM | PS_INTLEVEL;
+
+    if (option_enabled(dc, XTENSA_OPTION_MMU)) {
+        mask |= PS_RING;
+    }
+    tcg_gen_andi_i32(cpu_SR[sr], v, mask);
+    /* This can change mmu index, so exit tb */
+    gen_jumpi(dc, dc->next_pc, -1);
+}
+
 static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s)
 {
     static void (* const wsr_handler[256])(DisasContext *dc,
             uint32_t sr, TCGv_i32 v) = {
         [SAR] = gen_wsr_sar,
+        [PS] = gen_wsr_ps,
     };
 
     if (sregnames[sr]) {
@@ -973,7 +990,7 @@ static void disas_xtensa_insn(DisasContext *dc)
 
             /* no ext L32R */
 
-            tcg_gen_qemu_ld32u(cpu_R[RRR_T], tmp, 0);
+            tcg_gen_qemu_ld32u(cpu_R[RRR_T], tmp, dc->cring);
             tcg_temp_free(tmp);
         }
         break;
@@ -982,7 +999,7 @@ static void disas_xtensa_insn(DisasContext *dc)
 #define gen_load_store(type, shift) do { \
             TCGv_i32 addr = tcg_temp_new_i32(); \
             tcg_gen_addi_i32(addr, cpu_R[RRI8_S], RRI8_IMM8 << shift); \
-            tcg_gen_qemu_##type(cpu_R[RRI8_T], addr, 0); \
+            tcg_gen_qemu_##type(cpu_R[RRI8_T], addr, dc->cring); \
             tcg_temp_free(addr); \
         } while (0)
 
@@ -1140,11 +1157,11 @@ static void disas_xtensa_insn(DisasContext *dc)
 
                 tcg_gen_mov_i32(tmp, cpu_R[RRI8_T]);
                 tcg_gen_addi_i32(addr, cpu_R[RRI8_S], RRI8_IMM8 << 2);
-                tcg_gen_qemu_ld32u(cpu_R[RRI8_T], addr, 0);
+                tcg_gen_qemu_ld32u(cpu_R[RRI8_T], addr, dc->cring);
                 tcg_gen_brcond_i32(TCG_COND_NE, cpu_R[RRI8_T],
                         cpu_SR[SCOMPARE1], label);
 
-                tcg_gen_qemu_st32(tmp, addr, 0);
+                tcg_gen_qemu_st32(tmp, addr, dc->cring);
 
                 gen_set_label(label);
                 tcg_temp_free(addr);
@@ -1345,7 +1362,7 @@ static void disas_xtensa_insn(DisasContext *dc)
 #define gen_narrow_load_store(type) do { \
             TCGv_i32 addr = tcg_temp_new_i32(); \
             tcg_gen_addi_i32(addr, cpu_R[RRRN_S], RRRN_R << 2); \
-            tcg_gen_qemu_##type(cpu_R[RRRN_T], addr, 0); \
+            tcg_gen_qemu_##type(cpu_R[RRRN_T], addr, dc->cring); \
             tcg_temp_free(addr); \
         } while (0)
 
@@ -1468,6 +1485,8 @@ static void gen_intermediate_code_internal(
     dc.singlestep_enabled = env->singlestep_enabled;
     dc.tb = tb;
     dc.pc = pc_start;
+    dc.ring = tb->flags & XTENSA_TBFLAG_RING_MASK;
+    dc.cring = (tb->flags & XTENSA_TBFLAG_EXCM) ? 0 : dc.ring;
     dc.is_jmp = DISAS_NEXT;
 
     init_sar_tracker(&dc);
commit 8ffc2d0d97a59b25b48d023838906d5850e73184
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Tue Sep 6 03:55:39 2011 +0400

    target-xtensa: implement CACHE group
    
    All operations in this group are no-ops, because cache ought to be
    transparent to applications. However cache may be abused, then we'll
    need to actually implement these opcodes.
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index 4f1c18e..7d383b3 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -1012,7 +1012,100 @@ static void disas_xtensa_insn(DisasContext *dc)
             break;
 
         case 7: /*CACHEc*/
-            TBD();
+            if (RRI8_T < 8) {
+                HAS_OPTION(XTENSA_OPTION_DCACHE);
+            }
+
+            switch (RRI8_T) {
+            case 0: /*DPFRc*/
+                break;
+
+            case 1: /*DPFWc*/
+                break;
+
+            case 2: /*DPFROc*/
+                break;
+
+            case 3: /*DPFWOc*/
+                break;
+
+            case 4: /*DHWBc*/
+                break;
+
+            case 5: /*DHWBIc*/
+                break;
+
+            case 6: /*DHIc*/
+                break;
+
+            case 7: /*DIIc*/
+                break;
+
+            case 8: /*DCEc*/
+                switch (OP1) {
+                case 0: /*DPFLl*/
+                    HAS_OPTION(XTENSA_OPTION_DCACHE_INDEX_LOCK);
+                    break;
+
+                case 2: /*DHUl*/
+                    HAS_OPTION(XTENSA_OPTION_DCACHE_INDEX_LOCK);
+                    break;
+
+                case 3: /*DIUl*/
+                    HAS_OPTION(XTENSA_OPTION_DCACHE_INDEX_LOCK);
+                    break;
+
+                case 4: /*DIWBc*/
+                    HAS_OPTION(XTENSA_OPTION_DCACHE);
+                    break;
+
+                case 5: /*DIWBIc*/
+                    HAS_OPTION(XTENSA_OPTION_DCACHE);
+                    break;
+
+                default: /*reserved*/
+                    RESERVED();
+                    break;
+
+                }
+                break;
+
+            case 12: /*IPFc*/
+                HAS_OPTION(XTENSA_OPTION_ICACHE);
+                break;
+
+            case 13: /*ICEc*/
+                switch (OP1) {
+                case 0: /*IPFLl*/
+                    HAS_OPTION(XTENSA_OPTION_ICACHE_INDEX_LOCK);
+                    break;
+
+                case 2: /*IHUl*/
+                    HAS_OPTION(XTENSA_OPTION_ICACHE_INDEX_LOCK);
+                    break;
+
+                case 3: /*IIUl*/
+                    HAS_OPTION(XTENSA_OPTION_ICACHE_INDEX_LOCK);
+                    break;
+
+                default: /*reserved*/
+                    RESERVED();
+                    break;
+                }
+                break;
+
+            case 14: /*IHIc*/
+                HAS_OPTION(XTENSA_OPTION_ICACHE);
+                break;
+
+            case 15: /*IIIc*/
+                HAS_OPTION(XTENSA_OPTION_ICACHE);
+                break;
+
+            default: /*reserved*/
+                RESERVED();
+                break;
+            }
             break;
 
         case 9: /*L16SI*/
commit 28067b2288c70d7ce9a3735a777b73a627c71a1f
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Tue Sep 6 03:55:38 2011 +0400

    target-xtensa: implement SYNC group
    
    All operations in this group are no-ops, because there are no delayed
    side effects.
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index 8f92dfb..4f1c18e 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -429,7 +429,36 @@ static void disas_xtensa_insn(DisasContext *dc)
                     break;
 
                 case 2: /*SYNC*/
-                    TBD();
+                    switch (RRR_T) {
+                    case 0: /*ISYNC*/
+                        break;
+
+                    case 1: /*RSYNC*/
+                        break;
+
+                    case 2: /*ESYNC*/
+                        break;
+
+                    case 3: /*DSYNC*/
+                        break;
+
+                    case 8: /*EXCW*/
+                        HAS_OPTION(XTENSA_OPTION_EXCEPTION);
+                        break;
+
+                    case 12: /*MEMW*/
+                        break;
+
+                    case 13: /*EXTW*/
+                        break;
+
+                    case 15: /*NOP*/
+                        break;
+
+                    default: /*reserved*/
+                        RESERVED();
+                        break;
+                    }
                     break;
 
                 case 3: /*RFEIx*/
commit 91a5bb76d47e1b06f0b7b67cae8497d8efc6ab87
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Tue Sep 6 03:55:37 2011 +0400

    target-xtensa: mark reserved and TBD opcodes
    
    Reserved opcodes must generate illegal instruction exception. Usually
    they signal emulation quality problems.
    Not implemented opcodes are good to see.
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index dd89017..8f92dfb 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -267,6 +267,14 @@ static void disas_xtensa_insn(DisasContext *dc)
         } \
     } while (0)
 
+#define TBD() qemu_log("TBD(pc = %08x): %s:%d\n", dc->pc, __FILE__, __LINE__)
+#define RESERVED() do { \
+        qemu_log("RESERVED(pc = %08x, %02x%02x%02x): %s:%d\n", \
+                dc->pc, b0, b1, b2, __FILE__, __LINE__); \
+        goto invalid_opcode; \
+    } while (0)
+
+
 #ifdef TARGET_WORDS_BIGENDIAN
 #define OP0 (((b0) & 0xf0) >> 4)
 #define OP1 (((b2) & 0xf0) >> 4)
@@ -367,9 +375,11 @@ static void disas_xtensa_insn(DisasContext *dc)
                 case 0: /*SNM0*/
                     switch (CALLX_M) {
                     case 0: /*ILL*/
+                        TBD();
                         break;
 
                     case 1: /*reserved*/
+                        RESERVED();
                         break;
 
                     case 2: /*JR*/
@@ -381,9 +391,11 @@ static void disas_xtensa_insn(DisasContext *dc)
 
                         case 1: /*RETWw*/
                             HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                            TBD();
                             break;
 
                         case 3: /*reserved*/
+                            RESERVED();
                             break;
                         }
                         break;
@@ -404,6 +416,7 @@ static void disas_xtensa_insn(DisasContext *dc)
                         case 2: /*CALLX8w*/
                         case 3: /*CALLX12w*/
                             HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                            TBD();
                             break;
                         }
                         break;
@@ -412,12 +425,59 @@ static void disas_xtensa_insn(DisasContext *dc)
 
                 case 1: /*MOVSPw*/
                     HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                    TBD();
                     break;
 
                 case 2: /*SYNC*/
+                    TBD();
+                    break;
+
+                case 3: /*RFEIx*/
+                    TBD();
+                    break;
+
+                case 4: /*BREAKx*/
+                    HAS_OPTION(XTENSA_OPTION_EXCEPTION);
+                    TBD();
+                    break;
+
+                case 5: /*SYSCALLx*/
+                    HAS_OPTION(XTENSA_OPTION_EXCEPTION);
+                    TBD();
+                    break;
+
+                case 6: /*RSILx*/
+                    HAS_OPTION(XTENSA_OPTION_INTERRUPT);
+                    TBD();
+                    break;
+
+                case 7: /*WAITIx*/
+                    HAS_OPTION(XTENSA_OPTION_INTERRUPT);
+                    TBD();
+                    break;
+
+                case 8: /*ANY4p*/
+                    HAS_OPTION(XTENSA_OPTION_BOOLEAN);
+                    TBD();
+                    break;
+
+                case 9: /*ALL4p*/
+                    HAS_OPTION(XTENSA_OPTION_BOOLEAN);
+                    TBD();
                     break;
 
-                case 3:
+                case 10: /*ANY8p*/
+                    HAS_OPTION(XTENSA_OPTION_BOOLEAN);
+                    TBD();
+                    break;
+
+                case 11: /*ALL8p*/
+                    HAS_OPTION(XTENSA_OPTION_BOOLEAN);
+                    TBD();
+                    break;
+
+                default: /*reserved*/
+                    RESERVED();
                     break;
 
                 }
@@ -473,13 +533,16 @@ static void disas_xtensa_insn(DisasContext *dc)
                     break;
 
                 case 6: /*RER*/
+                    TBD();
                     break;
 
                 case 7: /*WER*/
+                    TBD();
                     break;
 
                 case 8: /*ROTWw*/
                     HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                    TBD();
                     break;
 
                 case 14: /*NSAu*/
@@ -493,11 +556,13 @@ static void disas_xtensa_insn(DisasContext *dc)
                     break;
 
                 default: /*reserved*/
+                    RESERVED();
                     break;
                 }
                 break;
 
             case 5: /*TLB*/
+                TBD();
                 break;
 
             case 6: /*RT0*/
@@ -518,11 +583,13 @@ static void disas_xtensa_insn(DisasContext *dc)
                     break;
 
                 default: /*reserved*/
+                    RESERVED();
                     break;
                 }
                 break;
 
             case 7: /*reserved*/
+                RESERVED();
                 break;
 
             case 8: /*ADD*/
@@ -582,6 +649,9 @@ static void disas_xtensa_insn(DisasContext *dc)
                     gen_rsr(dc, cpu_R[RRR_T], RSR_SR);
                     gen_wsr(dc, RSR_SR, tmp);
                     tcg_temp_free(tmp);
+                    if (!sregnames[RSR_SR]) {
+                        TBD();
+                    }
                 }
                 break;
 
@@ -671,21 +741,29 @@ static void disas_xtensa_insn(DisasContext *dc)
                 break;
 
             default: /*reserved*/
+                RESERVED();
                 break;
             }
             break;
 
         case 2: /*RST2*/
+            TBD();
             break;
 
         case 3: /*RST3*/
             switch (OP2) {
             case 0: /*RSR*/
                 gen_rsr(dc, cpu_R[RRR_T], RSR_SR);
+                if (!sregnames[RSR_SR]) {
+                    TBD();
+                }
                 break;
 
             case 1: /*WSR*/
                 gen_wsr(dc, RSR_SR, cpu_R[RRR_T]);
+                if (!sregnames[RSR_SR]) {
+                    TBD();
+                }
                 break;
 
             case 2: /*SEXTu*/
@@ -778,10 +856,12 @@ static void disas_xtensa_insn(DisasContext *dc)
 
             case 12: /*MOVFp*/
                 HAS_OPTION(XTENSA_OPTION_BOOLEAN);
+                TBD();
                 break;
 
             case 13: /*MOVTp*/
                 HAS_OPTION(XTENSA_OPTION_BOOLEAN);
+                TBD();
                 break;
 
             case 14: /*RUR*/
@@ -791,6 +871,7 @@ static void disas_xtensa_insn(DisasContext *dc)
                         tcg_gen_mov_i32(cpu_R[RRR_R], cpu_UR[st]);
                     } else {
                         qemu_log("RUR %d not implemented, ", st);
+                        TBD();
                     }
                 }
                 break;
@@ -801,6 +882,7 @@ static void disas_xtensa_insn(DisasContext *dc)
                         tcg_gen_mov_i32(cpu_UR[RSR_SR], cpu_R[RRR_T]);
                     } else {
                         qemu_log("WUR %d not implemented, ", RSR_SR);
+                        TBD();
                     }
                 }
                 break;
@@ -822,27 +904,34 @@ static void disas_xtensa_insn(DisasContext *dc)
             break;
 
         case 6: /*CUST0*/
+            RESERVED();
             break;
 
         case 7: /*CUST1*/
+            RESERVED();
             break;
 
         case 8: /*LSCXp*/
             HAS_OPTION(XTENSA_OPTION_COPROCESSOR);
+            TBD();
             break;
 
         case 9: /*LSC4*/
+            TBD();
             break;
 
         case 10: /*FP0*/
             HAS_OPTION(XTENSA_OPTION_FP_COPROCESSOR);
+            TBD();
             break;
 
         case 11: /*FP1*/
             HAS_OPTION(XTENSA_OPTION_FP_COPROCESSOR);
+            TBD();
             break;
 
         default: /*reserved*/
+            RESERVED();
             break;
         }
         break;
@@ -894,6 +983,7 @@ static void disas_xtensa_insn(DisasContext *dc)
             break;
 
         case 7: /*CACHEc*/
+            TBD();
             break;
 
         case 9: /*L16SI*/
@@ -946,6 +1036,7 @@ static void disas_xtensa_insn(DisasContext *dc)
             break;
 
         default: /*reserved*/
+            RESERVED();
             break;
         }
         break;
@@ -953,10 +1044,12 @@ static void disas_xtensa_insn(DisasContext *dc)
 
     case 3: /*LSCIp*/
         HAS_OPTION(XTENSA_OPTION_COPROCESSOR);
+        TBD();
         break;
 
     case 4: /*MAC16d*/
         HAS_OPTION(XTENSA_OPTION_MAC16);
+        TBD();
         break;
 
     case 5: /*CALLN*/
@@ -970,6 +1063,7 @@ static void disas_xtensa_insn(DisasContext *dc)
         case 2: /*CALL8w*/
         case 3: /*CALL12w*/
             HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+            TBD();
             break;
         }
         break;
@@ -1012,28 +1106,35 @@ static void disas_xtensa_insn(DisasContext *dc)
             switch (BRI8_M) {
             case 0: /*ENTRYw*/
                 HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                TBD();
                 break;
 
             case 1: /*B1*/
                 switch (BRI8_R) {
                 case 0: /*BFp*/
                     HAS_OPTION(XTENSA_OPTION_BOOLEAN);
+                    TBD();
                     break;
 
                 case 1: /*BTp*/
                     HAS_OPTION(XTENSA_OPTION_BOOLEAN);
+                    TBD();
                     break;
 
                 case 8: /*LOOP*/
+                    TBD();
                     break;
 
                 case 9: /*LOOPNEZ*/
+                    TBD();
                     break;
 
                 case 10: /*LOOPGTZ*/
+                    TBD();
                     break;
 
                 default: /*reserved*/
+                    RESERVED();
                     break;
 
                 }
@@ -1169,28 +1270,35 @@ static void disas_xtensa_insn(DisasContext *dc)
                 break;
 
             case 1: /*RETW.Nn*/
+                HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                TBD();
                 break;
 
             case 2: /*BREAK.Nn*/
+                TBD();
                 break;
 
             case 3: /*NOP.Nn*/
                 break;
 
             case 6: /*ILL.Nn*/
+                TBD();
                 break;
 
             default: /*reserved*/
+                RESERVED();
                 break;
             }
             break;
 
         default: /*reserved*/
+            RESERVED();
             break;
         }
         break;
 
     default: /*reserved*/
+        RESERVED();
         break;
     }
 
commit 809377aa52de87cb0cec987e614292c5d47f3d10
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Tue Sep 6 03:55:36 2011 +0400

    target-xtensa: implement LSAI group
    
    - base + offset load/store operations for 1/2/4 byte values;
    - cache operations (not implemented);
    - multiprocessor synchronization operations.
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index f756b43..ac9bbb4 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -107,6 +107,7 @@ enum {
 
 enum {
     SAR = 3,
+    SCOMPARE1 = 12,
 };
 
 typedef struct XtensaConfig {
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index fd18950..dd89017 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -64,6 +64,7 @@ static TCGv_i32 cpu_UR[256];
 
 static const char * const sregnames[256] = {
     [SAR] = "SAR",
+    [SCOMPARE1] = "SCOMPARE1",
 };
 
 static const char * const uregnames[256] = {
@@ -860,7 +861,95 @@ static void disas_xtensa_insn(DisasContext *dc)
         break;
 
     case 2: /*LSAI*/
+#define gen_load_store(type, shift) do { \
+            TCGv_i32 addr = tcg_temp_new_i32(); \
+            tcg_gen_addi_i32(addr, cpu_R[RRI8_S], RRI8_IMM8 << shift); \
+            tcg_gen_qemu_##type(cpu_R[RRI8_T], addr, 0); \
+            tcg_temp_free(addr); \
+        } while (0)
+
+        switch (RRI8_R) {
+        case 0: /*L8UI*/
+            gen_load_store(ld8u, 0);
+            break;
+
+        case 1: /*L16UI*/
+            gen_load_store(ld16u, 1);
+            break;
+
+        case 2: /*L32I*/
+            gen_load_store(ld32u, 2);
+            break;
+
+        case 4: /*S8I*/
+            gen_load_store(st8, 0);
+            break;
+
+        case 5: /*S16I*/
+            gen_load_store(st16, 1);
+            break;
+
+        case 6: /*S32I*/
+            gen_load_store(st32, 2);
+            break;
+
+        case 7: /*CACHEc*/
+            break;
+
+        case 9: /*L16SI*/
+            gen_load_store(ld16s, 1);
+            break;
+
+        case 10: /*MOVI*/
+            tcg_gen_movi_i32(cpu_R[RRI8_T],
+                    RRI8_IMM8 | (RRI8_S << 8) |
+                    ((RRI8_S & 0x8) ? 0xfffff000 : 0));
+            break;
+
+        case 11: /*L32AIy*/
+            HAS_OPTION(XTENSA_OPTION_MP_SYNCHRO);
+            gen_load_store(ld32u, 2); /*TODO acquire?*/
+            break;
+
+        case 12: /*ADDI*/
+            tcg_gen_addi_i32(cpu_R[RRI8_T], cpu_R[RRI8_S], RRI8_IMM8_SE);
+            break;
+
+        case 13: /*ADDMI*/
+            tcg_gen_addi_i32(cpu_R[RRI8_T], cpu_R[RRI8_S], RRI8_IMM8_SE << 8);
+            break;
+
+        case 14: /*S32C1Iy*/
+            HAS_OPTION(XTENSA_OPTION_MP_SYNCHRO);
+            {
+                int label = gen_new_label();
+                TCGv_i32 tmp = tcg_temp_local_new_i32();
+                TCGv_i32 addr = tcg_temp_local_new_i32();
+
+                tcg_gen_mov_i32(tmp, cpu_R[RRI8_T]);
+                tcg_gen_addi_i32(addr, cpu_R[RRI8_S], RRI8_IMM8 << 2);
+                tcg_gen_qemu_ld32u(cpu_R[RRI8_T], addr, 0);
+                tcg_gen_brcond_i32(TCG_COND_NE, cpu_R[RRI8_T],
+                        cpu_SR[SCOMPARE1], label);
+
+                tcg_gen_qemu_st32(tmp, addr, 0);
+
+                gen_set_label(label);
+                tcg_temp_free(addr);
+                tcg_temp_free(tmp);
+            }
+            break;
+
+        case 15: /*S32RIy*/
+            HAS_OPTION(XTENSA_OPTION_MP_SYNCHRO);
+            gen_load_store(st32, 2); /*TODO release?*/
+            break;
+
+        default: /*reserved*/
+            break;
+        }
         break;
+#undef gen_load_store
 
     case 3: /*LSCIp*/
         HAS_OPTION(XTENSA_OPTION_COPROCESSOR);
commit 3580ecad0acf25a28464c145f2c74a929d0e57b1
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Tue Sep 6 03:55:35 2011 +0400

    target-xtensa: implement shifts (ST1 and RST1 groups)
    
    - ST1: SAR (shift amount special register) manipulation, NSA(U);
    - RST1: shifts, 16-bit multiplication.
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index 8c3fe2e..f756b43 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -105,6 +105,10 @@ enum {
     FSR = 233,
 };
 
+enum {
+    SAR = 3,
+};
+
 typedef struct XtensaConfig {
     const char *name;
     uint64_t options;
diff --git a/target-xtensa/helpers.h b/target-xtensa/helpers.h
index c298d74..976c8d8 100644
--- a/target-xtensa/helpers.h
+++ b/target-xtensa/helpers.h
@@ -1,5 +1,7 @@
 #include "def-helper.h"
 
 DEF_HELPER_1(exception, void, i32)
+DEF_HELPER_1(nsa, i32, i32)
+DEF_HELPER_1(nsau, i32, i32)
 
 #include "def-helper.h"
diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c
index 0392fbe..c1cfd2e 100644
--- a/target-xtensa/op_helper.c
+++ b/target-xtensa/op_helper.c
@@ -28,6 +28,7 @@
 #include "cpu.h"
 #include "dyngen-exec.h"
 #include "helpers.h"
+#include "host-utils.h"
 
 #define MMUSUFFIX _mmu
 
@@ -57,3 +58,16 @@ void HELPER(exception)(uint32_t excp)
     env->exception_index = excp;
     cpu_loop_exit(env);
 }
+
+uint32_t HELPER(nsa)(uint32_t v)
+{
+    if (v & 0x80000000) {
+        v = ~v;
+    }
+    return v ? clz32(v) - 1 : 31;
+}
+
+uint32_t HELPER(nsau)(uint32_t v)
+{
+    return v ? clz32(v) : 32;
+}
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index 9a19ca8..fd18950 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -47,6 +47,11 @@ typedef struct DisasContext {
     uint32_t next_pc;
     int is_jmp;
     int singlestep_enabled;
+
+    bool sar_5bit;
+    bool sar_m32_5bit;
+    bool sar_m32_allocated;
+    TCGv_i32 sar_m32;
 } DisasContext;
 
 static TCGv_ptr cpu_env;
@@ -58,6 +63,7 @@ static TCGv_i32 cpu_UR[256];
 #include "gen-icount.h"
 
 static const char * const sregnames[256] = {
+    [SAR] = "SAR",
 };
 
 static const char * const uregnames[256] = {
@@ -110,6 +116,44 @@ static inline bool option_enabled(DisasContext *dc, int opt)
     return xtensa_option_enabled(dc->config, opt);
 }
 
+static void init_sar_tracker(DisasContext *dc)
+{
+    dc->sar_5bit = false;
+    dc->sar_m32_5bit = false;
+    dc->sar_m32_allocated = false;
+}
+
+static void reset_sar_tracker(DisasContext *dc)
+{
+    if (dc->sar_m32_allocated) {
+        tcg_temp_free(dc->sar_m32);
+    }
+}
+
+static void gen_right_shift_sar(DisasContext *dc, TCGv_i32 sa)
+{
+    tcg_gen_andi_i32(cpu_SR[SAR], sa, 0x1f);
+    if (dc->sar_m32_5bit) {
+        tcg_gen_discard_i32(dc->sar_m32);
+    }
+    dc->sar_5bit = true;
+    dc->sar_m32_5bit = false;
+}
+
+static void gen_left_shift_sar(DisasContext *dc, TCGv_i32 sa)
+{
+    TCGv_i32 tmp = tcg_const_i32(32);
+    if (!dc->sar_m32_allocated) {
+        dc->sar_m32 = tcg_temp_local_new_i32();
+        dc->sar_m32_allocated = true;
+    }
+    tcg_gen_andi_i32(dc->sar_m32, sa, 0x1f);
+    tcg_gen_sub_i32(cpu_SR[SAR], tmp, dc->sar_m32);
+    dc->sar_5bit = false;
+    dc->sar_m32_5bit = true;
+    tcg_temp_free(tmp);
+}
+
 static void gen_exception(int excp)
 {
     TCGv_i32 tmp = tcg_const_i32(excp);
@@ -184,10 +228,21 @@ static void gen_rsr(DisasContext *dc, TCGv_i32 d, uint32_t sr)
     }
 }
 
+static void gen_wsr_sar(DisasContext *dc, uint32_t sr, TCGv_i32 s)
+{
+    tcg_gen_andi_i32(cpu_SR[sr], s, 0x3f);
+    if (dc->sar_m32_5bit) {
+        tcg_gen_discard_i32(dc->sar_m32);
+    }
+    dc->sar_5bit = false;
+    dc->sar_m32_5bit = false;
+}
+
 static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s)
 {
     static void (* const wsr_handler[256])(DisasContext *dc,
             uint32_t sr, TCGv_i32 v) = {
+        [SAR] = gen_wsr_sar,
     };
 
     if (sregnames[sr]) {
@@ -380,6 +435,65 @@ static void disas_xtensa_insn(DisasContext *dc)
                 break;
 
             case 4: /*ST1*/
+                switch (RRR_R) {
+                case 0: /*SSR*/
+                    gen_right_shift_sar(dc, cpu_R[RRR_S]);
+                    break;
+
+                case 1: /*SSL*/
+                    gen_left_shift_sar(dc, cpu_R[RRR_S]);
+                    break;
+
+                case 2: /*SSA8L*/
+                    {
+                        TCGv_i32 tmp = tcg_temp_new_i32();
+                        tcg_gen_shli_i32(tmp, cpu_R[RRR_S], 3);
+                        gen_right_shift_sar(dc, tmp);
+                        tcg_temp_free(tmp);
+                    }
+                    break;
+
+                case 3: /*SSA8B*/
+                    {
+                        TCGv_i32 tmp = tcg_temp_new_i32();
+                        tcg_gen_shli_i32(tmp, cpu_R[RRR_S], 3);
+                        gen_left_shift_sar(dc, tmp);
+                        tcg_temp_free(tmp);
+                    }
+                    break;
+
+                case 4: /*SSAI*/
+                    {
+                        TCGv_i32 tmp = tcg_const_i32(
+                                RRR_S | ((RRR_T & 1) << 4));
+                        gen_right_shift_sar(dc, tmp);
+                        tcg_temp_free(tmp);
+                    }
+                    break;
+
+                case 6: /*RER*/
+                    break;
+
+                case 7: /*WER*/
+                    break;
+
+                case 8: /*ROTWw*/
+                    HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                    break;
+
+                case 14: /*NSAu*/
+                    HAS_OPTION(XTENSA_OPTION_MISC_OP);
+                    gen_helper_nsa(cpu_R[RRR_T], cpu_R[RRR_S]);
+                    break;
+
+                case 15: /*NSAUu*/
+                    HAS_OPTION(XTENSA_OPTION_MISC_OP);
+                    gen_helper_nsau(cpu_R[RRR_T], cpu_R[RRR_S]);
+                    break;
+
+                default: /*reserved*/
+                    break;
+                }
                 break;
 
             case 5: /*TLB*/
@@ -443,6 +557,121 @@ static void disas_xtensa_insn(DisasContext *dc)
             break;
 
         case 1: /*RST1*/
+            switch (OP2) {
+            case 0: /*SLLI*/
+            case 1:
+                tcg_gen_shli_i32(cpu_R[RRR_R], cpu_R[RRR_S],
+                        32 - (RRR_T | ((OP2 & 1) << 4)));
+                break;
+
+            case 2: /*SRAI*/
+            case 3:
+                tcg_gen_sari_i32(cpu_R[RRR_R], cpu_R[RRR_T],
+                        RRR_S | ((OP2 & 1) << 4));
+                break;
+
+            case 4: /*SRLI*/
+                tcg_gen_shri_i32(cpu_R[RRR_R], cpu_R[RRR_T], RRR_S);
+                break;
+
+            case 6: /*XSR*/
+                {
+                    TCGv_i32 tmp = tcg_temp_new_i32();
+                    tcg_gen_mov_i32(tmp, cpu_R[RRR_T]);
+                    gen_rsr(dc, cpu_R[RRR_T], RSR_SR);
+                    gen_wsr(dc, RSR_SR, tmp);
+                    tcg_temp_free(tmp);
+                }
+                break;
+
+                /*
+                 * Note: 64 bit ops are used here solely because SAR values
+                 * have range 0..63
+                 */
+#define gen_shift_reg(cmd, reg) do { \
+                    TCGv_i64 tmp = tcg_temp_new_i64(); \
+                    tcg_gen_extu_i32_i64(tmp, reg); \
+                    tcg_gen_##cmd##_i64(v, v, tmp); \
+                    tcg_gen_trunc_i64_i32(cpu_R[RRR_R], v); \
+                    tcg_temp_free_i64(v); \
+                    tcg_temp_free_i64(tmp); \
+                } while (0)
+
+#define gen_shift(cmd) gen_shift_reg(cmd, cpu_SR[SAR])
+
+            case 8: /*SRC*/
+                {
+                    TCGv_i64 v = tcg_temp_new_i64();
+                    tcg_gen_concat_i32_i64(v, cpu_R[RRR_T], cpu_R[RRR_S]);
+                    gen_shift(shr);
+                }
+                break;
+
+            case 9: /*SRL*/
+                if (dc->sar_5bit) {
+                    tcg_gen_shr_i32(cpu_R[RRR_R], cpu_R[RRR_T], cpu_SR[SAR]);
+                } else {
+                    TCGv_i64 v = tcg_temp_new_i64();
+                    tcg_gen_extu_i32_i64(v, cpu_R[RRR_T]);
+                    gen_shift(shr);
+                }
+                break;
+
+            case 10: /*SLL*/
+                if (dc->sar_m32_5bit) {
+                    tcg_gen_shl_i32(cpu_R[RRR_R], cpu_R[RRR_S], dc->sar_m32);
+                } else {
+                    TCGv_i64 v = tcg_temp_new_i64();
+                    TCGv_i32 s = tcg_const_i32(32);
+                    tcg_gen_sub_i32(s, s, cpu_SR[SAR]);
+                    tcg_gen_andi_i32(s, s, 0x3f);
+                    tcg_gen_extu_i32_i64(v, cpu_R[RRR_S]);
+                    gen_shift_reg(shl, s);
+                    tcg_temp_free(s);
+                }
+                break;
+
+            case 11: /*SRA*/
+                if (dc->sar_5bit) {
+                    tcg_gen_sar_i32(cpu_R[RRR_R], cpu_R[RRR_T], cpu_SR[SAR]);
+                } else {
+                    TCGv_i64 v = tcg_temp_new_i64();
+                    tcg_gen_ext_i32_i64(v, cpu_R[RRR_T]);
+                    gen_shift(sar);
+                }
+                break;
+#undef gen_shift
+#undef gen_shift_reg
+
+            case 12: /*MUL16U*/
+                HAS_OPTION(XTENSA_OPTION_16_BIT_IMUL);
+                {
+                    TCGv_i32 v1 = tcg_temp_new_i32();
+                    TCGv_i32 v2 = tcg_temp_new_i32();
+                    tcg_gen_ext16u_i32(v1, cpu_R[RRR_S]);
+                    tcg_gen_ext16u_i32(v2, cpu_R[RRR_T]);
+                    tcg_gen_mul_i32(cpu_R[RRR_R], v1, v2);
+                    tcg_temp_free(v2);
+                    tcg_temp_free(v1);
+                }
+                break;
+
+            case 13: /*MUL16S*/
+                HAS_OPTION(XTENSA_OPTION_16_BIT_IMUL);
+                {
+                    TCGv_i32 v1 = tcg_temp_new_i32();
+                    TCGv_i32 v2 = tcg_temp_new_i32();
+                    tcg_gen_ext16s_i32(v1, cpu_R[RRR_S]);
+                    tcg_gen_ext16s_i32(v2, cpu_R[RRR_T]);
+                    tcg_gen_mul_i32(cpu_R[RRR_R], v1, v2);
+                    tcg_temp_free(v2);
+                    tcg_temp_free(v1);
+                }
+                break;
+
+            default: /*reserved*/
+                break;
+            }
             break;
 
         case 2: /*RST2*/
@@ -580,6 +809,15 @@ static void disas_xtensa_insn(DisasContext *dc)
 
         case 4: /*EXTUI*/
         case 5:
+            {
+                int shiftimm = RRR_S | (OP1 << 4);
+                int maskimm = (1 << (OP2 + 1)) - 1;
+
+                TCGv_i32 tmp = tcg_temp_new_i32();
+                tcg_gen_shri_i32(tmp, cpu_R[RRR_T], shiftimm);
+                tcg_gen_andi_i32(cpu_R[RRR_R], tmp, maskimm);
+                tcg_temp_free(tmp);
+            }
             break;
 
         case 6: /*CUST0*/
@@ -913,6 +1151,8 @@ static void gen_intermediate_code_internal(
     dc.pc = pc_start;
     dc.is_jmp = DISAS_NEXT;
 
+    init_sar_tracker(&dc);
+
     gen_icount_start();
 
     do {
@@ -947,6 +1187,8 @@ static void gen_intermediate_code_internal(
             dc.pc < next_page_start &&
             gen_opc_ptr < gen_opc_end);
 
+    reset_sar_tracker(&dc);
+
     if (dc.is_jmp == DISAS_NEXT) {
         gen_jumpi(&dc, dc.pc, 0);
     }
commit b8132eff891bce658b799df20748a1cb39f4dc06
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Tue Sep 6 03:55:34 2011 +0400

    target-xtensa: implement RST3 group
    
    - access to Special Registers (wsr, rsr);
    - access to User Registers (wur, rur);
    - misc. operations option (value clamp, sign extension, min, max);
    - conditional moves.
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index 358ea96..9a19ca8 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -167,6 +167,40 @@ static void gen_brcondi(DisasContext *dc, TCGCond cond,
     tcg_temp_free(tmp);
 }
 
+static void gen_rsr(DisasContext *dc, TCGv_i32 d, uint32_t sr)
+{
+    static void (* const rsr_handler[256])(DisasContext *dc,
+            TCGv_i32 d, uint32_t sr) = {
+    };
+
+    if (sregnames[sr]) {
+        if (rsr_handler[sr]) {
+            rsr_handler[sr](dc, d, sr);
+        } else {
+            tcg_gen_mov_i32(d, cpu_SR[sr]);
+        }
+    } else {
+        qemu_log("RSR %d not implemented, ", sr);
+    }
+}
+
+static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s)
+{
+    static void (* const wsr_handler[256])(DisasContext *dc,
+            uint32_t sr, TCGv_i32 v) = {
+    };
+
+    if (sregnames[sr]) {
+        if (wsr_handler[sr]) {
+            wsr_handler[sr](dc, sr, s);
+        } else {
+            tcg_gen_mov_i32(cpu_SR[sr], s);
+        }
+    } else {
+        qemu_log("WSR %d not implemented, ", sr);
+    }
+}
+
 static void disas_xtensa_insn(DisasContext *dc)
 {
 #define HAS_OPTION(opt) do { \
@@ -415,6 +449,133 @@ static void disas_xtensa_insn(DisasContext *dc)
             break;
 
         case 3: /*RST3*/
+            switch (OP2) {
+            case 0: /*RSR*/
+                gen_rsr(dc, cpu_R[RRR_T], RSR_SR);
+                break;
+
+            case 1: /*WSR*/
+                gen_wsr(dc, RSR_SR, cpu_R[RRR_T]);
+                break;
+
+            case 2: /*SEXTu*/
+                HAS_OPTION(XTENSA_OPTION_MISC_OP);
+                {
+                    int shift = 24 - RRR_T;
+
+                    if (shift == 24) {
+                        tcg_gen_ext8s_i32(cpu_R[RRR_R], cpu_R[RRR_S]);
+                    } else if (shift == 16) {
+                        tcg_gen_ext16s_i32(cpu_R[RRR_R], cpu_R[RRR_S]);
+                    } else {
+                        TCGv_i32 tmp = tcg_temp_new_i32();
+                        tcg_gen_shli_i32(tmp, cpu_R[RRR_S], shift);
+                        tcg_gen_sari_i32(cpu_R[RRR_R], tmp, shift);
+                        tcg_temp_free(tmp);
+                    }
+                }
+                break;
+
+            case 3: /*CLAMPSu*/
+                HAS_OPTION(XTENSA_OPTION_MISC_OP);
+                {
+                    TCGv_i32 tmp1 = tcg_temp_new_i32();
+                    TCGv_i32 tmp2 = tcg_temp_new_i32();
+                    int label = gen_new_label();
+
+                    tcg_gen_sari_i32(tmp1, cpu_R[RRR_S], 24 - RRR_T);
+                    tcg_gen_xor_i32(tmp2, tmp1, cpu_R[RRR_S]);
+                    tcg_gen_andi_i32(tmp2, tmp2, 0xffffffff << (RRR_T + 7));
+                    tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_S]);
+                    tcg_gen_brcondi_i32(TCG_COND_EQ, tmp2, 0, label);
+
+                    tcg_gen_sari_i32(tmp1, cpu_R[RRR_S], 31);
+                    tcg_gen_xori_i32(cpu_R[RRR_R], tmp1,
+                            0xffffffff >> (25 - RRR_T));
+
+                    gen_set_label(label);
+
+                    tcg_temp_free(tmp1);
+                    tcg_temp_free(tmp2);
+                }
+                break;
+
+            case 4: /*MINu*/
+            case 5: /*MAXu*/
+            case 6: /*MINUu*/
+            case 7: /*MAXUu*/
+                HAS_OPTION(XTENSA_OPTION_MISC_OP);
+                {
+                    static const TCGCond cond[] = {
+                        TCG_COND_LE,
+                        TCG_COND_GE,
+                        TCG_COND_LEU,
+                        TCG_COND_GEU
+                    };
+                    int label = gen_new_label();
+
+                    if (RRR_R != RRR_T) {
+                        tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_S]);
+                        tcg_gen_brcond_i32(cond[OP2 - 4],
+                                cpu_R[RRR_S], cpu_R[RRR_T], label);
+                        tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_T]);
+                    } else {
+                        tcg_gen_brcond_i32(cond[OP2 - 4],
+                                cpu_R[RRR_T], cpu_R[RRR_S], label);
+                        tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_S]);
+                    }
+                    gen_set_label(label);
+                }
+                break;
+
+            case 8: /*MOVEQZ*/
+            case 9: /*MOVNEZ*/
+            case 10: /*MOVLTZ*/
+            case 11: /*MOVGEZ*/
+                {
+                    static const TCGCond cond[] = {
+                        TCG_COND_NE,
+                        TCG_COND_EQ,
+                        TCG_COND_GE,
+                        TCG_COND_LT
+                    };
+                    int label = gen_new_label();
+                    tcg_gen_brcondi_i32(cond[OP2 - 8], cpu_R[RRR_T], 0, label);
+                    tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_S]);
+                    gen_set_label(label);
+                }
+                break;
+
+            case 12: /*MOVFp*/
+                HAS_OPTION(XTENSA_OPTION_BOOLEAN);
+                break;
+
+            case 13: /*MOVTp*/
+                HAS_OPTION(XTENSA_OPTION_BOOLEAN);
+                break;
+
+            case 14: /*RUR*/
+                {
+                    int st = (RRR_S << 4) + RRR_T;
+                    if (uregnames[st]) {
+                        tcg_gen_mov_i32(cpu_R[RRR_R], cpu_UR[st]);
+                    } else {
+                        qemu_log("RUR %d not implemented, ", st);
+                    }
+                }
+                break;
+
+            case 15: /*WUR*/
+                {
+                    if (uregnames[RSR_SR]) {
+                        tcg_gen_mov_i32(cpu_UR[RSR_SR], cpu_R[RRR_T]);
+                    } else {
+                        qemu_log("WUR %d not implemented, ", RSR_SR);
+                    }
+                }
+                break;
+
+            }
             break;
 
         case 4: /*EXTUI*/
commit 2af3da91839c04a5d73643b4eacce4cd93b9d428
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Tue Sep 6 03:55:33 2011 +0400

    target-xtensa: add special and user registers
    
    Special Registers hold the majority of the state added to the processor
    by the options. See ISA, 5.3 for details.
    
    User Registers hold state added in support of designer's TIE and in some
    cases of options that Tensilica provides. See ISA, 5.4 for details.
    
    Only registers mapped in sregnames or uregnames are considered valid.
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index c323891..8c3fe2e 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -99,6 +99,12 @@ enum {
     XTENSA_OPTION_TRACE_PORT,
 };
 
+enum {
+    THREADPTR = 231,
+    FCR = 232,
+    FSR = 233,
+};
+
 typedef struct XtensaConfig {
     const char *name;
     uint64_t options;
@@ -109,6 +115,7 @@ typedef struct CPUXtensaState {
     uint32_t regs[16];
     uint32_t pc;
     uint32_t sregs[256];
+    uint32_t uregs[256];
 
     CPU_COMMON
 } CPUXtensaState;
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index 78fffc5..358ea96 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -52,9 +52,20 @@ typedef struct DisasContext {
 static TCGv_ptr cpu_env;
 static TCGv_i32 cpu_pc;
 static TCGv_i32 cpu_R[16];
+static TCGv_i32 cpu_SR[256];
+static TCGv_i32 cpu_UR[256];
 
 #include "gen-icount.h"
 
+static const char * const sregnames[256] = {
+};
+
+static const char * const uregnames[256] = {
+    [THREADPTR] = "THREADPTR",
+    [FCR] = "FCR",
+    [FSR] = "FSR",
+};
+
 void xtensa_translate_init(void)
 {
     static const char * const regnames[] = {
@@ -74,6 +85,22 @@ void xtensa_translate_init(void)
                 offsetof(CPUState, regs[i]),
                 regnames[i]);
     }
+
+    for (i = 0; i < 256; ++i) {
+        if (sregnames[i]) {
+            cpu_SR[i] = tcg_global_mem_new_i32(TCG_AREG0,
+                    offsetof(CPUState, sregs[i]),
+                    sregnames[i]);
+        }
+    }
+
+    for (i = 0; i < 256; ++i) {
+        if (uregnames[i]) {
+            cpu_UR[i] = tcg_global_mem_new_i32(TCG_AREG0,
+                    offsetof(CPUState, uregs[i]),
+                    uregnames[i]);
+        }
+    }
 #define GEN_HELPER 2
 #include "helpers.h"
 }
@@ -784,9 +811,27 @@ void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
 void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
         int flags)
 {
-    int i;
+    int i, j;
+
+    cpu_fprintf(f, "PC=%08x\n\n", env->pc);
+
+    for (i = j = 0; i < 256; ++i) {
+        if (sregnames[i]) {
+            cpu_fprintf(f, "%s=%08x%c", sregnames[i], env->sregs[i],
+                    (j++ % 4) == 3 ? '\n' : ' ');
+        }
+    }
+
+    cpu_fprintf(f, (j % 4) == 0 ? "\n" : "\n\n");
+
+    for (i = j = 0; i < 256; ++i) {
+        if (uregnames[i]) {
+            cpu_fprintf(f, "%s=%08x%c", uregnames[i], env->uregs[i],
+                    (j++ % 4) == 3 ? '\n' : ' ');
+        }
+    }
 
-    cpu_fprintf(f, "PC=%08x\n", env->pc);
+    cpu_fprintf(f, (j % 4) == 0 ? "\n" : "\n\n");
 
     for (i = 0; i < 16; ++i) {
         cpu_fprintf(f, "A%02d=%08x%c", i, env->regs[i],
commit 5da4a6a8c5271234fdc2ab53b80cf7a23952849b
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Tue Sep 6 03:55:32 2011 +0400

    target-xtensa: implement JX/RET0/CALLX
    
    Group SNM0 (indirect jumps and calls).
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index 9e26a65..78fffc5 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -248,6 +248,49 @@ static void disas_xtensa_insn(DisasContext *dc)
 
                 switch (RRR_R) {
                 case 0: /*SNM0*/
+                    switch (CALLX_M) {
+                    case 0: /*ILL*/
+                        break;
+
+                    case 1: /*reserved*/
+                        break;
+
+                    case 2: /*JR*/
+                        switch (CALLX_N) {
+                        case 0: /*RET*/
+                        case 2: /*JX*/
+                            gen_jump(dc, cpu_R[CALLX_S]);
+                            break;
+
+                        case 1: /*RETWw*/
+                            HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                            break;
+
+                        case 3: /*reserved*/
+                            break;
+                        }
+                        break;
+
+                    case 3: /*CALLX*/
+                        switch (CALLX_N) {
+                        case 0: /*CALLX0*/
+                            {
+                                TCGv_i32 tmp = tcg_temp_new_i32();
+                                tcg_gen_mov_i32(tmp, cpu_R[CALLX_S]);
+                                tcg_gen_movi_i32(cpu_R[0], dc->next_pc);
+                                gen_jump(dc, tmp);
+                                tcg_temp_free(tmp);
+                            }
+                            break;
+
+                        case 1: /*CALLX4w*/
+                        case 2: /*CALLX8w*/
+                        case 3: /*CALLX12w*/
+                            HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                            break;
+                        }
+                        break;
+                    }
                     break;
 
                 case 1: /*MOVSPw*/
commit bd57fb91ae15acea8c17459556220d6454a1e389
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Tue Sep 6 03:55:31 2011 +0400

    target-xtensa: implement conditional jumps
    
    - BZ (comparison to zero);
    - BI0 (comparison to signed immediate);
    - BI1 (comparison to unsigned immediate);
    - B (two registers comparison, bit sets comparison);
    - BEQZ.N/BNEZ.N (narrow comparison to zero).
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index 92547d2..9e26a65 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -121,6 +121,25 @@ static void gen_jumpi(DisasContext *dc, uint32_t dest, int slot)
     tcg_temp_free(tmp);
 }
 
+static void gen_brcond(DisasContext *dc, TCGCond cond,
+        TCGv_i32 t0, TCGv_i32 t1, uint32_t offset)
+{
+    int label = gen_new_label();
+
+    tcg_gen_brcond_i32(cond, t0, t1, label);
+    gen_jumpi(dc, dc->next_pc, 0);
+    gen_set_label(label);
+    gen_jumpi(dc, dc->pc + offset, 1);
+}
+
+static void gen_brcondi(DisasContext *dc, TCGCond cond,
+        TCGv_i32 t0, uint32_t t1, uint32_t offset)
+{
+    TCGv_i32 tmp = tcg_const_i32(t1);
+    gen_brcond(dc, cond, t0, tmp, offset);
+    tcg_temp_free(tmp);
+}
+
 static void disas_xtensa_insn(DisasContext *dc)
 {
 #define HAS_OPTION(opt) do { \
@@ -202,6 +221,14 @@ static void disas_xtensa_insn(DisasContext *dc)
     uint8_t b1 = ldub_code(dc->pc + 1);
     uint8_t b2 = ldub_code(dc->pc + 2);
 
+    static const uint32_t B4CONST[] = {
+        0xffffffff, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 16, 32, 64, 128, 256
+    };
+
+    static const uint32_t B4CONSTU[] = {
+        32768, 65536, 2, 3, 4, 5, 6, 7, 8, 10, 12, 16, 32, 64, 128, 256
+    };
+
     if (OP0 >= 8) {
         dc->next_pc = dc->pc + 2;
         HAS_OPTION(XTENSA_OPTION_CODE_DENSITY);
@@ -395,10 +422,143 @@ static void disas_xtensa_insn(DisasContext *dc)
             gen_jumpi(dc, dc->pc + 4 + CALL_OFFSET_SE, 0);
             break;
 
+        case 1: /*BZ*/
+            {
+                static const TCGCond cond[] = {
+                    TCG_COND_EQ, /*BEQZ*/
+                    TCG_COND_NE, /*BNEZ*/
+                    TCG_COND_LT, /*BLTZ*/
+                    TCG_COND_GE, /*BGEZ*/
+                };
+
+                gen_brcondi(dc, cond[BRI12_M & 3], cpu_R[BRI12_S], 0,
+                        4 + BRI12_IMM12_SE);
+            }
+            break;
+
+        case 2: /*BI0*/
+            {
+                static const TCGCond cond[] = {
+                    TCG_COND_EQ, /*BEQI*/
+                    TCG_COND_NE, /*BNEI*/
+                    TCG_COND_LT, /*BLTI*/
+                    TCG_COND_GE, /*BGEI*/
+                };
+
+                gen_brcondi(dc, cond[BRI8_M & 3],
+                        cpu_R[BRI8_S], B4CONST[BRI8_R], 4 + BRI8_IMM8_SE);
+            }
+            break;
+
+        case 3: /*BI1*/
+            switch (BRI8_M) {
+            case 0: /*ENTRYw*/
+                HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                break;
+
+            case 1: /*B1*/
+                switch (BRI8_R) {
+                case 0: /*BFp*/
+                    HAS_OPTION(XTENSA_OPTION_BOOLEAN);
+                    break;
+
+                case 1: /*BTp*/
+                    HAS_OPTION(XTENSA_OPTION_BOOLEAN);
+                    break;
+
+                case 8: /*LOOP*/
+                    break;
+
+                case 9: /*LOOPNEZ*/
+                    break;
+
+                case 10: /*LOOPGTZ*/
+                    break;
+
+                default: /*reserved*/
+                    break;
+
+                }
+                break;
+
+            case 2: /*BLTUI*/
+            case 3: /*BGEUI*/
+                gen_brcondi(dc, BRI8_M == 2 ? TCG_COND_LTU : TCG_COND_GEU,
+                        cpu_R[BRI8_S], B4CONSTU[BRI8_R], 4 + BRI8_IMM8_SE);
+                break;
+            }
+            break;
+
         }
         break;
 
     case 7: /*B*/
+        {
+            TCGCond eq_ne = (RRI8_R & 8) ? TCG_COND_NE : TCG_COND_EQ;
+
+            switch (RRI8_R & 7) {
+            case 0: /*BNONE*/ /*BANY*/
+                {
+                    TCGv_i32 tmp = tcg_temp_new_i32();
+                    tcg_gen_and_i32(tmp, cpu_R[RRI8_S], cpu_R[RRI8_T]);
+                    gen_brcondi(dc, eq_ne, tmp, 0, 4 + RRI8_IMM8_SE);
+                    tcg_temp_free(tmp);
+                }
+                break;
+
+            case 1: /*BEQ*/ /*BNE*/
+            case 2: /*BLT*/ /*BGE*/
+            case 3: /*BLTU*/ /*BGEU*/
+                {
+                    static const TCGCond cond[] = {
+                        [1] = TCG_COND_EQ,
+                        [2] = TCG_COND_LT,
+                        [3] = TCG_COND_LTU,
+                        [9] = TCG_COND_NE,
+                        [10] = TCG_COND_GE,
+                        [11] = TCG_COND_GEU,
+                    };
+                    gen_brcond(dc, cond[RRI8_R], cpu_R[RRI8_S], cpu_R[RRI8_T],
+                            4 + RRI8_IMM8_SE);
+                }
+                break;
+
+            case 4: /*BALL*/ /*BNALL*/
+                {
+                    TCGv_i32 tmp = tcg_temp_new_i32();
+                    tcg_gen_and_i32(tmp, cpu_R[RRI8_S], cpu_R[RRI8_T]);
+                    gen_brcond(dc, eq_ne, tmp, cpu_R[RRI8_T],
+                            4 + RRI8_IMM8_SE);
+                    tcg_temp_free(tmp);
+                }
+                break;
+
+            case 5: /*BBC*/ /*BBS*/
+                {
+                    TCGv_i32 bit = tcg_const_i32(1);
+                    TCGv_i32 tmp = tcg_temp_new_i32();
+                    tcg_gen_andi_i32(tmp, cpu_R[RRI8_T], 0x1f);
+                    tcg_gen_shl_i32(bit, bit, tmp);
+                    tcg_gen_and_i32(tmp, cpu_R[RRI8_S], bit);
+                    gen_brcondi(dc, eq_ne, tmp, 0, 4 + RRI8_IMM8_SE);
+                    tcg_temp_free(tmp);
+                    tcg_temp_free(bit);
+                }
+                break;
+
+            case 6: /*BBCI*/ /*BBSI*/
+            case 7:
+                {
+                    TCGv_i32 tmp = tcg_temp_new_i32();
+                    tcg_gen_andi_i32(tmp, cpu_R[RRI8_S],
+                            1 << (((RRI8_R & 1) << 4) | RRI8_T));
+                    gen_brcondi(dc, eq_ne, tmp, 0, 4 + RRI8_IMM8_SE);
+                    tcg_temp_free(tmp);
+                }
+                break;
+
+            }
+        }
         break;
 
 #define gen_narrow_load_store(type) do { \
@@ -431,6 +591,10 @@ static void disas_xtensa_insn(DisasContext *dc)
                     RRRN_R | (RRRN_T << 4) |
                     ((RRRN_T & 6) == 6 ? 0xffffff80 : 0));
         } else { /*BEQZ.Nn*/ /*BNEZ.Nn*/
+            TCGCond eq_ne = (RRRN_T & 4) ? TCG_COND_NE : TCG_COND_EQ;
+
+            gen_brcondi(dc, eq_ne, cpu_R[RRRN_S], 0,
+                    4 + (RRRN_R | ((RRRN_T & 3) << 4)));
         }
         break;
 
commit 7b039f741c03988058447694a605cf1df067106e
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Tue Sep 6 03:55:30 2011 +0400

    target-xtensa: add sample board
    
    Sample board and sample CPU core are used for debug and may be used for
    development of custom SoC emulators.
    
    This board has two fixed size memory regions for DTCM and ITCM and
    variable length SRAM region.
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/Makefile.target b/Makefile.target
index 2e94a63..7833dcc 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -369,6 +369,7 @@ obj-alpha-y = i8259.o mc146818rtc.o
 obj-alpha-y += vga.o cirrus_vga.o
 
 obj-xtensa-y += xtensa_pic.o
+obj-xtensa-y += xtensa_sample.o
 
 main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
 
diff --git a/hw/xtensa_sample.c b/hw/xtensa_sample.c
new file mode 100644
index 0000000..0aeb7c8
--- /dev/null
+++ b/hw/xtensa_sample.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "sysemu.h"
+#include "boards.h"
+#include "loader.h"
+#include "elf.h"
+#include "memory.h"
+#include "exec-memory.h"
+
+static void xtensa_sample_reset(void *env)
+{
+    cpu_reset(env);
+}
+
+static void xtensa_init(ram_addr_t ram_size,
+        const char *boot_device,
+        const char *kernel_filename, const char *kernel_cmdline,
+        const char *initrd_filename, const char *cpu_model)
+{
+    CPUState *env = NULL;
+    MemoryRegion *ram;
+    const size_t dram_size = 0x10000;
+    const size_t iram_size = 0x20000;
+    int n;
+
+    for (n = 0; n < smp_cpus; n++) {
+        env = cpu_init(cpu_model);
+        if (!env) {
+            fprintf(stderr, "Unable to find CPU definition\n");
+            exit(1);
+        }
+        qemu_register_reset(xtensa_sample_reset, env);
+    }
+
+    ram = g_malloc(sizeof(*ram));
+    memory_region_init_ram(ram, NULL, "xtensa.ram",
+            dram_size + iram_size + ram_size);
+    memory_region_add_subregion(get_system_memory(),
+            0x60000000 - dram_size - iram_size, ram);
+
+    if (kernel_filename) {
+        uint64_t elf_entry;
+        uint64_t elf_lowaddr;
+#ifdef TARGET_WORDS_BIGENDIAN
+        int success = load_elf(kernel_filename, NULL, NULL, &elf_entry,
+                &elf_lowaddr, NULL, 1, ELF_MACHINE, 0);
+#else
+        int success = load_elf(kernel_filename, NULL, NULL, &elf_entry,
+                &elf_lowaddr, NULL, 0, ELF_MACHINE, 0);
+#endif
+        if (success > 0) {
+            env->pc = elf_entry;
+        }
+    }
+}
+
+static void xtensa_sample_init(ram_addr_t ram_size,
+                     const char *boot_device,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename, const char *cpu_model)
+{
+    if (!cpu_model) {
+        cpu_model = "sample-xtensa-core";
+    }
+    xtensa_init(ram_size, boot_device, kernel_filename, kernel_cmdline,
+                  initrd_filename, cpu_model);
+}
+
+static QEMUMachine xtensa_sample_machine = {
+    .name = "sample-xtensa-machine",
+    .desc = "Sample Xtensa machine (sample Xtensa core)",
+    .init = xtensa_sample_init,
+    .max_cpus = 4,
+};
+
+static void xtensa_sample_machine_init(void)
+{
+    qemu_register_machine(&xtensa_sample_machine);
+}
+
+machine_init(xtensa_sample_machine_init);
commit f331fe5e5fc05fc4626e5dfe4be8ef62a7763b99
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Tue Sep 6 03:55:29 2011 +0400

    target-xtensa: implement RT0 group
    
    NEG and ABS are the only members of RT0 group.
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index 4dfca2b..92547d2 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -255,6 +255,25 @@ static void disas_xtensa_insn(DisasContext *dc)
                 break;
 
             case 6: /*RT0*/
+                switch (RRR_S) {
+                case 0: /*NEG*/
+                    tcg_gen_neg_i32(cpu_R[RRR_R], cpu_R[RRR_T]);
+                    break;
+
+                case 1: /*ABS*/
+                    {
+                        int label = gen_new_label();
+                        tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_T]);
+                        tcg_gen_brcondi_i32(
+                                TCG_COND_GE, cpu_R[RRR_R], 0, label);
+                        tcg_gen_neg_i32(cpu_R[RRR_R], cpu_R[RRR_T]);
+                        gen_set_label(label);
+                    }
+                    break;
+
+                default: /*reserved*/
+                    break;
+                }
                 break;
 
             case 7: /*reserved*/
commit 67882fd177389527510eb36b3f7712011a835545
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Tue Sep 6 03:55:28 2011 +0400

    target-xtensa: implement narrow instructions
    
    Instructions with op0 >= 8 are 2 bytes long, others are 3 bytes long.
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index 0524dc7..4dfca2b 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -106,6 +106,11 @@ static void gen_jump_slot(DisasContext *dc, TCGv dest, int slot)
     dc->is_jmp = DISAS_UPDATE;
 }
 
+static void gen_jump(DisasContext *dc, TCGv dest)
+{
+    gen_jump_slot(dc, dest, -1);
+}
+
 static void gen_jumpi(DisasContext *dc, uint32_t dest, int slot)
 {
     TCGv_i32 tmp = tcg_const_i32(dest);
@@ -377,22 +382,71 @@ static void disas_xtensa_insn(DisasContext *dc)
     case 7: /*B*/
         break;
 
+#define gen_narrow_load_store(type) do { \
+            TCGv_i32 addr = tcg_temp_new_i32(); \
+            tcg_gen_addi_i32(addr, cpu_R[RRRN_S], RRRN_R << 2); \
+            tcg_gen_qemu_##type(cpu_R[RRRN_T], addr, 0); \
+            tcg_temp_free(addr); \
+        } while (0)
+
     case 8: /*L32I.Nn*/
+        gen_narrow_load_store(ld32u);
         break;
 
     case 9: /*S32I.Nn*/
+        gen_narrow_load_store(st32);
         break;
+#undef gen_narrow_load_store
 
     case 10: /*ADD.Nn*/
+        tcg_gen_add_i32(cpu_R[RRRN_R], cpu_R[RRRN_S], cpu_R[RRRN_T]);
         break;
 
     case 11: /*ADDI.Nn*/
+        tcg_gen_addi_i32(cpu_R[RRRN_R], cpu_R[RRRN_S], RRRN_T ? RRRN_T : -1);
         break;
 
     case 12: /*ST2n*/
+        if (RRRN_T < 8) { /*MOVI.Nn*/
+            tcg_gen_movi_i32(cpu_R[RRRN_S],
+                    RRRN_R | (RRRN_T << 4) |
+                    ((RRRN_T & 6) == 6 ? 0xffffff80 : 0));
+        } else { /*BEQZ.Nn*/ /*BNEZ.Nn*/
+        }
         break;
 
     case 13: /*ST3n*/
+        switch (RRRN_R) {
+        case 0: /*MOV.Nn*/
+            tcg_gen_mov_i32(cpu_R[RRRN_T], cpu_R[RRRN_S]);
+            break;
+
+        case 15: /*S3*/
+            switch (RRRN_T) {
+            case 0: /*RET.Nn*/
+                gen_jump(dc, cpu_R[0]);
+                break;
+
+            case 1: /*RETW.Nn*/
+                break;
+
+            case 2: /*BREAK.Nn*/
+                break;
+
+            case 3: /*NOP.Nn*/
+                break;
+
+            case 6: /*ILL.Nn*/
+                break;
+
+            default: /*reserved*/
+                break;
+            }
+            break;
+
+        default: /*reserved*/
+            break;
+        }
         break;
 
     default: /*reserved*/
commit dedc5eae2324b3c4a6d25af2138396aa5dc3d9e0
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Tue Sep 6 03:55:27 2011 +0400

    target-xtensa: implement disas_xtensa_insn
    
    Set up disas_xtensa_insn switch structure, mark required options on high
    level groups. Implement arithmetic/bit logic/jump/call0.
    
    Implement code generation loop with single step/breakpoint checking.
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index a51ffc8..c323891 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -45,7 +45,67 @@
 #define TARGET_VIRT_ADDR_SPACE_BITS 32
 #define TARGET_PAGE_BITS 12
 
+enum {
+    /* Additional instructions */
+    XTENSA_OPTION_CODE_DENSITY,
+    XTENSA_OPTION_LOOP,
+    XTENSA_OPTION_EXTENDED_L32R,
+    XTENSA_OPTION_16_BIT_IMUL,
+    XTENSA_OPTION_32_BIT_IMUL,
+    XTENSA_OPTION_32_BIT_IDIV,
+    XTENSA_OPTION_MAC16,
+    XTENSA_OPTION_MISC_OP,
+    XTENSA_OPTION_COPROCESSOR,
+    XTENSA_OPTION_BOOLEAN,
+    XTENSA_OPTION_FP_COPROCESSOR,
+    XTENSA_OPTION_MP_SYNCHRO,
+    XTENSA_OPTION_CONDITIONAL_STORE,
+
+    /* Interrupts and exceptions */
+    XTENSA_OPTION_EXCEPTION,
+    XTENSA_OPTION_RELOCATABLE_VECTOR,
+    XTENSA_OPTION_UNALIGNED_EXCEPTION,
+    XTENSA_OPTION_INTERRUPT,
+    XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+    XTENSA_OPTION_TIMER_INTERRUPT,
+
+    /* Local memory */
+    XTENSA_OPTION_ICACHE,
+    XTENSA_OPTION_ICACHE_TEST,
+    XTENSA_OPTION_ICACHE_INDEX_LOCK,
+    XTENSA_OPTION_DCACHE,
+    XTENSA_OPTION_DCACHE_TEST,
+    XTENSA_OPTION_DCACHE_INDEX_LOCK,
+    XTENSA_OPTION_IRAM,
+    XTENSA_OPTION_IROM,
+    XTENSA_OPTION_DRAM,
+    XTENSA_OPTION_DROM,
+    XTENSA_OPTION_XLMI,
+    XTENSA_OPTION_HW_ALIGNMENT,
+    XTENSA_OPTION_MEMORY_ECC_PARITY,
+
+    /* Memory protection and translation */
+    XTENSA_OPTION_REGION_PROTECTION,
+    XTENSA_OPTION_REGION_TRANSLATION,
+    XTENSA_OPTION_MMU,
+
+    /* Other */
+    XTENSA_OPTION_WINDOWED_REGISTER,
+    XTENSA_OPTION_PROCESSOR_INTERFACE,
+    XTENSA_OPTION_MISC_SR,
+    XTENSA_OPTION_THREAD_POINTER,
+    XTENSA_OPTION_PROCESSOR_ID,
+    XTENSA_OPTION_DEBUG,
+    XTENSA_OPTION_TRACE_PORT,
+};
+
+typedef struct XtensaConfig {
+    const char *name;
+    uint64_t options;
+} XtensaConfig;
+
 typedef struct CPUXtensaState {
+    const XtensaConfig *config;
     uint32_t regs[16];
     uint32_t pc;
     uint32_t sregs[256];
@@ -66,6 +126,13 @@ void do_interrupt(CPUXtensaState *s);
 int cpu_xtensa_signal_handler(int host_signum, void *pinfo, void *puc);
 void xtensa_cpu_list(FILE *f, fprintf_function cpu_fprintf);
 
+#define XTENSA_OPTION_BIT(opt) (((uint64_t)1) << (opt))
+
+static inline bool xtensa_option_enabled(const XtensaConfig *config, int opt)
+{
+    return (config->options & XTENSA_OPTION_BIT(opt)) != 0;
+}
+
 static inline int cpu_mmu_index(CPUState *env)
 {
     return 0;
diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c
index dc30e00..c119fd0 100644
--- a/target-xtensa/helper.c
+++ b/target-xtensa/helper.c
@@ -39,12 +39,32 @@ void cpu_reset(CPUXtensaState *env)
     env->pc = 0;
 }
 
+static const XtensaConfig core_config[] = {
+    {
+        .name = "sample-xtensa-core",
+        .options = -1,
+    },
+};
+
 CPUXtensaState *cpu_xtensa_init(const char *cpu_model)
 {
     static int tcg_inited;
     CPUXtensaState *env;
+    const XtensaConfig *config = NULL;
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(core_config); ++i)
+        if (strcmp(core_config[i].name, cpu_model) == 0) {
+            config = core_config + i;
+            break;
+        }
+
+    if (config == NULL) {
+        return NULL;
+    }
 
     env = g_malloc0(sizeof(*env));
+    env->config = config;
     cpu_exec_init(env);
 
     if (!tcg_inited) {
@@ -59,8 +79,11 @@ CPUXtensaState *cpu_xtensa_init(const char *cpu_model)
 
 void xtensa_cpu_list(FILE *f, fprintf_function cpu_fprintf)
 {
-    cpu_fprintf(f, "Available CPUs:\n"
-            "  Xtensa core\n");
+    int i;
+    cpu_fprintf(f, "Available CPUs:\n");
+    for (i = 0; i < ARRAY_SIZE(core_config); ++i) {
+        cpu_fprintf(f, "  %s\n", core_config[i].name);
+    }
 }
 
 target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
diff --git a/target-xtensa/helpers.h b/target-xtensa/helpers.h
new file mode 100644
index 0000000..c298d74
--- /dev/null
+++ b/target-xtensa/helpers.h
@@ -0,0 +1,5 @@
+#include "def-helper.h"
+
+DEF_HELPER_1(exception, void, i32)
+
+#include "def-helper.h"
diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c
index aafa33d..0392fbe 100644
--- a/target-xtensa/op_helper.c
+++ b/target-xtensa/op_helper.c
@@ -27,6 +27,7 @@
 
 #include "cpu.h"
 #include "dyngen-exec.h"
+#include "helpers.h"
 
 #define MMUSUFFIX _mmu
 
@@ -50,3 +51,9 @@ void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
             PAGE_READ | PAGE_WRITE | PAGE_EXEC,
             mmu_idx, TARGET_PAGE_SIZE);
 }
+
+void HELPER(exception)(uint32_t excp)
+{
+    env->exception_index = excp;
+    cpu_loop_exit(env);
+}
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index 4f517d6..0524dc7 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -36,17 +36,469 @@
 #include "tcg-op.h"
 #include "qemu-log.h"
 
+#include "helpers.h"
+#define GEN_HELPER 1
+#include "helpers.h"
+
+typedef struct DisasContext {
+    const XtensaConfig *config;
+    TranslationBlock *tb;
+    uint32_t pc;
+    uint32_t next_pc;
+    int is_jmp;
+    int singlestep_enabled;
+} DisasContext;
+
+static TCGv_ptr cpu_env;
+static TCGv_i32 cpu_pc;
+static TCGv_i32 cpu_R[16];
+
+#include "gen-icount.h"
 
 void xtensa_translate_init(void)
 {
+    static const char * const regnames[] = {
+        "ar0", "ar1", "ar2", "ar3",
+        "ar4", "ar5", "ar6", "ar7",
+        "ar8", "ar9", "ar10", "ar11",
+        "ar12", "ar13", "ar14", "ar15",
+    };
+    int i;
+
+    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+    cpu_pc = tcg_global_mem_new_i32(TCG_AREG0,
+            offsetof(CPUState, pc), "pc");
+
+    for (i = 0; i < 16; i++) {
+        cpu_R[i] = tcg_global_mem_new_i32(TCG_AREG0,
+                offsetof(CPUState, regs[i]),
+                regnames[i]);
+    }
+#define GEN_HELPER 2
+#include "helpers.h"
+}
+
+static inline bool option_enabled(DisasContext *dc, int opt)
+{
+    return xtensa_option_enabled(dc->config, opt);
+}
+
+static void gen_exception(int excp)
+{
+    TCGv_i32 tmp = tcg_const_i32(excp);
+    gen_helper_exception(tmp);
+    tcg_temp_free(tmp);
+}
+
+static void gen_jump_slot(DisasContext *dc, TCGv dest, int slot)
+{
+    tcg_gen_mov_i32(cpu_pc, dest);
+    if (dc->singlestep_enabled) {
+        gen_exception(EXCP_DEBUG);
+    } else {
+        if (slot >= 0) {
+            tcg_gen_goto_tb(slot);
+            tcg_gen_exit_tb((tcg_target_long)dc->tb + slot);
+        } else {
+            tcg_gen_exit_tb(0);
+        }
+    }
+    dc->is_jmp = DISAS_UPDATE;
+}
+
+static void gen_jumpi(DisasContext *dc, uint32_t dest, int slot)
+{
+    TCGv_i32 tmp = tcg_const_i32(dest);
+    if (((dc->pc ^ dest) & TARGET_PAGE_MASK) != 0) {
+        slot = -1;
+    }
+    gen_jump_slot(dc, tmp, slot);
+    tcg_temp_free(tmp);
+}
+
+static void disas_xtensa_insn(DisasContext *dc)
+{
+#define HAS_OPTION(opt) do { \
+        if (!option_enabled(dc, opt)) { \
+            qemu_log("Option %d is not enabled %s:%d\n", \
+                    (opt), __FILE__, __LINE__); \
+            goto invalid_opcode; \
+        } \
+    } while (0)
+
+#ifdef TARGET_WORDS_BIGENDIAN
+#define OP0 (((b0) & 0xf0) >> 4)
+#define OP1 (((b2) & 0xf0) >> 4)
+#define OP2 ((b2) & 0xf)
+#define RRR_R ((b1) & 0xf)
+#define RRR_S (((b1) & 0xf0) >> 4)
+#define RRR_T ((b0) & 0xf)
+#else
+#define OP0 (((b0) & 0xf))
+#define OP1 (((b2) & 0xf))
+#define OP2 (((b2) & 0xf0) >> 4)
+#define RRR_R (((b1) & 0xf0) >> 4)
+#define RRR_S (((b1) & 0xf))
+#define RRR_T (((b0) & 0xf0) >> 4)
+#endif
+
+#define RRRN_R RRR_R
+#define RRRN_S RRR_S
+#define RRRN_T RRR_T
+
+#define RRI8_R RRR_R
+#define RRI8_S RRR_S
+#define RRI8_T RRR_T
+#define RRI8_IMM8 (b2)
+#define RRI8_IMM8_SE ((((b2) & 0x80) ? 0xffffff00 : 0) | RRI8_IMM8)
+
+#ifdef TARGET_WORDS_BIGENDIAN
+#define RI16_IMM16 (((b1) << 8) | (b2))
+#else
+#define RI16_IMM16 (((b2) << 8) | (b1))
+#endif
+
+#ifdef TARGET_WORDS_BIGENDIAN
+#define CALL_N (((b0) & 0xc) >> 2)
+#define CALL_OFFSET ((((b0) & 0x3) << 16) | ((b1) << 8) | (b2))
+#else
+#define CALL_N (((b0) & 0x30) >> 4)
+#define CALL_OFFSET ((((b0) & 0xc0) >> 6) | ((b1) << 2) | ((b2) << 10))
+#endif
+#define CALL_OFFSET_SE \
+    (((CALL_OFFSET & 0x20000) ? 0xfffc0000 : 0) | CALL_OFFSET)
+
+#define CALLX_N CALL_N
+#ifdef TARGET_WORDS_BIGENDIAN
+#define CALLX_M ((b0) & 0x3)
+#else
+#define CALLX_M (((b0) & 0xc0) >> 6)
+#endif
+#define CALLX_S RRR_S
+
+#define BRI12_M CALLX_M
+#define BRI12_S RRR_S
+#ifdef TARGET_WORDS_BIGENDIAN
+#define BRI12_IMM12 ((((b1) & 0xf) << 8) | (b2))
+#else
+#define BRI12_IMM12 ((((b1) & 0xf0) >> 4) | ((b2) << 4))
+#endif
+#define BRI12_IMM12_SE (((BRI12_IMM12 & 0x800) ? 0xfffff000 : 0) | BRI12_IMM12)
+
+#define BRI8_M BRI12_M
+#define BRI8_R RRI8_R
+#define BRI8_S RRI8_S
+#define BRI8_IMM8 RRI8_IMM8
+#define BRI8_IMM8_SE RRI8_IMM8_SE
+
+#define RSR_SR (b1)
+
+    uint8_t b0 = ldub_code(dc->pc);
+    uint8_t b1 = ldub_code(dc->pc + 1);
+    uint8_t b2 = ldub_code(dc->pc + 2);
+
+    if (OP0 >= 8) {
+        dc->next_pc = dc->pc + 2;
+        HAS_OPTION(XTENSA_OPTION_CODE_DENSITY);
+    } else {
+        dc->next_pc = dc->pc + 3;
+    }
+
+    switch (OP0) {
+    case 0: /*QRST*/
+        switch (OP1) {
+        case 0: /*RST0*/
+            switch (OP2) {
+            case 0: /*ST0*/
+                if ((RRR_R & 0xc) == 0x8) {
+                    HAS_OPTION(XTENSA_OPTION_BOOLEAN);
+                }
+
+                switch (RRR_R) {
+                case 0: /*SNM0*/
+                    break;
+
+                case 1: /*MOVSPw*/
+                    HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                    break;
+
+                case 2: /*SYNC*/
+                    break;
+
+                case 3:
+                    break;
+
+                }
+                break;
+
+            case 1: /*AND*/
+                tcg_gen_and_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
+                break;
+
+            case 2: /*OR*/
+                tcg_gen_or_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
+                break;
+
+            case 3: /*XOR*/
+                tcg_gen_xor_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
+                break;
+
+            case 4: /*ST1*/
+                break;
+
+            case 5: /*TLB*/
+                break;
+
+            case 6: /*RT0*/
+                break;
+
+            case 7: /*reserved*/
+                break;
+
+            case 8: /*ADD*/
+                tcg_gen_add_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
+                break;
+
+            case 9: /*ADD**/
+            case 10:
+            case 11:
+                {
+                    TCGv_i32 tmp = tcg_temp_new_i32();
+                    tcg_gen_shli_i32(tmp, cpu_R[RRR_S], OP2 - 8);
+                    tcg_gen_add_i32(cpu_R[RRR_R], tmp, cpu_R[RRR_T]);
+                    tcg_temp_free(tmp);
+                }
+                break;
+
+            case 12: /*SUB*/
+                tcg_gen_sub_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
+                break;
+
+            case 13: /*SUB**/
+            case 14:
+            case 15:
+                {
+                    TCGv_i32 tmp = tcg_temp_new_i32();
+                    tcg_gen_shli_i32(tmp, cpu_R[RRR_S], OP2 - 12);
+                    tcg_gen_sub_i32(cpu_R[RRR_R], tmp, cpu_R[RRR_T]);
+                    tcg_temp_free(tmp);
+                }
+                break;
+            }
+            break;
+
+        case 1: /*RST1*/
+            break;
+
+        case 2: /*RST2*/
+            break;
+
+        case 3: /*RST3*/
+            break;
+
+        case 4: /*EXTUI*/
+        case 5:
+            break;
+
+        case 6: /*CUST0*/
+            break;
+
+        case 7: /*CUST1*/
+            break;
+
+        case 8: /*LSCXp*/
+            HAS_OPTION(XTENSA_OPTION_COPROCESSOR);
+            break;
+
+        case 9: /*LSC4*/
+            break;
+
+        case 10: /*FP0*/
+            HAS_OPTION(XTENSA_OPTION_FP_COPROCESSOR);
+            break;
+
+        case 11: /*FP1*/
+            HAS_OPTION(XTENSA_OPTION_FP_COPROCESSOR);
+            break;
+
+        default: /*reserved*/
+            break;
+        }
+        break;
+
+    case 1: /*L32R*/
+        {
+            TCGv_i32 tmp = tcg_const_i32(
+                    (0xfffc0000 | (RI16_IMM16 << 2)) +
+                    ((dc->pc + 3) & ~3));
+
+            /* no ext L32R */
+
+            tcg_gen_qemu_ld32u(cpu_R[RRR_T], tmp, 0);
+            tcg_temp_free(tmp);
+        }
+        break;
+
+    case 2: /*LSAI*/
+        break;
+
+    case 3: /*LSCIp*/
+        HAS_OPTION(XTENSA_OPTION_COPROCESSOR);
+        break;
+
+    case 4: /*MAC16d*/
+        HAS_OPTION(XTENSA_OPTION_MAC16);
+        break;
+
+    case 5: /*CALLN*/
+        switch (CALL_N) {
+        case 0: /*CALL0*/
+            tcg_gen_movi_i32(cpu_R[0], dc->next_pc);
+            gen_jumpi(dc, (dc->pc & ~3) + (CALL_OFFSET_SE << 2) + 4, 0);
+            break;
+
+        case 1: /*CALL4w*/
+        case 2: /*CALL8w*/
+        case 3: /*CALL12w*/
+            HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+            break;
+        }
+        break;
+
+    case 6: /*SI*/
+        switch (CALL_N) {
+        case 0: /*J*/
+            gen_jumpi(dc, dc->pc + 4 + CALL_OFFSET_SE, 0);
+            break;
+
+        }
+        break;
+
+    case 7: /*B*/
+        break;
+
+    case 8: /*L32I.Nn*/
+        break;
+
+    case 9: /*S32I.Nn*/
+        break;
+
+    case 10: /*ADD.Nn*/
+        break;
+
+    case 11: /*ADDI.Nn*/
+        break;
+
+    case 12: /*ST2n*/
+        break;
+
+    case 13: /*ST3n*/
+        break;
+
+    default: /*reserved*/
+        break;
+    }
+
+    dc->pc = dc->next_pc;
+    return;
+
+invalid_opcode:
+    qemu_log("INVALID(pc = %08x)\n", dc->pc);
+    dc->pc = dc->next_pc;
+#undef HAS_OPTION
+}
+
+static void check_breakpoint(CPUState *env, DisasContext *dc)
+{
+    CPUBreakpoint *bp;
+
+    if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
+        QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+            if (bp->pc == dc->pc) {
+                tcg_gen_movi_i32(cpu_pc, dc->pc);
+                gen_exception(EXCP_DEBUG);
+                dc->is_jmp = DISAS_UPDATE;
+             }
+        }
+    }
+}
+
+static void gen_intermediate_code_internal(
+        CPUState *env, TranslationBlock *tb, int search_pc)
+{
+    DisasContext dc;
+    int insn_count = 0;
+    int j, lj = -1;
+    uint16_t *gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
+    int max_insns = tb->cflags & CF_COUNT_MASK;
+    uint32_t pc_start = tb->pc;
+    uint32_t next_page_start =
+        (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
+
+    if (max_insns == 0) {
+        max_insns = CF_COUNT_MASK;
+    }
+
+    dc.config = env->config;
+    dc.singlestep_enabled = env->singlestep_enabled;
+    dc.tb = tb;
+    dc.pc = pc_start;
+    dc.is_jmp = DISAS_NEXT;
+
+    gen_icount_start();
+
+    do {
+        check_breakpoint(env, &dc);
+
+        if (search_pc) {
+            j = gen_opc_ptr - gen_opc_buf;
+            if (lj < j) {
+                lj++;
+                while (lj < j) {
+                    gen_opc_instr_start[lj++] = 0;
+                }
+            }
+            gen_opc_pc[lj] = dc.pc;
+            gen_opc_instr_start[lj] = 1;
+            gen_opc_icount[lj] = insn_count;
+        }
+
+        if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
+            tcg_gen_debug_insn_start(dc.pc);
+        }
+
+        disas_xtensa_insn(&dc);
+        ++insn_count;
+        if (env->singlestep_enabled) {
+            tcg_gen_movi_i32(cpu_pc, dc.pc);
+            gen_exception(EXCP_DEBUG);
+            break;
+        }
+    } while (dc.is_jmp == DISAS_NEXT &&
+            insn_count < max_insns &&
+            dc.pc < next_page_start &&
+            gen_opc_ptr < gen_opc_end);
+
+    if (dc.is_jmp == DISAS_NEXT) {
+        gen_jumpi(&dc, dc.pc, 0);
+    }
+    gen_icount_end(tb, insn_count);
+    *gen_opc_ptr = INDEX_op_end;
+
+    if (!search_pc) {
+        tb->size = dc.pc - pc_start;
+        tb->icount = insn_count;
+    }
 }
 
 void gen_intermediate_code(CPUState *env, TranslationBlock *tb)
 {
+    gen_intermediate_code_internal(env, tb, 0);
 }
 
 void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
 {
+    gen_intermediate_code_internal(env, tb, 1);
 }
 
 void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
commit cfa550c6acc6718c3f932e858366e3e1e81266d6
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Tue Sep 6 03:55:26 2011 +0400

    target-xtensa: add target to the configure script
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/configure b/configure
index 348f36a..0875f95 100755
--- a/configure
+++ b/configure
@@ -873,6 +873,8 @@ sh4eb-softmmu \
 sparc-softmmu \
 sparc64-softmmu \
 s390x-softmmu \
+xtensa-softmmu \
+xtensaeb-softmmu \
 "
 fi
 # the following are Linux specific
@@ -3150,7 +3152,7 @@ target_arch2=`echo $target | cut -d '-' -f 1`
 target_bigendian="no"
 
 case "$target_arch2" in
-  armeb|lm32|m68k|microblaze|mips|mipsn32|mips64|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus)
+  armeb|lm32|m68k|microblaze|mips|mipsn32|mips64|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus|xtensaeb)
   target_bigendian=yes
   ;;
 esac
@@ -3345,6 +3347,10 @@ case "$target_arch2" in
   unicore32)
     target_phys_bits=32
   ;;
+  xtensa|xtensaeb)
+    TARGET_ARCH=xtensa
+    target_phys_bits=32
+  ;;
   *)
     echo "Unsupported target CPU"
     exit 1
@@ -3519,6 +3525,10 @@ for i in $ARCH $TARGET_BASE_ARCH ; do
     echo "CONFIG_SPARC_DIS=y"  >> $config_target_mak
     echo "CONFIG_SPARC_DIS=y"  >> $libdis_config_mak
   ;;
+  xtensa*)
+    echo "CONFIG_XTENSA_DIS=y"  >> $config_target_mak
+    echo "CONFIG_XTENSA_DIS=y"  >> $libdis_config_mak
+  ;;
   esac
 done
 
diff --git a/default-configs/xtensa-softmmu.mak b/default-configs/xtensa-softmmu.mak
new file mode 100644
index 0000000..e5faa09
--- /dev/null
+++ b/default-configs/xtensa-softmmu.mak
@@ -0,0 +1 @@
+# Default configuration for Xtensa
diff --git a/default-configs/xtensaeb-softmmu.mak b/default-configs/xtensaeb-softmmu.mak
new file mode 100644
index 0000000..e5faa09
--- /dev/null
+++ b/default-configs/xtensaeb-softmmu.mak
@@ -0,0 +1 @@
+# Default configuration for Xtensa
commit 2328826b1d7d516cfe825546682cfe8513db07b4
Author: Max Filippov <jcmvbkbc at gmail.com>
Date:   Tue Sep 6 03:55:25 2011 +0400

    target-xtensa: add target stubs
    
    Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/Makefile.target b/Makefile.target
index 5f93d9e..2e94a63 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -368,6 +368,8 @@ obj-s390x-y = s390-virtio-bus.o s390-virtio.o
 obj-alpha-y = i8259.o mc146818rtc.o
 obj-alpha-y += vga.o cirrus_vga.o
 
+obj-xtensa-y += xtensa_pic.o
+
 main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
 
 monitor.o: hmp-commands.h qmp-commands.h
diff --git a/arch_init.c b/arch_init.c
index 567ab32..9a5a0e3 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -78,6 +78,8 @@ const char arch_config_name[] = CONFIG_QEMU_CONFDIR "/target-" TARGET_ARCH ".con
 #define QEMU_ARCH QEMU_ARCH_SH4
 #elif defined(TARGET_SPARC)
 #define QEMU_ARCH QEMU_ARCH_SPARC
+#elif defined(TARGET_XTENSA)
+#define QEMU_ARCH QEMU_ARCH_XTENSA
 #endif
 
 const uint32_t arch_type = QEMU_ARCH;
diff --git a/arch_init.h b/arch_init.h
index 2de9f08..a74187a 100644
--- a/arch_init.h
+++ b/arch_init.h
@@ -17,6 +17,7 @@ enum {
     QEMU_ARCH_S390X = 512,
     QEMU_ARCH_SH4 = 1024,
     QEMU_ARCH_SPARC = 2048,
+    QEMU_ARCH_XTENSA = 4096,
 };
 
 extern const uint32_t arch_type;
diff --git a/cpu-exec.c b/cpu-exec.c
index b00753c..d9278f3 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -223,6 +223,7 @@ int cpu_exec(CPUState *env)
 #elif defined(TARGET_SH4)
 #elif defined(TARGET_CRIS)
 #elif defined(TARGET_S390X)
+#elif defined(TARGET_XTENSA)
     /* XXXXX */
 #else
 #error unsupported target CPU
@@ -617,6 +618,7 @@ int cpu_exec(CPUState *env)
 #elif defined(TARGET_ALPHA)
 #elif defined(TARGET_CRIS)
 #elif defined(TARGET_S390X)
+#elif defined(TARGET_XTENSA)
     /* XXXXX */
 #else
 #error unsupported target CPU
diff --git a/elf.h b/elf.h
index ffcac7e..2e05d34 100644
--- a/elf.h
+++ b/elf.h
@@ -125,6 +125,8 @@ typedef int64_t  Elf64_Sxword;
 #define EM_MICROBLAZE      189
 #define EM_MICROBLAZE_OLD  0xBAAB
 
+#define EM_XTENSA   94      /* Tensilica Xtensa */
+
 /* This is the info that is needed to parse the dynamic section of the file */
 #define DT_NULL		0
 #define DT_NEEDED	1
diff --git a/hw/xtensa_pic.c b/hw/xtensa_pic.c
new file mode 100644
index 0000000..91a5445
--- /dev/null
+++ b/hw/xtensa_pic.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "hw.h"
+#include "pc.h"
+
+/* Stub functions for hardware that doesn't exist.  */
+void pic_info(Monitor *mon)
+{
+}
+
+void irq_info(Monitor *mon)
+{
+}
diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
new file mode 100644
index 0000000..a51ffc8
--- /dev/null
+++ b/target-xtensa/cpu.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CPU_XTENSA_H
+#define CPU_XTENSA_H
+
+#define TARGET_LONG_BITS 32
+#define ELF_MACHINE EM_XTENSA
+
+#define CPUState struct CPUXtensaState
+
+#include "config.h"
+#include "qemu-common.h"
+#include "cpu-defs.h"
+
+#define TARGET_HAS_ICE 1
+
+#define NB_MMU_MODES 4
+
+#define TARGET_PHYS_ADDR_SPACE_BITS 32
+#define TARGET_VIRT_ADDR_SPACE_BITS 32
+#define TARGET_PAGE_BITS 12
+
+typedef struct CPUXtensaState {
+    uint32_t regs[16];
+    uint32_t pc;
+    uint32_t sregs[256];
+
+    CPU_COMMON
+} CPUXtensaState;
+
+#define cpu_init cpu_xtensa_init
+#define cpu_exec cpu_xtensa_exec
+#define cpu_gen_code cpu_xtensa_gen_code
+#define cpu_signal_handler cpu_xtensa_signal_handler
+#define cpu_list xtensa_cpu_list
+
+CPUXtensaState *cpu_xtensa_init(const char *cpu_model);
+void xtensa_translate_init(void);
+int cpu_xtensa_exec(CPUXtensaState *s);
+void do_interrupt(CPUXtensaState *s);
+int cpu_xtensa_signal_handler(int host_signum, void *pinfo, void *puc);
+void xtensa_cpu_list(FILE *f, fprintf_function cpu_fprintf);
+
+static inline int cpu_mmu_index(CPUState *env)
+{
+    return 0;
+}
+
+static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
+        target_ulong *cs_base, int *flags)
+{
+    *pc = env->pc;
+    *cs_base = 0;
+    *flags = 0;
+}
+
+#include "cpu-all.h"
+#include "exec-all.h"
+
+static inline int cpu_has_work(CPUState *env)
+{
+    return 1;
+}
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+    env->pc = tb->pc;
+}
+
+#endif
diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c
new file mode 100644
index 0000000..dc30e00
--- /dev/null
+++ b/target-xtensa/helper.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cpu.h"
+#include "exec-all.h"
+#include "gdbstub.h"
+#include "qemu-common.h"
+#include "host-utils.h"
+#if !defined(CONFIG_USER_ONLY)
+#include "hw/loader.h"
+#endif
+
+void cpu_reset(CPUXtensaState *env)
+{
+    env->pc = 0;
+}
+
+CPUXtensaState *cpu_xtensa_init(const char *cpu_model)
+{
+    static int tcg_inited;
+    CPUXtensaState *env;
+
+    env = g_malloc0(sizeof(*env));
+    cpu_exec_init(env);
+
+    if (!tcg_inited) {
+        tcg_inited = 1;
+        xtensa_translate_init();
+    }
+
+    qemu_init_vcpu(env);
+    return env;
+}
+
+
+void xtensa_cpu_list(FILE *f, fprintf_function cpu_fprintf)
+{
+    cpu_fprintf(f, "Available CPUs:\n"
+            "  Xtensa core\n");
+}
+
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+{
+    return addr;
+}
+
+void do_interrupt(CPUState *env)
+{
+}
diff --git a/target-xtensa/machine.c b/target-xtensa/machine.c
new file mode 100644
index 0000000..ddeffb2
--- /dev/null
+++ b/target-xtensa/machine.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "hw/hw.h"
+#include "hw/boards.h"
+
+void cpu_save(QEMUFile *f, void *opaque)
+{
+}
+
+int cpu_load(QEMUFile *f, void *opaque, int version_id)
+{
+    return 0;
+}
diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c
new file mode 100644
index 0000000..aafa33d
--- /dev/null
+++ b/target-xtensa/op_helper.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cpu.h"
+#include "dyngen-exec.h"
+
+#define MMUSUFFIX _mmu
+
+#define SHIFT 0
+#include "softmmu_template.h"
+
+#define SHIFT 1
+#include "softmmu_template.h"
+
+#define SHIFT 2
+#include "softmmu_template.h"
+
+#define SHIFT 3
+#include "softmmu_template.h"
+
+void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+{
+    tlb_set_page(cpu_single_env,
+            addr & ~(TARGET_PAGE_SIZE - 1),
+            addr & ~(TARGET_PAGE_SIZE - 1),
+            PAGE_READ | PAGE_WRITE | PAGE_EXEC,
+            mmu_idx, TARGET_PAGE_SIZE);
+}
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
new file mode 100644
index 0000000..4f517d6
--- /dev/null
+++ b/target-xtensa/translate.c
@@ -0,0 +1,68 @@
+/*
+ * Xtensa ISA:
+ * http://www.tensilica.com/products/literature-docs/documentation/xtensa-isa-databook.htm
+ *
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+
+#include "cpu.h"
+#include "exec-all.h"
+#include "disas.h"
+#include "tcg-op.h"
+#include "qemu-log.h"
+
+
+void xtensa_translate_init(void)
+{
+}
+
+void gen_intermediate_code(CPUState *env, TranslationBlock *tb)
+{
+}
+
+void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
+{
+}
+
+void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
+        int flags)
+{
+    int i;
+
+    cpu_fprintf(f, "PC=%08x\n", env->pc);
+
+    for (i = 0; i < 16; ++i) {
+        cpu_fprintf(f, "A%02d=%08x%c", i, env->regs[i],
+                (i % 4) == 3 ? '\n' : ' ');
+    }
+}
+
+void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
+{
+    env->pc = gen_opc_pc[pc_pos];
+}
commit 83818f7cdd0dc31cd05a517da92fc056d8078908
Author: Hervé Poussineau <hpoussin at reactos.org>
Date:   Sun Sep 4 22:29:27 2011 +0200

    mipsnet: use trace framework
    
    Signed-off-by: Hervé Poussineau <hpoussin at reactos.org>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/mipsnet.c b/hw/mipsnet.c
index 9a29ffe..605367b 100644
--- a/hw/mipsnet.c
+++ b/hw/mipsnet.c
@@ -1,12 +1,8 @@
 #include "hw.h"
 #include "net.h"
+#include "trace.h"
 #include "sysbus.h"
 
-//#define DEBUG_MIPSNET_SEND
-//#define DEBUG_MIPSNET_RECEIVE
-//#define DEBUG_MIPSNET_DATA
-//#define DEBUG_MIPSNET_IRQ
-
 /* MIPSnet register offsets */
 
 #define MIPSNET_DEV_ID		0x00
@@ -55,9 +51,7 @@ static void mipsnet_reset(MIPSnetState *s)
 static void mipsnet_update_irq(MIPSnetState *s)
 {
     int isr = !!s->intctl;
-#ifdef DEBUG_MIPSNET_IRQ
-    printf("mipsnet: Set IRQ to %d (%02x)\n", isr, s->intctl);
-#endif
+    trace_mipsnet_irq(isr, s->intctl);
     qemu_set_irq(s->irq, isr);
 }
 
@@ -81,9 +75,7 @@ static ssize_t mipsnet_receive(VLANClientState *nc, const uint8_t *buf, size_t s
 {
     MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
 
-#ifdef DEBUG_MIPSNET_RECEIVE
-    printf("mipsnet: receiving len=%zu\n", size);
-#endif
+    trace_mipsnet_receive(size);
     if (!mipsnet_can_receive(nc))
         return -1;
 
@@ -146,9 +138,7 @@ static uint64_t mipsnet_ioport_read(void *opaque, target_phys_addr_t addr,
     default:
         break;
     }
-#ifdef DEBUG_MIPSNET_DATA
-    printf("mipsnet: read addr=0x%02x val=0x%02x\n", addr, ret);
-#endif
+    trace_mipsnet_read(addr, ret);
     return ret;
 }
 
@@ -158,9 +148,7 @@ static void mipsnet_ioport_write(void *opaque, target_phys_addr_t addr,
     MIPSnetState *s = opaque;
 
     addr &= 0x3f;
-#ifdef DEBUG_MIPSNET_DATA
-    printf("mipsnet: write addr=0x%02x val=0x%02x\n", addr, val);
-#endif
+    trace_mipsnet_write(addr, val);
     switch (addr) {
     case MIPSNET_TX_DATA_COUNT:
 	s->tx_count = (val <= MAX_ETH_FRAME_SIZE) ? val : 0;
@@ -184,9 +172,7 @@ static void mipsnet_ioport_write(void *opaque, target_phys_addr_t addr,
         s->tx_buffer[s->tx_written++] = val;
         if (s->tx_written == s->tx_count) {
             /* Send buffer. */
-#ifdef DEBUG_MIPSNET_SEND
-            printf("mipsnet: sending len=%d\n", s->tx_count);
-#endif
+            trace_mipsnet_send(s->tx_count);
             qemu_send_packet(&s->nic->nc, s->tx_buffer, s->tx_count);
             s->tx_count = s->tx_written = 0;
             s->intctl |= MIPSNET_INTCTL_TXDONE;
diff --git a/trace-events b/trace-events
index 3fdd60f..a8e7684 100644
--- a/trace-events
+++ b/trace-events
@@ -450,6 +450,13 @@ milkymist_uart_pulse_irq_tx(void) "Pulse IRQ TX"
 milkymist_vgafb_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
 milkymist_vgafb_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
 
+# hw/mipsnet.c
+mipsnet_send(uint32_t size) "sending len=%u"
+mipsnet_receive(uint32_t size) "receiving len=%u"
+mipsnet_read(uint64_t addr, uint32_t val) "read addr=0x%" PRIx64 " val=0x%x"
+mipsnet_write(uint64_t addr, uint64_t val) "write addr=0x%" PRIx64 " val=0x%" PRIx64
+mipsnet_irq(uint32_t isr, uint32_t intctl) "set irq to %d (%02x)"
+
 # xen-all.c
 xen_ram_alloc(unsigned long ram_addr, unsigned long size) "requested: %#lx, size %#lx"
 xen_client_set_memory(uint64_t start_addr, unsigned long size, unsigned long phys_offset, bool log_dirty) "%#"PRIx64" size %#lx, offset %#lx, log_dirty %i"
commit d118d64a929173f7ee7340265c4cd37bcf34667e
Author: Hervé Poussineau <hpoussin at reactos.org>
Date:   Sun Sep 4 22:29:26 2011 +0200

    mipsnet: convert to qdev
    
    Move mipsnet_init() function to mipssim machine
    
    Signed-off-by: Hervé Poussineau <hpoussin at reactos.org>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/mips.h b/hw/mips.h
index 8ce41fc..6fa9a3a 100644
--- a/hw/mips.h
+++ b/hw/mips.h
@@ -8,9 +8,6 @@ PCIBus *gt64120_register(qemu_irq *pic);
 /* bonito.c */
 PCIBus *bonito_init(qemu_irq *pic);
 
-/* mipsnet.c */
-void mipsnet_init(int base, qemu_irq irq, NICInfo *nd);
-
 /* jazz_led.c */
 void jazz_led_init(target_phys_addr_t base);
 
diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c
index 0d46cc4..ac65555 100644
--- a/hw/mips_mipssim.c
+++ b/hw/mips_mipssim.c
@@ -35,6 +35,8 @@
 #include "mips-bios.h"
 #include "loader.h"
 #include "elf.h"
+#include "sysbus.h"
+#include "exec-memory.h"
 
 static struct _loaderparams {
     int ram_size;
@@ -112,6 +114,22 @@ static void main_cpu_reset(void *opaque)
     }
 }
 
+static void mipsnet_init(int base, qemu_irq irq, NICInfo *nd)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    dev = qdev_create(NULL, "mipsnet");
+    qdev_set_nic_properties(dev, nd);
+    qdev_init_nofail(dev);
+
+    s = sysbus_from_qdev(dev);
+    sysbus_connect_irq(s, 0, irq);
+    memory_region_add_subregion(get_system_io(),
+                                base,
+                                sysbus_mmio_get_region(s, 0));
+}
+
 static void
 mips_mipssim_init (ram_addr_t ram_size,
                    const char *boot_device,
diff --git a/hw/mipsnet.c b/hw/mipsnet.c
index b889ee0..9a29ffe 100644
--- a/hw/mipsnet.c
+++ b/hw/mipsnet.c
@@ -1,7 +1,6 @@
 #include "hw.h"
-#include "mips.h"
 #include "net.h"
-#include "isa.h"
+#include "sysbus.h"
 
 //#define DEBUG_MIPSNET_SEND
 //#define DEBUG_MIPSNET_RECEIVE
@@ -25,6 +24,8 @@
 #define MAX_ETH_FRAME_SIZE	1514
 
 typedef struct MIPSnetState {
+    SysBusDevice busdev;
+
     uint32_t busy;
     uint32_t rx_count;
     uint32_t rx_read;
@@ -33,7 +34,7 @@ typedef struct MIPSnetState {
     uint32_t intctl;
     uint8_t rx_buffer[MAX_ETH_FRAME_SIZE];
     uint8_t tx_buffer[MAX_ETH_FRAME_SIZE];
-    int io_base;
+    MemoryRegion io;
     qemu_irq irq;
     NICState *nic;
     NICConf conf;
@@ -103,7 +104,8 @@ static ssize_t mipsnet_receive(VLANClientState *nc, const uint8_t *buf, size_t s
     return size;
 }
 
-static uint32_t mipsnet_ioport_read(void *opaque, uint32_t addr)
+static uint64_t mipsnet_ioport_read(void *opaque, target_phys_addr_t addr,
+                                    unsigned int size)
 {
     MIPSnetState *s = opaque;
     int ret = 0;
@@ -150,7 +152,8 @@ static uint32_t mipsnet_ioport_read(void *opaque, uint32_t addr)
     return ret;
 }
 
-static void mipsnet_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+static void mipsnet_ioport_write(void *opaque, target_phys_addr_t addr,
+                                 uint64_t val, unsigned int size)
 {
     MIPSnetState *s = opaque;
 
@@ -224,11 +227,7 @@ static void mipsnet_cleanup(VLANClientState *nc)
 {
     MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
 
-    vmstate_unregister(NULL, &vmstate_mipsnet, s);
-
-    isa_unassign_ioport(s->io_base, 36);
-
-    g_free(s);
+    s->nic = NULL;
 }
 
 static NetClientInfo net_mipsnet_info = {
@@ -239,35 +238,50 @@ static NetClientInfo net_mipsnet_info = {
     .cleanup = mipsnet_cleanup,
 };
 
-void mipsnet_init (int base, qemu_irq irq, NICInfo *nd)
-{
-    MIPSnetState *s;
-
-    qemu_check_nic_model(nd, "mipsnet");
+static MemoryRegionOps mipsnet_ioport_ops = {
+    .read = mipsnet_ioport_read,
+    .write = mipsnet_ioport_write,
+    .impl.min_access_size = 1,
+    .impl.max_access_size = 4,
+};
 
-    s = g_malloc0(sizeof(MIPSnetState));
+static int mipsnet_sysbus_init(SysBusDevice *dev)
+{
+    MIPSnetState *s = DO_UPCAST(MIPSnetState, busdev, dev);
 
-    register_ioport_write(base, 36, 1, mipsnet_ioport_write, s);
-    register_ioport_read(base, 36, 1, mipsnet_ioport_read, s);
-    register_ioport_write(base, 36, 2, mipsnet_ioport_write, s);
-    register_ioport_read(base, 36, 2, mipsnet_ioport_read, s);
-    register_ioport_write(base, 36, 4, mipsnet_ioport_write, s);
-    register_ioport_read(base, 36, 4, mipsnet_ioport_read, s);
+    memory_region_init_io(&s->io, &mipsnet_ioport_ops, s, "mipsnet-io", 36);
+    sysbus_init_mmio_region(dev, &s->io);
+    sysbus_init_irq(dev, &s->irq);
 
-    s->io_base = base;
-    s->irq = irq;
+    s->nic = qemu_new_nic(&net_mipsnet_info, &s->conf,
+                          dev->qdev.info->name, dev->qdev.id, s);
+    qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
 
-    if (nd) {
-        s->conf.macaddr = nd->macaddr;
-        s->conf.vlan = nd->vlan;
-        s->conf.peer = nd->netdev;
+    return 0;
+}
 
-        s->nic = qemu_new_nic(&net_mipsnet_info, &s->conf,
-                              nd->model, nd->name, s);
+static void mipsnet_sysbus_reset(DeviceState *dev)
+{
+    MIPSnetState *s = DO_UPCAST(MIPSnetState, busdev.qdev, dev);
+    mipsnet_reset(s);
+}
 
-        qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
+static SysBusDeviceInfo mipsnet_info = {
+    .init = mipsnet_sysbus_init,
+    .qdev.name = "mipsnet",
+    .qdev.desc = "MIPS Simulator network device",
+    .qdev.size = sizeof(MIPSnetState),
+    .qdev.vmsd = &vmstate_mipsnet,
+    .qdev.reset = mipsnet_sysbus_reset,
+    .qdev.props = (Property[]) {
+        DEFINE_NIC_PROPERTIES(MIPSnetState, conf),
+        DEFINE_PROP_END_OF_LIST(),
     }
+};
 
-    mipsnet_reset(s);
-    vmstate_register(NULL, 0, &vmstate_mipsnet, s);
+static void mipsnet_register_devices(void)
+{
+    sysbus_register_withprop(&mipsnet_info);
 }
+
+device_init(mipsnet_register_devices)
commit f64e02b6cc17d6c9c096ec2c89af75dc8e56666b
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sat Sep 3 16:41:21 2011 +0000

    PCI: delete unused mem_base and pci_to_cpu_addr
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/pci.c b/hw/pci.c
index 57ff7b1..af74003 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -312,11 +312,6 @@ void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *qdev)
     bus->hotplug_qdev = qdev;
 }
 
-void pci_bus_set_mem_base(PCIBus *bus, target_phys_addr_t base)
-{
-    bus->mem_base = base;
-}
-
 PCIBus *pci_register_bus(DeviceState *parent, const char *name,
                          pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
                          void *irq_opaque,
@@ -833,12 +828,6 @@ PCIDevice *pci_register_device(PCIBus *bus, const char *name,
     return pci_dev;
 }
 
-static target_phys_addr_t pci_to_cpu_addr(PCIBus *bus,
-                                          target_phys_addr_t addr)
-{
-    return addr + bus->mem_base;
-}
-
 static void pci_unregister_io_regions(PCIDevice *pci_dev)
 {
     PCIIORegion *r;
@@ -1066,8 +1055,7 @@ static void pci_update_mappings(PCIDevice *d)
                                                     1);
             } else {
                 memory_region_add_subregion_overlap(r->address_space,
-                                                    pci_to_cpu_addr(d->bus,
-                                                                    r->addr),
+                                                    r->addr,
                                                     r->memory,
                                                     1);
             }
diff --git a/hw/pci.h b/hw/pci.h
index 391217e..c04b169 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -255,8 +255,6 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name,
 void pci_device_reset(PCIDevice *dev);
 void pci_bus_reset(PCIBus *bus);
 
-void pci_bus_set_mem_base(PCIBus *bus, target_phys_addr_t base);
-
 PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model,
                         const char *default_devaddr);
 PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model,
commit de18f87eb15801b8e2aef4e5e6cde7299dc7f12b
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Sep 4 11:32:23 2011 +0000

    Sparc64: remove useless variable
    
    Remove a useless variable, spotted by clang analyzer:
    /src/qemu/target-sparc/op_helper.c:3904:18: warning: unused variable 'tmp' [-Wunused-variable]
        target_ulong tmp = val;
    The error message is actually incorrect since the variable is used.
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
index d1a8dd9..48e1db8 100644
--- a/target-sparc/op_helper.c
+++ b/target-sparc/op_helper.c
@@ -3901,10 +3901,8 @@ target_ulong cpu_get_ccr(CPUState *env1)
 
 static void put_ccr(target_ulong val)
 {
-    target_ulong tmp = val;
-
-    env->xcc = (tmp >> 4) << 20;
-    env->psr = (tmp & 0xf) << 20;
+    env->xcc = (val >> 4) << 20;
+    env->psr = (val & 0xf) << 20;
     CC_OP = CC_OP_FLAGS;
 }
 
commit a6c6f44ae4a8637e2c7394b46e2ba15f7b7682a0
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Sep 4 11:22:31 2011 +0000

    lsi53c895a: avoid a warning from clang analyzer
    
    Avoid this warning from clang analyzer by deleting the variable:
    /src/qemu/hw/lsi53c895a.c:895:5: warning: Value stored to 'id' is never read
        id = (current_tag >> 8) & 0xf;
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index 1643a63..ac284e9 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -883,7 +883,6 @@ static void lsi_do_msgout(LSIState *s)
     int len;
     uint32_t current_tag;
     lsi_request *current_req, *p, *p_next;
-    int id;
 
     if (s->current) {
         current_tag = s->current->tag;
@@ -892,7 +891,6 @@ static void lsi_do_msgout(LSIState *s)
         current_tag = s->select_tag;
         current_req = lsi_find_by_tag(s, current_tag);
     }
-    id = (current_tag >> 8) & 0xf;
 
     DPRINTF("MSG out len=%d\n", s->dbc);
     while (s->dbc) {
@@ -977,9 +975,8 @@ static void lsi_do_msgout(LSIState *s)
                device, but this is currently not implemented (and seems not
                to be really necessary). So let's simply clear all queued
                commands for the current device: */
-            id = current_tag & 0x0000ff00;
             QTAILQ_FOREACH_SAFE(p, &s->queue, next, p_next) {
-                if ((p->tag & 0x0000ff00) == id) {
+                if ((p->tag & 0x0000ff00) == (current_tag & 0x0000ff00)) {
                     scsi_req_cancel(p->req);
                 }
             }
commit 337fc758703b2cc2edabc1fdca5907f11fa837b0
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Sep 4 11:06:22 2011 +0000

    cpu-exec: remove unnecessary assignment
    
    Avoid this warning from clang analyzer:
    /src/qemu/cpu-exec.c:97:5: warning: Value stored to 'phys_page2' is never read
        phys_page2 = -1;
    
    Adjust the scope of the variable while at it.
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/cpu-exec.c b/cpu-exec.c
index de0d716..b00753c 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -86,7 +86,7 @@ static TranslationBlock *tb_find_slow(CPUState *env,
 {
     TranslationBlock *tb, **ptb1;
     unsigned int h;
-    tb_page_addr_t phys_pc, phys_page1, phys_page2;
+    tb_page_addr_t phys_pc, phys_page1;
     target_ulong virt_page2;
 
     tb_invalidated_flag = 0;
@@ -94,7 +94,6 @@ static TranslationBlock *tb_find_slow(CPUState *env,
     /* find translated block using physical mappings */
     phys_pc = get_page_addr_code(env, pc);
     phys_page1 = phys_pc & TARGET_PAGE_MASK;
-    phys_page2 = -1;
     h = tb_phys_hash_func(phys_pc);
     ptb1 = &tb_phys_hash[h];
     for(;;) {
@@ -107,6 +106,8 @@ static TranslationBlock *tb_find_slow(CPUState *env,
             tb->flags == flags) {
             /* check next page if needed */
             if (tb->page_addr[1] != -1) {
+                tb_page_addr_t phys_page2;
+
                 virt_page2 = (pc & TARGET_PAGE_MASK) +
                     TARGET_PAGE_SIZE;
                 phys_page2 = get_page_addr_code(env, virt_page2);
commit 6115c0a82dfdb4192ea42b48aebced2a7f96efd4
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Sep 4 11:03:52 2011 +0000

    kvm: remove unnecessary assignments
    
    Avoid these warnings from clang analyzer:
    /src/qemu/target-i386/kvm.c:772:5: warning: Value stored to 'cwd' is never read
        cwd = swd = twd = 0;
    /src/qemu/target-i386/kvm.c:772:11: warning: Although the value stored to 'swd' is used in the enclosing expression, the value is never actually read from 'swd'
        cwd = swd = twd = 0;
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 70ef74b..22b1dd0 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -769,7 +769,7 @@ static int kvm_put_xsave(CPUState *env)
 
     xsave = qemu_memalign(4096, sizeof(struct kvm_xsave));
     memset(xsave, 0, sizeof(struct kvm_xsave));
-    cwd = swd = twd = 0;
+    twd = 0;
     swd = env->fpus & ~(7 << 11);
     swd |= (env->fpstt & 7) << 11;
     cwd = env->fpuc;
commit 18f88f1195e32afd86eab2bda083f4624180e3f4
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Sep 4 10:59:52 2011 +0000

    hid: fix misassignment
    
    The code does not have any effect as is, fix it.
    
    Spotted by clang analyzer:
    /src/qemu/hw/hid.c:99:13: warning: Value stored to 'x1' is never read
                x1 = 1;
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/hid.c b/hw/hid.c
index ec066cf..03761ab 100644
--- a/hw/hid.c
+++ b/hw/hid.c
@@ -96,7 +96,7 @@ static void hid_pointer_event_combine(HIDPointerEvent *e, int xyrel,
         /* Windows drivers do not like the 0/0 position and ignore such
          * events. */
         if (!(x1 | y1)) {
-            x1 = 1;
+            e->xdx = 1;
         }
     }
     e->dz += z1;
commit 48bb9f53f4944771bc5d7bf89bbaa61094ad4382
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Sep 4 10:56:51 2011 +0000

    scsi-bus: remove duplicate table entries
    
    Remove duplicate entries from SCSI command table, spotted by
    clang analyzer:
    /src/qemu/hw/scsi-bus.c:979:40: warning: initializer overrides prior initialization of this subobject
            [ ERASE_16                 ] = "ERASE_16",
    /src/qemu/hw/scsi-bus.c:978:40: note: previous initialization is here
            [ WRITE_SAME_16            ] = "WRITE_SAME_16",
    /src/qemu/hw/scsi-bus.c:984:40: warning: initializer overrides prior initialization of this subobject
            [ MAINTENANCE_IN           ] = "MAINTENANCE_IN",
    /src/qemu/hw/scsi-bus.c:917:40: note: previous initialization is here
            [ MAINTENANCE_IN           ] = "MAINTENANCE_IN",
    /src/qemu/hw/scsi-bus.c:985:40: warning: initializer overrides prior initialization of this subobject
            [ MAINTENANCE_OUT          ] = "MAINTENANCE_OUT",
    /src/qemu/hw/scsi-bus.c:918:40: note: previous initialization is here
            [ MAINTENANCE_OUT          ] = "MAINTENANCE_OUT",
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 160eaee..59d6ada 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -977,13 +977,11 @@ static const char *scsi_command_name(uint8_t cmd)
         [ SYNCHRONIZE_CACHE_16     ] = "SYNCHRONIZE_CACHE_16",
         [ LOCATE_16                ] = "LOCATE_16",
         [ WRITE_SAME_16            ] = "WRITE_SAME_16",
-        [ ERASE_16                 ] = "ERASE_16",
+        /* ERASE_16 and WRITE_SAME_16 use the same operation code */
         [ SERVICE_ACTION_IN_16     ] = "SERVICE_ACTION_IN_16",
         [ WRITE_LONG_16            ] = "WRITE_LONG_16",
         [ REPORT_LUNS              ] = "REPORT_LUNS",
         [ BLANK                    ] = "BLANK",
-        [ MAINTENANCE_IN           ] = "MAINTENANCE_IN",
-        [ MAINTENANCE_OUT          ] = "MAINTENANCE_OUT",
         [ MOVE_MEDIUM              ] = "MOVE_MEDIUM",
         [ LOAD_UNLOAD              ] = "LOAD_UNLOAD",
         [ READ_12                  ] = "READ_12",
commit 84c8c656d0f4b4a0deab4064dd33d4a9fff8519d
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Sep 4 10:38:01 2011 +0000

    qemu-io: remove unnecessary assignment
    
    Remove an unnecessary assignment, spotted by clang analyzer:
    /src/qemu/qemu-io.c:995:9: warning: Value stored to 'offset' is never read
            offset += reqs[i].qiov->size;
    
    Acked-by: Kevin Wolf <kwolf at redhat.com>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/qemu-io.c b/qemu-io.c
index 7e40c48..5e46213 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -992,7 +992,6 @@ static int multiwrite_f(int argc, char **argv)
 
         optind = j + 1;
 
-        offset += reqs[i].qiov->size;
         pattern++;
     }
 
commit 7948a66574c3efd2e922853429b197840d119879
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Sep 4 09:32:55 2011 +0000

    win32: improve version.o dependency
    
    Actually, version.rc doesn't need config-host.mak but config-host.h, fix it.
    
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/Makefile b/Makefile
index e0cf51a..7e9382f 100644
--- a/Makefile
+++ b/Makefile
@@ -116,7 +116,7 @@ ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
 
 bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)
 
-version.o: $(SRC_PATH)/version.rc config-host.mak
+version.o: $(SRC_PATH)/version.rc config-host.h
 	$(call quiet-command,$(WINDRES) -I. -o $@ $<,"  RC    $(TARGET_DIR)$@")
 
 version-obj-$(CONFIG_WIN32) += version.o
commit 1213406bf8d924a0747ec59d98751a8204558050
Author: Blue Swirl <blauwirbel at gmail.com>
Date:   Sun Sep 4 20:51:28 2011 +0000

    g364fb: compile in hwlib
    
    Compile g364fb in hwlib. Two compilations less for the full build.
    
    Acked-by: Hervé Poussineau <hpoussin at reactos.org>
    Signed-off-by: Blue Swirl <blauwirbel at gmail.com>

diff --git a/Makefile.objs b/Makefile.objs
index a529a11..62020d7 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -240,6 +240,7 @@ hw-obj-$(CONFIG_PPCE500_PCI) += ppce500_pci.o
 
 # MIPS devices
 hw-obj-$(CONFIG_PIIX4) += piix4.o
+hw-obj-$(CONFIG_G364FB) += g364fb.o
 
 # PCI watchdog devices
 hw-obj-$(CONFIG_PCI) += wdt_i6300esb.o
diff --git a/Makefile.target b/Makefile.target
index 8822442..5f93d9e 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -284,7 +284,7 @@ obj-lm32-y += framebuffer.o
 obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
 obj-mips-y += mips_addr.o mips_timer.o mips_int.o
 obj-mips-y += vga.o i8259.o
-obj-mips-y += g364fb.o jazz_led.o
+obj-mips-y += jazz_led.o
 obj-mips-y += gt64xxx.o mc146818rtc.o
 obj-mips-y += cirrus_vga.o
 obj-mips-$(CONFIG_FULONG) += bonito.o vt82c686.o mips_fulong2e.o
diff --git a/default-configs/mips-softmmu.mak b/default-configs/mips-softmmu.mak
index f524971..45bdefb 100644
--- a/default-configs/mips-softmmu.mak
+++ b/default-configs/mips-softmmu.mak
@@ -26,3 +26,4 @@ CONFIG_DP8393X=y
 CONFIG_DS1225Y=y
 CONFIG_MIPSNET=y
 CONFIG_PFLASH_CFI01=y
+CONFIG_G364FB=y
diff --git a/default-configs/mips64-softmmu.mak b/default-configs/mips64-softmmu.mak
index aeab6b2..d43e33c 100644
--- a/default-configs/mips64-softmmu.mak
+++ b/default-configs/mips64-softmmu.mak
@@ -26,3 +26,4 @@ CONFIG_DP8393X=y
 CONFIG_DS1225Y=y
 CONFIG_MIPSNET=y
 CONFIG_PFLASH_CFI01=y
+CONFIG_G364FB=y
diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
index 8e6511c..f307e8d 100644
--- a/default-configs/mips64el-softmmu.mak
+++ b/default-configs/mips64el-softmmu.mak
@@ -28,3 +28,4 @@ CONFIG_DS1225Y=y
 CONFIG_MIPSNET=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_FULONG=y
+CONFIG_G364FB=y
diff --git a/default-configs/mipsel-softmmu.mak b/default-configs/mipsel-softmmu.mak
index a05ac25..1a66bc3 100644
--- a/default-configs/mipsel-softmmu.mak
+++ b/default-configs/mipsel-softmmu.mak
@@ -26,3 +26,4 @@ CONFIG_DP8393X=y
 CONFIG_DS1225Y=y
 CONFIG_MIPSNET=y
 CONFIG_PFLASH_CFI01=y
+CONFIG_G364FB=y
diff --git a/hw/g364fb.c b/hw/g364fb.c
index 5e7bcfa..b43341f 100644
--- a/hw/g364fb.c
+++ b/hw/g364fb.c
@@ -58,6 +58,8 @@ typedef struct G364State {
 #define CTLA_FORCE_BLANK 0x00000400
 #define CTLA_NO_CURSOR   0x00800000
 
+#define G364_PAGE_SIZE 4096
+
 static inline int check_dirty(G364State *s, ram_addr_t page)
 {
     return memory_region_get_dirty(&s->mem_vram, page, DIRTY_MEMORY_VGA);
@@ -68,7 +70,7 @@ static inline void reset_dirty(G364State *s,
 {
     memory_region_reset_dirty(&s->mem_vram,
                               page_min,
-                              page_max + TARGET_PAGE_SIZE - page_min - 1,
+                              page_max + G364_PAGE_SIZE - page_min - 1,
                               DIRTY_MEMORY_VGA);
 }
 
@@ -136,7 +138,7 @@ static void g364fb_draw_graphic8(G364State *s)
             page_max = page;
             if (x < xmin)
                 xmin = x;
-            for (i = 0; i < TARGET_PAGE_SIZE; i++) {
+            for (i = 0; i < G364_PAGE_SIZE; i++) {
                 uint8_t index;
                 unsigned int color;
                 if (unlikely((y >= ycursor && y < ycursor + 64) &&
@@ -200,15 +202,15 @@ static void g364fb_draw_graphic8(G364State *s)
                 ymin = s->height;
                 ymax = 0;
             }
-            x += TARGET_PAGE_SIZE;
+            x += G364_PAGE_SIZE;
             dy = x / s->width;
             x = x % s->width;
             y += dy;
-            vram += TARGET_PAGE_SIZE;
+            vram += G364_PAGE_SIZE;
             data_display += dy * ds_get_linesize(s->ds);
             dd = data_display + x * w;
         }
-        page += TARGET_PAGE_SIZE;
+        page += G364_PAGE_SIZE;
     }
 
 done:
@@ -267,7 +269,7 @@ static inline void g364fb_invalidate_display(void *opaque)
     int i;
 
     s->blanked = 0;
-    for (i = 0; i < s->vram_size; i += TARGET_PAGE_SIZE) {
+    for (i = 0; i < s->vram_size; i += G364_PAGE_SIZE) {
         memory_region_set_dirty(&s->mem_vram, i);
     }
 }
@@ -387,7 +389,7 @@ static void g364_invalidate_cursor_position(G364State *s)
     start = ymin * ds_get_linesize(s->ds);
     end = (ymax + 1) * ds_get_linesize(s->ds);
 
-    for (i = start; i < end; i += TARGET_PAGE_SIZE) {
+    for (i = start; i < end; i += G364_PAGE_SIZE) {
         memory_region_set_dirty(&s->mem_vram, i);
     }
 }
commit 282c355b174755ae53e2feeaf624c418ea009dc6
Merge: da5391e... 56c119e...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Sep 9 13:13:27 2011 -0500

    Merge remote-tracking branch 'sstabellini/xen-next' into staging

commit da5391edd18a1d75d4ca13f2dffe70e02f851110
Merge: 5689dc6... 5a61cb6...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Fri Sep 9 13:09:57 2011 -0500

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

commit 5689dc6557cecfd4318dea5490ecac4967081aed
Author: Michael Roth <mdroth at linux.vnet.ibm.com>
Date:   Wed Sep 7 18:40:51 2011 -0500

    build: fix missing trace dep on GENERATED_HEADERS
    
    fc764105 added an include for qemu-common.h to trace/control.h, which
    made all users of this header file dependent on GENERATED_HEADERS. Since
    it's used by pretty much all the trace backends now, make trace-obj-y
    dependent on GENERATED_HEADERS.
    
    Signed-off-by: Michael Roth <mdroth at linux.vnet.ibm.com>
    Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Michael Roth <mdroth at linux.vnet.ibm.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/Makefile.objs b/Makefile.objs
index 26b885b..a529a11 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -390,6 +390,8 @@ trace-nested-y += control.o
 
 trace-obj-y += $(addprefix trace/, $(trace-nested-y))
 
+$(trace-obj-y): $(GENERATED_HEADERS)
+
 ######################################################################
 # smartcard
 
commit f40d55081667a716312b9a8b6e13835c4074f56b
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Sep 7 17:52:10 2011 +0200

    vns/tls: don't use depricated gnutls functions
    
    Avoid using deprecated gnutls functions with recent gnutls versions.
    Fixes build failure on Fedora 16.  Keep the old way for compatibility
    with old installations such as RHEL-5 (gnutls 1.4.x).
    
    Based on a patch from Raghavendra D Prabhu <raghu.prabhu13 at gmail.com>
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/ui/vnc-tls.c b/ui/vnc-tls.c
index 2e2456e..ffbd172 100644
--- a/ui/vnc-tls.c
+++ b/ui/vnc-tls.c
@@ -283,13 +283,57 @@ int vnc_tls_validate_certificate(struct VncState *vs)
     return 0;
 }
 
+#if defined(GNUTLS_VERSION_NUMBER) && \
+    GNUTLS_VERSION_NUMBER >= 0x020200 /* 2.2.0 */
+
+static int vnc_set_gnutls_priority(gnutls_session_t s, int x509)
+{
+    const char *priority = x509 ? "NORMAL" : "NORMAL:+ANON-DH";
+    int rc;
+
+    rc = gnutls_priority_set_direct(s, priority, NULL);
+    if (rc != GNUTLS_E_SUCCESS) {
+        return -1;
+    }
+    return 0;
+}
+
+#else
+
+static int vnc_set_gnutls_priority(gnutls_session_t s, int x509)
+{
+    static const int cert_types[] = { GNUTLS_CRT_X509, 0 };
+    static const int protocols[] = {
+        GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0
+    };
+    static const int kx_anon[] = { GNUTLS_KX_ANON_DH, 0 };
+    static const int kx_x509[] = {
+        GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA,
+        GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0
+    };
+    int rc;
+
+    rc = gnutls_kx_set_priority(s, x509 ? kx_x509 : kx_anon);
+    if (rc != GNUTLS_E_SUCCESS) {
+        return -1;
+    }
+
+    rc = gnutls_certificate_type_set_priority(s, cert_types);
+    if (rc != GNUTLS_E_SUCCESS) {
+        return -1;
+    }
+
+    rc = gnutls_protocol_set_priority(s, protocols);
+    if (rc != GNUTLS_E_SUCCESS) {
+        return -1;
+    }
+    return 0;
+}
+
+#endif
 
 int vnc_tls_client_setup(struct VncState *vs,
                          int needX509Creds) {
-    static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
-    static const int protocol_priority[]= { GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 };
-    static const int kx_anon[] = {GNUTLS_KX_ANON_DH, 0};
-    static const int kx_x509[] = {GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0};
 
     VNC_DEBUG("Do TLS setup\n");
     if (vnc_tls_initialize() < 0) {
@@ -310,21 +354,7 @@ int vnc_tls_client_setup(struct VncState *vs,
             return -1;
         }
 
-        if (gnutls_kx_set_priority(vs->tls.session, needX509Creds ? kx_x509 : kx_anon) < 0) {
-            gnutls_deinit(vs->tls.session);
-            vs->tls.session = NULL;
-            vnc_client_error(vs);
-            return -1;
-        }
-
-        if (gnutls_certificate_type_set_priority(vs->tls.session, cert_type_priority) < 0) {
-            gnutls_deinit(vs->tls.session);
-            vs->tls.session = NULL;
-            vnc_client_error(vs);
-            return -1;
-        }
-
-        if (gnutls_protocol_set_priority(vs->tls.session, protocol_priority) < 0) {
+        if (vnc_set_gnutls_priority(vs->tls.session, needX509Creds) < 0) {
             gnutls_deinit(vs->tls.session);
             vs->tls.session = NULL;
             vnc_client_error(vs);
commit fa4e49c0c02f728e86df50a1c4a4011de8ca1225
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Sep 7 15:02:16 2011 +0200

    Use hex instead of binary.
    
    Older gcc versions don't understand 0b<bits>,
    use hex representation instead.
    
    Fixes build failure on RHEL-5.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/target-unicore32/translate.c b/target-unicore32/translate.c
index 4ecb0f1..4d0aa43 100644
--- a/target-unicore32/translate.c
+++ b/target-unicore32/translate.c
@@ -1788,7 +1788,7 @@ static void disas_uc32_insn(CPUState *env, DisasContext *s)
      * E    : 5
      */
     switch (insn >> 29) {
-    case 0b000:
+    case 0x0:
         if (UCOP_SET(5) && UCOP_SET(8) && !UCOP_SET(28)) {
             do_mult(env, s, insn);
             break;
@@ -1798,7 +1798,7 @@ static void disas_uc32_insn(CPUState *env, DisasContext *s)
             do_misc(env, s, insn);
             break;
         }
-    case 0b001:
+    case 0x1:
         if (((UCOP_OPCODES >> 2) == 2) && !UCOP_SET_S) {
             do_misc(env, s, insn);
             break;
@@ -1806,7 +1806,7 @@ static void disas_uc32_insn(CPUState *env, DisasContext *s)
         do_datap(env, s, insn);
         break;
 
-    case 0b010:
+    case 0x2:
         if (UCOP_SET(8) && UCOP_SET(5)) {
             do_ldst_hwsb(env, s, insn);
             break;
@@ -1814,24 +1814,24 @@ static void disas_uc32_insn(CPUState *env, DisasContext *s)
         if (UCOP_SET(8) || UCOP_SET(5)) {
             ILLEGAL;
         }
-    case 0b011:
+    case 0x3:
         do_ldst_ir(env, s, insn);
         break;
 
-    case 0b100:
+    case 0x4:
         if (UCOP_SET(8)) {
             ILLEGAL; /* extended instructions */
         }
         do_ldst_m(env, s, insn);
         break;
-    case 0b101:
+    case 0x5:
         do_branch(env, s, insn);
         break;
-    case 0b110:
+    case 0x6:
         /* Coprocessor.  */
         disas_coproc_insn(env, s, insn);
         break;
-    case 0b111:
+    case 0x7:
         if (!UCOP_SET(28)) {
             disas_coproc_insn(env, s, insn);
             break;
commit ad8b818686623ea4ad300a7a144fcfb2bce77050
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Sep 7 15:02:15 2011 +0200

    Don't use g_thread_get_initialized.
    
    Initialize glib threads unconditionally in main() instead
    of using g_thread_get_initialized in the 9p code.
    
    Fixes a build failure on RHEL-5, which ships glib 2.12.
    g_thread_get_initialized was added in 2.20.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/9pfs/virtio-9p-coth.c b/hw/9pfs/virtio-9p-coth.c
index ae05658..25556cc 100644
--- a/hw/9pfs/virtio-9p-coth.c
+++ b/hw/9pfs/virtio-9p-coth.c
@@ -67,10 +67,6 @@ int v9fs_init_worker_threads(void)
     /* Leave signal handling to the iothread.  */
     pthread_sigmask(SIG_SETMASK, &set, &oldset);
 
-    /* init thread system if not already initialized */
-    if (!g_thread_get_initialized()) {
-        g_thread_init(NULL);
-    }
     if (qemu_pipe(notifier_fds) == -1) {
         ret = -1;
         goto err_out;
diff --git a/vl.c b/vl.c
index 5ba9b35..6e998af 100644
--- a/vl.c
+++ b/vl.c
@@ -2200,6 +2200,7 @@ int main(int argc, char **argv, char **envp)
     error_set_progname(argv[0]);
 
     g_mem_set_vtable(&mem_trace);
+    g_thread_init(NULL);
 
     init_clocks();
 
commit 36b586284e678da28df3af9fd0907d2b16f9311c
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Sep 5 11:07:05 2011 +0300

    qemu_vmalloc: align properly for transparent hugepages and KVM
    
    To make good use of transparent hugepages, KVM requires that guest-physical
    and host-virtual addresses share the low 21 bits (as opposed to just the low
    12 bits normally required).
    
    Adjust qemu_vmalloc() to honor that requirement.  Ignore it for small regions
    to avoid fragmentation.
    
    Signed-off-by: Avi Kivity <avi at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/oslib-posix.c b/oslib-posix.c
index 196099c..a304fb0 100644
--- a/oslib-posix.c
+++ b/oslib-posix.c
@@ -35,6 +35,13 @@
 extern int daemon(int, int);
 #endif
 
+#if defined(__linux__) && defined(__x86_64__)
+   /* Use 2MB alignment so transparent hugepages can be used by KVM */
+#  define QEMU_VMALLOC_ALIGN (512 * 4096)
+#else
+#  define QEMU_VMALLOC_ALIGN getpagesize()
+#endif
+
 #include "config-host.h"
 #include "sysemu.h"
 #include "trace.h"
@@ -80,7 +87,12 @@ void *qemu_memalign(size_t alignment, size_t size)
 void *qemu_vmalloc(size_t size)
 {
     void *ptr;
-    ptr = qemu_memalign(getpagesize(), size);
+    size_t align = QEMU_VMALLOC_ALIGN;
+
+    if (size < align) {
+        align = getpagesize();
+    }
+    ptr = qemu_memalign(align, size);
     trace_qemu_vmalloc(size, ptr);
     return ptr;
 }
commit df00bed0fa30a6f5712456e7add783e470c534c9
Author: Devin J. Pohly <djpohly+launchpad at gmail.com>
Date:   Wed Sep 7 15:44:36 2011 -0400

    curses: fix garbling when chtype != long
    
    Qemu currently assumes that chtype is typedef'd to unsigned long, but
    this is not necessarily the case (ncurses, for instance, can configure
    this at build-time).  This patch uses the predefined chtype if qemu is
    configured for curses support and falls back to unsigned long otherwise.
    
    Fixes bug 568614.
    
    Signed-off-by: Devin J. Pohly <djpohly+launchpad at gmail.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/console.c b/console.c
index 500b3fb..5c7a93b 100644
--- a/console.c
+++ b/console.c
@@ -343,6 +343,7 @@ static const uint32_t dmask4[4] = {
 
 static uint32_t color_table[2][8];
 
+#ifndef CONFIG_CURSES
 enum color_names {
     COLOR_BLACK   = 0,
     COLOR_RED     = 1,
@@ -353,6 +354,7 @@ enum color_names {
     COLOR_CYAN    = 6,
     COLOR_WHITE   = 7
 };
+#endif
 
 static const uint32_t color_table_rgb[2][8] = {
     {   /* dark */
diff --git a/console.h b/console.h
index 67d1373..9c1487e 100644
--- a/console.h
+++ b/console.h
@@ -328,7 +328,12 @@ static inline int ds_get_bytes_per_pixel(DisplayState *ds)
     return ds->surface->pf.bytes_per_pixel;
 }
 
+#ifdef CONFIG_CURSES
+#include <curses.h>
+typedef chtype console_ch_t;
+#else
 typedef unsigned long console_ch_t;
+#endif
 static inline void console_write_ch(console_ch_t *dest, uint32_t ch)
 {
     if (!(ch & 0xff))
commit 3b86b13ab07407fc8c6ac0efbd717fe51df1cad7
Author: Amit Shah <amit.shah at redhat.com>
Date:   Fri Sep 9 14:30:40 2011 +0530

    virtio-balloon: Disassociate from the balloon handlers on unplug
    
    Adding a 2nd balloon device after unplugging the first one doesn't work.
    Also, the 'info balloon' command should indicate an error mentioning no
    balloon device is registered after unplug.
    
    Reproduction steps given by Shaolong Hu:
    
    (qemu) info balloon
    Device 'balloon' has not been activated by the guest
    (qemu) device_add virtio-balloon-pci,id=balloon1
    (qemu) info balloon
    balloon: actual=4096
    (qemu) balloon 2048
    (qemu) info balloon
    balloon: actual=2048
    (qemu) device_del balloon1
    (qemu) info balloon
    balloon: actual=4096
    (qemu) balloon 2048
    (qemu) info balloon
    balloon: actual=4096
    (qemu) device_del balloon1
    Device 'balloon1' not found
    (qemu) device_add virtio-balloon-pci,id=balloon1
    Another balloon device already registered
    Device 'virtio-balloon-pci' could not be initialized
    (qemu) device_add virtio-balloon-pci,id=balloon2
    Another balloon device already registered
    Device 'virtio-balloon-pci' could not be initialized
    
    Reported-by: Shaolong Hu <shu at redhat.com>
    Signed-off-by: Amit Shah <amit.shah at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c
index 072a88a..5f8f4bd 100644
--- a/hw/virtio-balloon.c
+++ b/hw/virtio-balloon.c
@@ -303,6 +303,8 @@ VirtIODevice *virtio_balloon_init(DeviceState *dev)
 void virtio_balloon_exit(VirtIODevice *vdev)
 {
     VirtIOBalloon *s = DO_UPCAST(VirtIOBalloon, vdev, vdev);
+
+    qemu_remove_balloon_handler(s);
     unregister_savevm(s->qdev, "virtio-balloon", s);
     virtio_cleanup(vdev);
 }
commit 8a7d552cb3684570491a5ecaa8b78818404ed2fb
Author: Amit Shah <amit.shah at redhat.com>
Date:   Fri Sep 9 14:30:39 2011 +0530

    balloon: Disassociate handlers from balloon device on unplug
    
    When a balloon device gets unplugged, allow the balloon handlers to be
    freed.
    
    Reported-by: Shaolong Hu <shu at redhat.com>
    Signed-off-by: Amit Shah <amit.shah at redhat.com>
    Signed-off-by: Amit Shah <amit.shah at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/balloon.c b/balloon.c
index f56fdc1..a2133db 100644
--- a/balloon.c
+++ b/balloon.c
@@ -52,6 +52,16 @@ int qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
     return 0;
 }
 
+void qemu_remove_balloon_handler(void *opaque)
+{
+    if (balloon_opaque != opaque) {
+        return;
+    }
+    balloon_event_fn = NULL;
+    balloon_stat_fn = NULL;
+    balloon_opaque = NULL;
+}
+
 static int qemu_balloon(ram_addr_t target)
 {
     if (!balloon_event_fn) {
diff --git a/balloon.h b/balloon.h
index 3df14e6..f59e288 100644
--- a/balloon.h
+++ b/balloon.h
@@ -22,6 +22,7 @@ typedef void (QEMUBalloonStatus)(void *opaque, MonitorCompletion cb,
 
 int qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
 			     QEMUBalloonStatus *stat_func, void *opaque);
+void qemu_remove_balloon_handler(void *opaque);
 
 void monitor_print_balloon(Monitor *mon, const QObject *data);
 int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque);
commit e89720b116131938fe3d4931302f69a28249c934
Author: Thomas Huth <thuth at de.ibm.com>
Date:   Fri Sep 9 15:58:37 2011 +1000

    tcg/ppc64: Fix zero extension code generation bug for ppc64 host
    
    The ppc64 code generation backend uses an rldicr (Rotate Left Double
    Immediate and Clear Right) instruction to implement zero extension of
    a 32 bit quantity to a 64 bit quantity (INDEX_op_ext32u_i64).  However
    this is wrong - this instruction clears specified low bits of the
    value, instead of high bits as we require for a zero extension.  It
    should instead use an rldicl (Rotate Left Double Immediate and Clear
    Left) instruction.
    
    Presumably amongst other things, this causes the SLOF firmware image
    used with -M pseries to not boot on a ppc64 host.
    
    It appears this bug was exposed by commit
    0bf1dbdcc935dfc220a93cd990e947e90706aec6 (tcg/ppc64: fix 16/32 mixup)
    which enabled the use of the op_ext32u_i64 operation on the ppc64
    backend.
    
    Signed-off-by: Thomas Huth <thuth at de.ibm.com>
    Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
    Signed-off-by: malc <av1474 at comtv.ru>

diff --git a/tcg/ppc64/tcg-target.c b/tcg/ppc64/tcg-target.c
index d831684..e3c63ad 100644
--- a/tcg/ppc64/tcg-target.c
+++ b/tcg/ppc64/tcg-target.c
@@ -1560,7 +1560,7 @@ static void tcg_out_op (TCGContext *s, TCGOpcode opc, const TCGArg *args,
         break;
 
     case INDEX_op_ext32u_i64:
-        tcg_out_rld (s, RLDICR, args[0], args[1], 0, 32);
+        tcg_out_rld (s, RLDICL, args[0], args[1], 0, 32);
         break;
 
     case INDEX_op_setcond_i32:
commit 56c119e52ca229869912b22a5bec283487b0cf9b
Author: Anthony PERARD <anthony.perard at citrix.com>
Date:   Fri Sep 9 12:50:18 2011 +0000

    xen-mapcache: Fix rlimit set size.
    
    Previously, the address space soft limit was set mcache_max_size. So,
    before the mcache_max_size was reached by the mapcache, QEMU was killed
    for overuse of the virtual address space.
    
    This patch fix that by setting the soft limit the maximum than can have
    QEMU. So the soft and hard limit are always set to RLIM_INFINITY if QEMU
    is privileged.
    
    In case QEMU is not run as root and the limit is too low, the maximum
    mapcache size will be set the rlim_max - 80MB because observed that QEMU
    use 75MB more than the maximum mapcache size after several empirical
    tests.
    
    Signed-off-by: Anthony PERARD <anthony.perard at citrix.com>
    Signed-off-by: Stefano Stabellini <stefano.stabellini at eu.citrix.com>

diff --git a/xen-mapcache.c b/xen-mapcache.c
index 5b247ee..7bcb86e 100644
--- a/xen-mapcache.c
+++ b/xen-mapcache.c
@@ -40,6 +40,13 @@
 #endif
 #define MCACHE_BUCKET_SIZE (1UL << MCACHE_BUCKET_SHIFT)
 
+/* This is the size of the virtual address space reserve to QEMU that will not
+ * be use by MapCache.
+ * From empirical tests I observed that qemu use 75MB more than the
+ * max_mcache_size.
+ */
+#define NON_MCACHE_MEMORY_SIZE (80 * 1024 * 1024)
+
 #define mapcache_lock()   ((void)0)
 #define mapcache_unlock() ((void)0)
 
@@ -92,15 +99,27 @@ void xen_map_cache_init(void)
     QTAILQ_INIT(&mapcache->locked_entries);
     mapcache->last_address_index = -1;
 
-    getrlimit(RLIMIT_AS, &rlimit_as);
-    if (rlimit_as.rlim_max < MCACHE_MAX_SIZE) {
-        rlimit_as.rlim_cur = rlimit_as.rlim_max;
+    if (geteuid() == 0) {
+        rlimit_as.rlim_cur = RLIM_INFINITY;
+        rlimit_as.rlim_max = RLIM_INFINITY;
+        mapcache->max_mcache_size = MCACHE_MAX_SIZE;
     } else {
-        rlimit_as.rlim_cur = MCACHE_MAX_SIZE;
+        getrlimit(RLIMIT_AS, &rlimit_as);
+        rlimit_as.rlim_cur = rlimit_as.rlim_max;
+
+        if (rlimit_as.rlim_max != RLIM_INFINITY) {
+            fprintf(stderr, "Warning: QEMU's maximum size of virtual"
+                    " memory is not infinity.\n");
+        }
+        if (rlimit_as.rlim_max < MCACHE_MAX_SIZE + NON_MCACHE_MEMORY_SIZE) {
+            mapcache->max_mcache_size = rlimit_as.rlim_max -
+                NON_MCACHE_MEMORY_SIZE;
+        } else {
+            mapcache->max_mcache_size = MCACHE_MAX_SIZE;
+        }
     }
 
     setrlimit(RLIMIT_AS, &rlimit_as);
-    mapcache->max_mcache_size = rlimit_as.rlim_cur;
 
     mapcache->nr_buckets =
         (((mapcache->max_mcache_size >> XC_PAGE_SHIFT) +
commit 2b734340407e9b9f70ba84bb596201ef7027a427
Author: Stefano Stabellini <stefano.stabellini at eu.citrix.com>
Date:   Fri May 20 16:57:24 2011 +0000

    xen: use uint64_t instead of target_ulong in cpu_ioreq_move
    
    cpu_ioreq_move might move 8 bytes at a time so we must make sure that
    the temporary variable can hold 8 bytes.
    
    Signed-off-by: Stefano Stabellini <stefano.stabellini at eu.citrix.com>

diff --git a/xen-all.c b/xen-all.c
index 84420d8..1bc2c3c 100644
--- a/xen-all.c
+++ b/xen-all.c
@@ -620,7 +620,7 @@ static void cpu_ioreq_move(ioreq_t *req)
             }
         }
     } else {
-        target_ulong tmp;
+        uint64_t tmp;
 
         if (req->dir == IOREQ_READ) {
             for (i = 0; i < req->count; i++) {
commit 6d6467305aa62368e086c697f14560c80eac17c5
Author: John Haxby <john.haxby at oracle.com>
Date:   Fri Jun 17 12:16:00 2011 +0000

    Move the xenfb pointer handler to the connected method
    
    Ensure that we read "request-abs-pointer" after the frontend has written
    it.  This means that we will correctly set up an ansolute or relative
    pointer handler correctly.
    
    Signed-off-by: John Haxby <john.haxby at oracle.com>
    Signed-off-by: Stefano Stabellini <stefano.stabellini at eu.citrix.com>

diff --git a/hw/xenfb.c b/hw/xenfb.c
index 3a53711..1bcf171 100644
--- a/hw/xenfb.c
+++ b/hw/xenfb.c
@@ -356,10 +356,6 @@ static int input_initialise(struct XenDevice *xendev)
     struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
     int rc;
 
-    if (xenstore_read_fe_int(xendev, "request-abs-pointer",
-                             &in->abs_pointer_wanted) == -1)
-	in->abs_pointer_wanted = 0;
-
     if (!in->c.ds) {
         char *vfb = xenstore_read_str(NULL, "device/vfb");
         if (vfb == NULL) {
@@ -377,10 +373,24 @@ static int input_initialise(struct XenDevice *xendev)
 	return rc;
 
     qemu_add_kbd_event_handler(xenfb_key_event, in);
+    return 0;
+}
+
+static void input_connected(struct XenDevice *xendev)
+{
+    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
+
+    if (xenstore_read_fe_int(xendev, "request-abs-pointer",
+                             &in->abs_pointer_wanted) == -1) {
+        in->abs_pointer_wanted = 0;
+    }
+
+    if (in->qmouse) {
+        qemu_remove_mouse_event_handler(in->qmouse);
+    }
     in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
 					      in->abs_pointer_wanted,
 					      "Xen PVFB Mouse");
-    return 0;
 }
 
 static void input_disconnect(struct XenDevice *xendev)
@@ -960,6 +970,7 @@ struct XenDevOps xen_kbdmouse_ops = {
     .size       = sizeof(struct XenInput),
     .init       = input_init,
     .initialise = input_initialise,
+    .connected  = input_connected,
     .disconnect = input_disconnect,
     .event      = input_event,
 };
commit 384087b2fec0da72238e92a0c6124579117e0c4b
Author: John Haxby <john.haxby at oracle.com>
Date:   Fri Jun 17 12:15:35 2011 +0000

    Introduce a new 'connected' xendev op called when Connected.
    
    Rename the existing xendev 'connect' op to 'initialised' and introduce
    a new 'connected' op.  This new op, if defined, is called when the
    backend is connected.  Note that since there is no state transition this
    may be called more than once.
    
    Signed-off-by: John Haxby <john.haxby at oracle.com>
    Signed-off-by: Stefano Stabellini <stefano.stabellini at eu.citrix.com>

diff --git a/hw/xen_backend.c b/hw/xen_backend.c
index aa64267..d876cab 100644
--- a/hw/xen_backend.c
+++ b/hw/xen_backend.c
@@ -421,13 +421,13 @@ static int xen_be_try_init(struct XenDevice *xendev)
 }
 
 /*
- * Try to connect xendev.  Depends on the frontend being ready
+ * Try to initialise xendev.  Depends on the frontend being ready
  * for it (shared ring and evtchn info in xenstore, state being
  * Initialised or Connected).
  *
  * Goes to Connected on success.
  */
-static int xen_be_try_connect(struct XenDevice *xendev)
+static int xen_be_try_initialise(struct XenDevice *xendev)
 {
     int rc = 0;
 
@@ -441,11 +441,11 @@ static int xen_be_try_connect(struct XenDevice *xendev)
         }
     }
 
-    if (xendev->ops->connect) {
-        rc = xendev->ops->connect(xendev);
+    if (xendev->ops->initialise) {
+        rc = xendev->ops->initialise(xendev);
     }
     if (rc != 0) {
-        xen_be_printf(xendev, 0, "connect() failed\n");
+        xen_be_printf(xendev, 0, "initialise() failed\n");
         return rc;
     }
 
@@ -454,6 +454,29 @@ static int xen_be_try_connect(struct XenDevice *xendev)
 }
 
 /*
+ * Try to let xendev know that it is connected.  Depends on the
+ * frontend being Connected.  Note that this may be called more
+ * than once since the backend state is not modified.
+ */
+static void xen_be_try_connected(struct XenDevice *xendev)
+{
+    if (!xendev->ops->connected) {
+        return;
+    }
+
+    if (xendev->fe_state != XenbusStateConnected) {
+        if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
+            xen_be_printf(xendev, 2, "frontend not ready, ignoring\n");
+        } else {
+            xen_be_printf(xendev, 2, "frontend not ready (yet)\n");
+            return;
+        }
+    }
+
+    xendev->ops->connected(xendev);
+}
+
+/*
  * Teardown connection.
  *
  * Goes to Closed when done.
@@ -508,7 +531,12 @@ void xen_be_check_state(struct XenDevice *xendev)
             rc = xen_be_try_init(xendev);
             break;
         case XenbusStateInitWait:
-            rc = xen_be_try_connect(xendev);
+            rc = xen_be_try_initialise(xendev);
+            break;
+        case XenbusStateConnected:
+            /* xendev->be_state doesn't change */
+            xen_be_try_connected(xendev);
+            rc = -1;
             break;
         case XenbusStateClosed:
             rc = xen_be_try_reset(xendev);
diff --git a/hw/xen_backend.h b/hw/xen_backend.h
index 6401c85..3305630 100644
--- a/hw/xen_backend.h
+++ b/hw/xen_backend.h
@@ -21,7 +21,8 @@ struct XenDevOps {
     uint32_t  flags;
     void      (*alloc)(struct XenDevice *xendev);
     int       (*init)(struct XenDevice *xendev);
-    int       (*connect)(struct XenDevice *xendev);
+    int       (*initialise)(struct XenDevice *xendev);
+    void      (*connected)(struct XenDevice *xendev);
     void      (*event)(struct XenDevice *xendev);
     void      (*disconnect)(struct XenDevice *xendev);
     int       (*free)(struct XenDevice *xendev);
diff --git a/hw/xen_console.c b/hw/xen_console.c
index 5789bd0..edcb31c 100644
--- a/hw/xen_console.c
+++ b/hw/xen_console.c
@@ -212,7 +212,7 @@ out:
     return ret;
 }
 
-static int con_connect(struct XenDevice *xendev)
+static int con_initialise(struct XenDevice *xendev)
 {
     struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
     int limit;
@@ -273,7 +273,7 @@ struct XenDevOps xen_console_ops = {
     .size       = sizeof(struct XenConsole),
     .flags      = DEVOPS_FLAG_IGNORE_STATE,
     .init       = con_init,
-    .connect    = con_connect,
+    .initialise = con_initialise,
     .event      = con_event,
     .disconnect = con_disconnect,
 };
diff --git a/hw/xen_disk.c b/hw/xen_disk.c
index da531a6..8a9fac4 100644
--- a/hw/xen_disk.c
+++ b/hw/xen_disk.c
@@ -852,7 +852,7 @@ struct XenDevOps xen_blkdev_ops = {
     .flags      = DEVOPS_FLAG_NEED_GNTDEV,
     .alloc      = blk_alloc,
     .init       = blk_init,
-    .connect    = blk_connect,
+    .initialise    = blk_connect,
     .disconnect = blk_disconnect,
     .event      = blk_event,
     .free       = blk_free,
diff --git a/hw/xen_nic.c b/hw/xen_nic.c
index b28b156..aeca8da 100644
--- a/hw/xen_nic.c
+++ b/hw/xen_nic.c
@@ -433,7 +433,7 @@ struct XenDevOps xen_netdev_ops = {
     .size       = sizeof(struct XenNetDev),
     .flags      = DEVOPS_FLAG_NEED_GNTDEV,
     .init       = net_init,
-    .connect    = net_connect,
+    .initialise    = net_connect,
     .event      = net_event,
     .disconnect = net_disconnect,
     .free       = net_free,
diff --git a/hw/xenfb.c b/hw/xenfb.c
index d532d3e..3a53711 100644
--- a/hw/xenfb.c
+++ b/hw/xenfb.c
@@ -351,7 +351,7 @@ static int input_init(struct XenDevice *xendev)
     return 0;
 }
 
-static int input_connect(struct XenDevice *xendev)
+static int input_initialise(struct XenDevice *xendev)
 {
     struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
     int rc;
@@ -865,7 +865,7 @@ static int fb_init(struct XenDevice *xendev)
     return 0;
 }
 
-static int fb_connect(struct XenDevice *xendev)
+static int fb_initialise(struct XenDevice *xendev)
 {
     struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
     struct xenfb_page *fb_page;
@@ -959,7 +959,7 @@ static void fb_event(struct XenDevice *xendev)
 struct XenDevOps xen_kbdmouse_ops = {
     .size       = sizeof(struct XenInput),
     .init       = input_init,
-    .connect    = input_connect,
+    .initialise = input_initialise,
     .disconnect = input_disconnect,
     .event      = input_event,
 };
@@ -967,7 +967,7 @@ struct XenDevOps xen_kbdmouse_ops = {
 struct XenDevOps xen_framebuffer_ops = {
     .size       = sizeof(struct XenFB),
     .init       = fb_init,
-    .connect    = fb_connect,
+    .initialise = fb_initialise,
     .disconnect = fb_disconnect,
     .event      = fb_event,
     .frontend_changed = fb_frontend_changed,
commit 7834cf77be7e3e301177c6ab98a3d7f1bf73f28f
Author: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Date:   Fri Sep 9 15:07:01 2011 +0530

    hw/9pfs: add 9P2000.L unlinkat operation
    
    unlinkat - Remove a directory entry
    
    size[4] Tunlinkat tag[2] dirfid[4] name[s] flag[4]
    size[4] Runlinkat tag[2]
    
    older Tremove have the below request format
    
    size[4] Tremove tag[2] fid[4]
    
    The remove message is used to remove a directory entry either file or directory
    The remove opreation is actually a directory opertation and should ideally have
    dirfid, if not we cannot represent the fid on server with anything other than
    name. We will have to derive the directory name from fid in the Tremove request.
    
    NOTE: The operation doesn't clunk the unlink fid.
    
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>

diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index 0293fe4..d28edb7 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -2338,6 +2338,45 @@ out_nofid:
     complete_pdu(pdu->s, pdu, err);
 }
 
+static void v9fs_unlinkat(void *opaque)
+{
+    int err = 0;
+    V9fsString name;
+    int32_t dfid, flags;
+    size_t offset = 7;
+    V9fsFidState *dfidp;
+    V9fsPDU *pdu = opaque;
+    V9fsString full_name;
+
+    pdu_unmarshal(pdu, offset, "dsd", &dfid, &name, &flags);
+
+    dfidp = get_fid(pdu->s, dfid);
+    if (dfidp == NULL) {
+        err = -EINVAL;
+        goto out_nofid;
+    }
+    v9fs_string_init(&full_name);
+    v9fs_string_sprintf(&full_name, "%s/%s", dfidp->path.data, name.data);
+    /*
+     * IF the file is unlinked, we cannot reopen
+     * the file later. So don't reclaim fd
+     */
+    err = v9fs_mark_fids_unreclaim(pdu->s, &full_name);
+    if (err < 0) {
+        goto out_err;
+    }
+    err = v9fs_co_remove(pdu->s, &full_name);
+    if (!err) {
+        err = offset;
+    }
+out_err:
+    put_fid(pdu->s, dfidp);
+    v9fs_string_free(&full_name);
+out_nofid:
+    complete_pdu(pdu->s, pdu, err);
+    v9fs_string_free(&name);
+}
+
 static int v9fs_complete_rename(V9fsState *s, V9fsFidState *fidp,
                                 int32_t newdirfid, V9fsString *name)
 {
@@ -3040,6 +3079,7 @@ static CoroutineEntry *pdu_co_handlers[] = {
     [P9_TGETLOCK] = v9fs_getlock,
     [P9_TRENAMEAT] = v9fs_renameat,
     [P9_TREADLINK] = v9fs_readlink,
+    [P9_TUNLINKAT] = v9fs_unlinkat,
     [P9_TMKDIR] = v9fs_mkdir,
     [P9_TVERSION] = v9fs_version,
     [P9_TLOPEN] = v9fs_open,
diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
index 4950782..17d44b4 100644
--- a/hw/9pfs/virtio-9p.h
+++ b/hw/9pfs/virtio-9p.h
@@ -52,6 +52,8 @@ enum {
     P9_RMKDIR,
     P9_TRENAMEAT = 74,
     P9_RRENAMEAT,
+    P9_TUNLINKAT = 76,
+    P9_RUNLINKAT,
     P9_TVERSION = 100,
     P9_RVERSION,
     P9_TAUTH = 102,
commit 89bf65938aa9f70e1c903160af509b693bd58c7b
Author: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Date:   Mon May 23 23:24:41 2011 +0530

    hw/9pfs: add 9P2000.L renameat operation
    
    rename - change name of file or directory
    
    size[4] Trenameat tag[2] olddirfid[4] oldname[s] newdirfid[4] newname[s]
    size[4] Rrenameat tag[2]
    
    older Trename have the below request format
    
    size[4] Trename tag[2] fid[4] newdirfid[4] name[s]
    
    The rename message is used to change the name of a file, possibly moving it
    to a new directory. The rename opreation is actually a directory opertation
    and should ideally have olddirfid, if not we cannot represent the fid on server
    with anything other than name. We will have to derive the old directory name
    from fid in the Trename request.
    
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>

diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index 1f186a2..0293fe4 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -2440,6 +2440,87 @@ out_nofid:
     v9fs_string_free(&name);
 }
 
+static int v9fs_complete_renameat(V9fsState *s, int32_t olddirfid,
+                                  V9fsString *old_name, int32_t newdirfid,
+                                  V9fsString *new_name)
+{
+    int err = 0;
+    V9fsString old_full_name, new_full_name;
+    V9fsFidState *newdirfidp = NULL, *olddirfidp = NULL;
+
+    olddirfidp = get_fid(s, olddirfid);
+    if (olddirfidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+    v9fs_string_init(&old_full_name);
+    v9fs_string_init(&new_full_name);
+
+    v9fs_string_sprintf(&old_full_name, "%s/%s",
+                        olddirfidp->path.data, old_name->data);
+    if (newdirfid != -1) {
+        newdirfidp = get_fid(s, newdirfid);
+        if (newdirfidp == NULL) {
+            err = -ENOENT;
+            goto out;
+        }
+        v9fs_string_sprintf(&new_full_name, "%s/%s",
+                            newdirfidp->path.data, new_name->data);
+    } else {
+        v9fs_string_sprintf(&new_full_name, "%s/%s",
+                            olddirfidp->path.data, new_name->data);
+    }
+
+    if (strcmp(old_full_name.data, new_full_name.data) != 0) {
+        V9fsFidState *tfidp;
+        err = v9fs_co_rename(s, &old_full_name, &new_full_name);
+        if (err < 0) {
+            goto out;
+        }
+        /*
+         * Fixup fid's pointing to the old name to
+         * start pointing to the new name
+         */
+        for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
+            if (v9fs_path_is_ancestor(&old_full_name, &tfidp->path)) {
+                /* replace the name */
+                v9fs_fix_path(&tfidp->path, &new_full_name, old_full_name.size);
+            }
+        }
+    }
+out:
+    if (olddirfidp) {
+        put_fid(s, olddirfidp);
+    }
+    if (newdirfidp) {
+        put_fid(s, newdirfidp);
+    }
+    v9fs_string_free(&old_full_name);
+    v9fs_string_free(&new_full_name);
+    return err;
+}
+
+static void v9fs_renameat(void *opaque)
+{
+    ssize_t err = 0;
+    size_t offset = 7;
+    V9fsPDU *pdu = opaque;
+    V9fsState *s = pdu->s;
+    int32_t olddirfid, newdirfid;
+    V9fsString old_name, new_name;
+
+    pdu_unmarshal(pdu, offset, "dsds", &olddirfid,
+                  &old_name, &newdirfid, &new_name);
+
+    err = v9fs_complete_renameat(s, olddirfid, &old_name, newdirfid, &new_name);
+    if (!err) {
+        err = offset;
+    }
+    complete_pdu(s, pdu, err);
+    v9fs_string_free(&old_name);
+    v9fs_string_free(&new_name);
+}
+
 static void v9fs_wstat(void *opaque)
 {
     int32_t fid;
@@ -2957,6 +3038,7 @@ static CoroutineEntry *pdu_co_handlers[] = {
     [P9_TRENAME] = v9fs_rename,
     [P9_TLOCK] = v9fs_lock,
     [P9_TGETLOCK] = v9fs_getlock,
+    [P9_TRENAMEAT] = v9fs_renameat,
     [P9_TREADLINK] = v9fs_readlink,
     [P9_TMKDIR] = v9fs_mkdir,
     [P9_TVERSION] = v9fs_version,
diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
index 9d1b508..4950782 100644
--- a/hw/9pfs/virtio-9p.h
+++ b/hw/9pfs/virtio-9p.h
@@ -50,6 +50,8 @@ enum {
     P9_RLINK,
     P9_TMKDIR = 72,
     P9_RMKDIR,
+    P9_TRENAMEAT = 74,
+    P9_RRENAMEAT,
     P9_TVERSION = 100,
     P9_RVERSION,
     P9_TAUTH = 102,
commit 10e72295bd33af848e96c2ceaad86299ef244da4
Author: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Date:   Mon Aug 8 12:19:51 2011 +0530

    hw/9pfs: Fix memleaks in some 9p operation
    
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>

diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index 91e0957..1f186a2 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -2696,6 +2696,7 @@ out_nofid:
     err = offset;
     err += pdu_marshal(pdu, offset, "b", status);
     complete_pdu(s, pdu, err);
+    v9fs_string_free(&flock->client_id);
     g_free(flock);
 }
 
@@ -2736,6 +2737,7 @@ out:
     put_fid(s, fidp);
 out_nofid:
     complete_pdu(s, pdu, err);
+    v9fs_string_free(&glock->client_id);
     g_free(glock);
 }
 
commit 25427ec1437b63e335a30293b58d47b601373223
Author: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Date:   Tue Aug 2 11:36:24 2011 +0530

    hw/9pfs: Initialize rest of qid field to zero.
    
    Since qid is allocated out of stack we need to intialize
    the field to zero. Otherwise we will send wrong qid value
    to client.
    
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>

diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index 71bc51b..91e0957 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -543,6 +543,7 @@ static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp)
 {
     size_t size;
 
+    memset(&qidp->path, 0, sizeof(qidp->path));
     size = MIN(sizeof(stbuf->st_ino), sizeof(qidp->path));
     memcpy(&qidp->path, &stbuf->st_ino, size);
     qidp->version = stbuf->st_mtime ^ (stbuf->st_size << 8);
commit 407fee0f026faf3296f08231e862799fbc2740c5
Author: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Date:   Thu May 26 14:41:15 2011 +0530

    hw/9pfs: Update the fidp path before opendir
    
    We need to update the fidp path before opendir. Since we don't
    use the fid returned by mkdir, earlier code should not have
    much issue. We do a double v9fs_string_copy here. The later patch
    cleanup the entire function.
    
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>

diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index 94b7090..71bc51b 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -2106,6 +2106,7 @@ static void v9fs_create(void *opaque)
         if (err < 0) {
             goto out;
         }
+        v9fs_string_copy(&fidp->path, &fullname);
         err = v9fs_co_opendir(pdu->s, fidp);
         if (err < 0) {
             goto out;
commit 5a61cb60d6ee8d49c553d7959363df26b55f4873
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Thu Sep 8 17:55:32 2011 +0200

    Fix include statements for qemu-common.h
    
    * qemu-common.h is not a system include file, so it should be included
      with "" instead of <>. Otherwise incremental builds might fail
      because only local include files are checked for changes.
    
    * linux-user/syscall.c included the file twice.
    
    Cc: Riku Voipio <riku.voipio at iki.fi>
    Cc: Jan Kiszka <jan.kiszka at siemens.com>
    Acked-by: Kevin Wolf <kwolf at redhat.com>
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index 4df23f4..d5d4757 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -11,7 +11,7 @@
  *
  */
 
-#include <qemu-common.h>
+#include "qemu-common.h"
 #include "qemu-error.h"
 #include "trace.h"
 #include "blockdev.h"
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 6bdf4e6..e87e174 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -60,7 +60,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
 #include <netinet/ip.h>
 #include <netinet/tcp.h>
 #include <linux/wireless.h>
-#include <qemu-common.h>
+#include "qemu-common.h"
 #ifdef TARGET_GPROF
 #include <sys/gmon.h>
 #endif
@@ -96,7 +96,6 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
 #include "cpu-uname.h"
 
 #include "qemu.h"
-#include "qemu-common.h"
 
 #if defined(CONFIG_USE_NPTL)
 #define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
diff --git a/nbd.h b/nbd.h
index 96f77fe..273cfa1 100644
--- a/nbd.h
+++ b/nbd.h
@@ -21,7 +21,7 @@
 
 #include <sys/types.h>
 
-#include <qemu-common.h>
+#include "qemu-common.h"
 
 #include "block_int.h"
 
diff --git a/qemu-nbd.c b/qemu-nbd.c
index 0b25a4d..3a39145 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -16,7 +16,7 @@
  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <qemu-common.h>
+#include "qemu-common.h"
 #include "block_int.h"
 #include "nbd.h"
 
diff --git a/slirp/libslirp.h b/slirp/libslirp.h
index 67c70e3..a755123 100644
--- a/slirp/libslirp.h
+++ b/slirp/libslirp.h
@@ -1,7 +1,7 @@
 #ifndef _LIBSLIRP_H
 #define _LIBSLIRP_H
 
-#include <qemu-common.h>
+#include "qemu-common.h"
 
 #ifdef CONFIG_SLIRP
 
commit 069d89b8a8dc5a9af4733bca14763b45bbb2546f
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Wed Jul 20 08:27:28 2011 +0200

    virtio-9p: Fix syntax error in debug code
    
    This error was reported by cppcheck:
    
    qemu/hw/9pfs/virtio-9p-debug.c:342:
    error: Invalid number of character ({) when these macros are defined:
    'DEBUG_DATA'.
    
    Cc: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/hw/9pfs/virtio-9p-debug.c b/hw/9pfs/virtio-9p-debug.c
index 4636ad5..96925f0 100644
--- a/hw/9pfs/virtio-9p-debug.c
+++ b/hw/9pfs/virtio-9p-debug.c
@@ -295,7 +295,7 @@ static void pprint_data(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
 
     if (rx) {
         count = pdu->elem.in_num;
-    } else
+    } else {
         count = pdu->elem.out_num;
     }
 
commit 3f9c359507ca3732d1e5669759c95bce098620c5
Author: Nathan Kunkee <nkunkee42 at hotmail.com>
Date:   Thu Sep 8 21:58:31 2011 -0500

    SPARC: Trivial patch to clean up npc monitor output
    
    This patch fixes the spacing of the PC output from 'info cpus' for
    SPARC.
    
    Signed-off-by: Nathan Kunkee <nkunkee42 at hotmail.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/monitor.c b/monitor.c
index df0f622..03ae997 100644
--- a/monitor.c
+++ b/monitor.c
@@ -886,7 +886,7 @@ static void print_cpu_iter(QObject *obj, void *opaque)
     monitor_printf(mon, "nip=0x" TARGET_FMT_lx,
                    (target_long) qdict_get_int(cpu, "nip"));
 #elif defined(TARGET_SPARC)
-    monitor_printf(mon, "pc=0x " TARGET_FMT_lx,
+    monitor_printf(mon, "pc=0x" TARGET_FMT_lx,
                    (target_long) qdict_get_int(cpu, "pc"));
     monitor_printf(mon, "npc=0x" TARGET_FMT_lx,
                    (target_long) qdict_get_int(cpu, "npc"));
commit af2d37de72ea67fddad0d51f5f81d7d7d54fd03a
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Sun Sep 4 18:30:02 2011 +0200

    configure: Avoid duplicate flags when calling compile_prog
    
    This patch removes redundant shell code and cleans it a little bit.
    
    Shell macro compile_prog takes two arguments:
    local_cflags and local ldflags.
    
    $QEMU_CFLAGS is added automatically to the cflags, so there is no need
    to pass it as an argument.
    
    It is also unnecessary to pass -Werror twice.
    
    $flag is a compiler warning option, so it should be in local_cflags
    instead of local_ldflags.
    
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/configure b/configure
index f808f48..348f36a 100755
--- a/configure
+++ b/configure
@@ -1070,7 +1070,7 @@ cat > $TMPC << EOF
 int main(void) { return 0; }
 EOF
 for flag in $gcc_flags; do
-    if compile_prog "-Werror $QEMU_CFLAGS" "-Werror $flag" ; then
+    if compile_prog "$flag -Werror" "" ; then
 	QEMU_CFLAGS="$QEMU_CFLAGS $flag"
     fi
 done
commit c1ba4e0be16f64567bba8210d8fecf37798f3796
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Mon Sep 5 18:13:03 2011 +0200

    qemu-options: Improve help texts for options which depend on configure
    
    * Replace "available only" by the more common "only available".
    
    * Tracing options depend on the configuration of the QEMU executable,
      so clarify the help text for both options.
    
    Cc: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/qemu-options.hx b/qemu-options.hx
index 659ecb2..552d41c 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1412,7 +1412,7 @@ qemu linux.img -net nic,macaddr=52:54:00:12:34:56 \
 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}
 and MODE @var{octalmode} to change default ownership and permissions for
-communication port. This option is available only if QEMU has been compiled
+communication port. This option is only available if QEMU has been compiled
 with vde support enabled.
 
 Example:
@@ -2453,13 +2453,13 @@ Specify tracing options.
 Immediately enable events listed in @var{file}.
 The file must contain one event name (as listed in the @var{trace-events} file)
 per line.
-
-This option is only available when using the @var{simple} and @var{stderr}
-tracing backends.
+This option is only available if QEMU has been compiled with
+either @var{simple} or @var{stderr} tracing backend.
 @item file=@var{file}
 Log output traces to @var{file}.
 
-This option is only available when using the @var{simple} tracing backend.
+This option is only available if QEMU has been compiled with
+the @var{simple} tracing backend.
 @end table
 ETEXI
 
commit 6e93a44bc55550fffee80ea314da0357969eea68
Author: Markus Armbruster <armbru at redhat.com>
Date:   Tue Sep 6 10:01:36 2011 +0200

    docs: Fix qdev-device-use.txt typo in -chardev serial, path=COM<NUM>
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/docs/qdev-device-use.txt b/docs/qdev-device-use.txt
index 057c322..136d271 100644
--- a/docs/qdev-device-use.txt
+++ b/docs/qdev-device-use.txt
@@ -208,7 +208,7 @@ LEGACY-CHARDEV translates to -chardev HOST-OPTS... as follows:
 
 * con: becomes -chardev console
 
-* COM<NUM> becomes -chardev serial,path=<NUM>
+* COM<NUM> becomes -chardev serial,path=COM<NUM>
 
 * file:FNAME becomes -chardev file,path=FNAME
 
commit bca4b9885fc021e5550ac1c488dc0048c2694b79
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Sun Sep 4 15:29:32 2011 +0200

    configure: Remove relicts from --enable-io-thread
    
    Commit 12d4536f7d911b6d87a766ad7300482ea663cea2 removed
    configure option --enable-io-thread.
    
    Remove help message which is now no longer valid.
    
    Cc: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/configure b/configure
index fe3147b..f808f48 100755
--- a/configure
+++ b/configure
@@ -1025,7 +1025,6 @@ echo "  --disable-linux-aio      disable Linux AIO support"
 echo "  --enable-linux-aio       enable Linux AIO support"
 echo "  --disable-attr           disables attr and xattr support"
 echo "  --enable-attr            enable attr and xattr support"
-echo "  --enable-io-thread       enable IO thread"
 echo "  --disable-blobs          disable installing provided firmware blobs"
 echo "  --enable-docs            enable documentation build"
 echo "  --disable-docs           disable documentation build"
commit 60474fb56836d1b4cb091c82371157d9b917047c
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Sun Sep 4 15:17:46 2011 +0200

    Fix comment (install patch -> install path)
    
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/vl.c b/vl.c
index 5ba9b35..c9e1975 100644
--- a/vl.c
+++ b/vl.c
@@ -3061,7 +3061,7 @@ int main(int argc, char **argv, char **envp)
     if (!data_dir) {
         data_dir = os_find_datadir(argv[0]);
     }
-    /* If all else fails use the install patch specified when building.  */
+    /* If all else fails use the install path specified when building. */
     if (!data_dir) {
         data_dir = CONFIG_QEMU_DATADIR;
     }
commit fc9c54124d134dbd76338a92a91804dab2df8166
Author: Johannes Schauer <j.schauer at email.de>
Date:   Sat Aug 6 08:54:12 2011 +0200

    introduce environment variables for all qemu-user options
    
    (Edits by Riku Voipio to apply to current HEAD)
    
    Rework option parsing code for linux-user in a table-driven manner to allow
    environment variables for all commandline options.
    
    Also generate usage() output from option table.
    
    Fix complains from checkpatch.pl, also have envlist global
    
    Signed-off-by: Johannes Schauer <j.schauer at email.de>
    Signed-off-by: Riku Voipio <riku.voipio at linaro.org>

diff --git a/linux-user/main.c b/linux-user/main.c
index 0cc9148..186358b 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -39,6 +39,11 @@
 char *exec_path;
 
 int singlestep;
+const char *filename;
+const char *argv0;
+int gdbstub_port;
+envlist_t *envlist;
+const char *cpu_model;
 unsigned long mmap_min_addr;
 #if defined(CONFIG_USE_GUEST_BASE)
 unsigned long guest_base;
@@ -46,6 +51,8 @@ int have_guest_base;
 unsigned long reserved_va;
 #endif
 
+static void usage(void);
+
 static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
 const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
 
@@ -2879,57 +2886,6 @@ void cpu_loop(CPUS390XState *env)
 
 #endif /* TARGET_S390X */
 
-static void version(void)
-{
-    printf("qemu-" TARGET_ARCH " version " QEMU_VERSION QEMU_PKGVERSION
-           ", Copyright (c) 2003-2008 Fabrice Bellard\n");
-}
-
-static void usage(void)
-{
-    version();
-    printf("usage: qemu-" TARGET_ARCH " [options] program [arguments...]\n"
-           "Linux CPU emulator (compiled for %s emulation)\n"
-           "\n"
-           "Standard options:\n"
-           "-h                print this help\n"
-           "-version          display version information and exit\n"
-           "-g port           wait gdb connection to port\n"
-           "-L path           set the elf interpreter prefix (default=%s)\n"
-           "-s size           set the stack size in bytes (default=%ld)\n"
-           "-cpu model        select CPU (-cpu ? for list)\n"
-           "-drop-ld-preload  drop LD_PRELOAD for target process\n"
-           "-E var=value      sets/modifies targets environment variable(s)\n"
-           "-U var            unsets targets environment variable(s)\n"
-           "-0 argv0          forces target process argv[0] to be argv0\n"
-#if defined(CONFIG_USE_GUEST_BASE)
-           "-B address        set guest_base address to address\n"
-           "-R size           reserve size bytes for guest virtual address space\n"
-#endif
-           "\n"
-           "Debug options:\n"
-           "-d options   activate log (logfile=%s)\n"
-           "-p pagesize  set the host page size to 'pagesize'\n"
-           "-singlestep  always run in singlestep mode\n"
-           "-strace      log system calls\n"
-           "\n"
-           "Environment variables:\n"
-           "QEMU_STRACE       Print system calls and arguments similar to the\n"
-           "                  'strace' program.  Enable by setting to any value.\n"
-           "You can use -E and -U options to set/unset environment variables\n"
-           "for target process.  It is possible to provide several variables\n"
-           "by repeating the option.  For example:\n"
-           "    -E var1=val2 -E var2=val2 -U LD_PRELOAD -U LD_DEBUG\n"
-           "Note that if you provide several changes to single variable\n"
-           "last change will stay in effect.\n"
-           ,
-           TARGET_ARCH,
-           interp_prefix,
-           guest_stack_size,
-           DEBUG_LOGFILE);
-    exit(1);
-}
-
 THREAD CPUState *thread_env;
 
 void task_settid(TaskState *ts)
@@ -2965,26 +2921,358 @@ void init_task_state(TaskState *ts)
     }
     ts->sigqueue_table[i].next = NULL;
 }
- 
+
+static void handle_arg_help(const char *arg)
+{
+    usage();
+}
+
+static void handle_arg_log(const char *arg)
+{
+    int mask;
+    const CPULogItem *item;
+
+    mask = cpu_str_to_log_mask(arg);
+    if (!mask) {
+        printf("Log items (comma separated):\n");
+        for (item = cpu_log_items; item->mask != 0; item++) {
+            printf("%-10s %s\n", item->name, item->help);
+        }
+        exit(1);
+    }
+    cpu_set_log(mask);
+}
+
+static void handle_arg_set_env(const char *arg)
+{
+    char *r, *p, *token;
+    r = p = strdup(arg);
+    while ((token = strsep(&p, ",")) != NULL) {
+        if (envlist_setenv(envlist, token) != 0) {
+            usage();
+        }
+    }
+    free(r);
+}
+
+static void handle_arg_unset_env(const char *arg)
+{
+    char *r, *p, *token;
+    r = p = strdup(arg);
+    while ((token = strsep(&p, ",")) != NULL) {
+        if (envlist_unsetenv(envlist, token) != 0) {
+            usage();
+        }
+    }
+    free(r);
+}
+
+static void handle_arg_argv0(const char *arg)
+{
+    argv0 = strdup(arg);
+}
+
+static void handle_arg_stack_size(const char *arg)
+{
+    char *p;
+    guest_stack_size = strtoul(arg, &p, 0);
+    if (guest_stack_size == 0) {
+        usage();
+    }
+
+    if (*p == 'M') {
+        guest_stack_size *= 1024 * 1024;
+    } else if (*p == 'k' || *p == 'K') {
+        guest_stack_size *= 1024;
+    }
+}
+
+static void handle_arg_ld_prefix(const char *arg)
+{
+    interp_prefix = strdup(arg);
+}
+
+static void handle_arg_pagesize(const char *arg)
+{
+    qemu_host_page_size = atoi(arg);
+    if (qemu_host_page_size == 0 ||
+        (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
+        fprintf(stderr, "page size must be a power of two\n");
+        exit(1);
+    }
+}
+
+static void handle_arg_gdb(const char *arg)
+{
+    gdbstub_port = atoi(arg);
+}
+
+static void handle_arg_uname(const char *arg)
+{
+    qemu_uname_release = strdup(arg);
+}
+
+static void handle_arg_cpu(const char *arg)
+{
+    cpu_model = strdup(arg);
+    if (cpu_model == NULL || strcmp(cpu_model, "?") == 0) {
+        /* XXX: implement xxx_cpu_list for targets that still miss it */
+#if defined(cpu_list_id)
+        cpu_list_id(stdout, &fprintf, "");
+#elif defined(cpu_list)
+        cpu_list(stdout, &fprintf); /* deprecated */
+#endif
+        exit(1);
+    }
+}
+
+#if defined(CONFIG_USE_GUEST_BASE)
+static void handle_arg_guest_base(const char *arg)
+{
+    guest_base = strtol(arg, NULL, 0);
+    have_guest_base = 1;
+}
+
+static void handle_arg_reserved_va(const char *arg)
+{
+    char *p;
+    int shift = 0;
+    reserved_va = strtoul(arg, &p, 0);
+    switch (*p) {
+    case 'k':
+    case 'K':
+        shift = 10;
+        break;
+    case 'M':
+        shift = 20;
+        break;
+    case 'G':
+        shift = 30;
+        break;
+    }
+    if (shift) {
+        unsigned long unshifted = reserved_va;
+        p++;
+        reserved_va <<= shift;
+        if (((reserved_va >> shift) != unshifted)
+#if HOST_LONG_BITS > TARGET_VIRT_ADDR_SPACE_BITS
+            || (reserved_va > (1ul << TARGET_VIRT_ADDR_SPACE_BITS))
+#endif
+            ) {
+            fprintf(stderr, "Reserved virtual address too big\n");
+            exit(1);
+        }
+    }
+    if (*p) {
+        fprintf(stderr, "Unrecognised -R size suffix '%s'\n", p);
+        exit(1);
+    }
+}
+#endif
+
+static void handle_arg_singlestep(const char *arg)
+{
+    singlestep = 1;
+}
+
+static void handle_arg_strace(const char *arg)
+{
+    do_strace = 1;
+}
+
+static void handle_arg_version(const char *arg)
+{
+    printf("qemu-" TARGET_ARCH " version " QEMU_VERSION QEMU_PKGVERSION
+           ", Copyright (c) 2003-2008 Fabrice Bellard\n");
+}
+
+struct qemu_argument {
+    const char *argv;
+    const char *env;
+    bool has_arg;
+    void (*handle_opt)(const char *arg);
+    const char *example;
+    const char *help;
+};
+
+struct qemu_argument arg_table[] = {
+    {"h",          "",                 false, handle_arg_help,
+     "",           "print this help"},
+    {"g",          "QEMU_GDB",         true,  handle_arg_gdb,
+     "port",       "wait gdb connection to 'port'"},
+    {"L",          "QEMU_LD_PREFIX",   true,  handle_arg_ld_prefix,
+     "path",       "set the elf interpreter prefix to 'path'"},
+    {"s",          "QEMU_STACK_SIZE",  true,  handle_arg_stack_size,
+     "size",       "set the stack size to 'size' bytes"},
+    {"cpu",        "QEMU_CPU",         true,  handle_arg_cpu,
+     "model",      "select CPU (-cpu ? for list)"},
+    {"E",          "QEMU_SET_ENV",     true,  handle_arg_set_env,
+     "var=value",  "sets targets environment variable (see below)"},
+    {"U",          "QEMU_UNSET_ENV",   true,  handle_arg_unset_env,
+     "var",        "unsets targets environment variable (see below)"},
+    {"0",          "QEMU_ARGV0",       true,  handle_arg_argv0,
+     "argv0",      "forces target process argv[0] to be 'argv0'"},
+    {"r",          "QEMU_UNAME",       true,  handle_arg_uname,
+     "uname",      "set qemu uname release string to 'uname'"},
+#if defined(CONFIG_USE_GUEST_BASE)
+    {"B",          "QEMU_GUEST_BASE",  true,  handle_arg_guest_base,
+     "address",    "set guest_base address to 'address'"},
+    {"R",          "QEMU_RESERVED_VA", true,  handle_arg_reserved_va,
+     "size",       "reserve 'size' bytes for guest virtual address space"},
+#endif
+    {"d",          "QEMU_LOG",         true,  handle_arg_log,
+     "options",    "activate log"},
+    {"p",          "QEMU_PAGESIZE",    true,  handle_arg_pagesize,
+     "pagesize",   "set the host page size to 'pagesize'"},
+    {"singlestep", "QEMU_SINGLESTEP",  false, handle_arg_singlestep,
+     "",           "run in singlestep mode"},
+    {"strace",     "QEMU_STRACE",      false, handle_arg_strace,
+     "",           "log system calls"},
+    {"version",    "QEMU_VERSION",     false, handle_arg_version,
+     "",           "log system calls"},
+    {NULL, NULL, false, NULL, NULL, NULL}
+};
+
+static void usage(void)
+{
+    struct qemu_argument *arginfo;
+    int maxarglen;
+    int maxenvlen;
+
+    printf("usage: qemu-" TARGET_ARCH " [options] program [arguments...]\n"
+           "Linux CPU emulator (compiled for " TARGET_ARCH " emulation)\n"
+           "\n"
+           "Options and associated environment variables:\n"
+           "\n");
+
+    maxarglen = maxenvlen = 0;
+
+    for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
+        if (strlen(arginfo->env) > maxenvlen) {
+            maxenvlen = strlen(arginfo->env);
+        }
+        if (strlen(arginfo->argv) > maxarglen) {
+            maxarglen = strlen(arginfo->argv);
+        }
+    }
+
+    printf("%-*s%-*sDescription\n", maxarglen+3, "Argument",
+            maxenvlen+1, "Env-variable");
+
+    for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
+        if (arginfo->has_arg) {
+            printf("-%s %-*s %-*s %s\n", arginfo->argv,
+                    (int)(maxarglen-strlen(arginfo->argv)), arginfo->example,
+                    maxenvlen, arginfo->env, arginfo->help);
+        } else {
+            printf("-%-*s %-*s %s\n", maxarglen+1, arginfo->argv,
+                    maxenvlen, arginfo->env,
+                    arginfo->help);
+        }
+    }
+
+    printf("\n"
+           "Defaults:\n"
+           "QEMU_LD_PREFIX  = %s\n"
+           "QEMU_STACK_SIZE = %ld byte\n"
+           "QEMU_LOG        = %s\n",
+           interp_prefix,
+           guest_stack_size,
+           DEBUG_LOGFILE);
+
+    printf("\n"
+           "You can use -E and -U options or the QEMU_SET_ENV and\n"
+           "QEMU_UNSET_ENV environment variables to set and unset\n"
+           "environment variables for the target process.\n"
+           "It is possible to provide several variables by separating them\n"
+           "by commas in getsubopt(3) style. Additionally it is possible to\n"
+           "provide the -E and -U options multiple times.\n"
+           "The following lines are equivalent:\n"
+           "    -E var1=val2 -E var2=val2 -U LD_PRELOAD -U LD_DEBUG\n"
+           "    -E var1=val2,var2=val2 -U LD_PRELOAD,LD_DEBUG\n"
+           "    QEMU_SET_ENV=var1=val2,var2=val2 QEMU_UNSET_ENV=LD_PRELOAD,LD_DEBUG\n"
+           "Note that if you provide several changes to a single variable\n"
+           "the last change will stay in effect.\n");
+
+    exit(1);
+}
+
+static int parse_args(int argc, char **argv)
+{
+    const char *r;
+    int optind;
+    struct qemu_argument *arginfo;
+
+    for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
+        if (arginfo->env == NULL) {
+            continue;
+        }
+
+        r = getenv(arginfo->env);
+        if (r != NULL) {
+            arginfo->handle_opt(r);
+        }
+    }
+
+    optind = 1;
+    for (;;) {
+        if (optind >= argc) {
+            break;
+        }
+        r = argv[optind];
+        if (r[0] != '-') {
+            break;
+        }
+        optind++;
+        r++;
+        if (!strcmp(r, "-")) {
+            break;
+        }
+
+        for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
+            if (!strcmp(r, arginfo->argv)) {
+                if (optind >= argc) {
+                    usage();
+                }
+
+                arginfo->handle_opt(argv[optind]);
+
+                if (arginfo->has_arg) {
+                    optind++;
+                }
+
+                break;
+            }
+        }
+
+        /* no option matched the current argv */
+        if (arginfo->handle_opt == NULL) {
+            usage();
+        }
+    }
+
+    if (optind >= argc) {
+        usage();
+    }
+
+    filename = argv[optind];
+    exec_path = argv[optind];
+
+    return optind;
+}
+
 int main(int argc, char **argv, char **envp)
 {
-    const char *filename;
-    const char *cpu_model;
     const char *log_file = DEBUG_LOGFILE;
-    const char *log_mask = NULL;
     struct target_pt_regs regs1, *regs = &regs1;
     struct image_info info1, *info = &info1;
     struct linux_binprm bprm;
     TaskState *ts;
     CPUState *env;
     int optind;
-    const char *r;
-    int gdbstub_port = 0;
     char **target_environ, **wrk;
     char **target_argv;
     int target_argc;
-    envlist_t *envlist = NULL;
-    const char *argv0 = NULL;
     int i;
     int ret;
 
@@ -3019,156 +3307,9 @@ int main(int argc, char **argv, char **envp)
     cpudef_setup(); /* parse cpu definitions in target config file (TBD) */
 #endif
 
-    optind = 1;
-    for(;;) {
-        if (optind >= argc)
-            break;
-        r = argv[optind];
-        if (r[0] != '-')
-            break;
-        optind++;
-        r++;
-        if (!strcmp(r, "-")) {
-            break;
-        } else if (!strcmp(r, "d")) {
-            if (optind >= argc) {
-		break;
-            }
-            log_mask = argv[optind++];
-        } else if (!strcmp(r, "D")) {
-            if (optind >= argc) {
-                break;
-            }
-            log_file = argv[optind++];
-        } else if (!strcmp(r, "E")) {
-            r = argv[optind++];
-            if (envlist_setenv(envlist, r) != 0)
-                usage();
-        } else if (!strcmp(r, "ignore-environment")) {
-            envlist_free(envlist);
-            if ((envlist = envlist_create()) == NULL) {
-                (void) fprintf(stderr, "Unable to allocate envlist\n");
-                exit(1);
-            }
-        } else if (!strcmp(r, "U")) {
-            r = argv[optind++];
-            if (envlist_unsetenv(envlist, r) != 0)
-                usage();
-        } else if (!strcmp(r, "0")) {
-            r = argv[optind++];
-            argv0 = r;
-        } else if (!strcmp(r, "s")) {
-            if (optind >= argc)
-                break;
-            r = argv[optind++];
-            guest_stack_size = strtoul(r, (char **)&r, 0);
-            if (guest_stack_size == 0)
-                usage();
-            if (*r == 'M')
-                guest_stack_size *= 1024 * 1024;
-            else if (*r == 'k' || *r == 'K')
-                guest_stack_size *= 1024;
-        } else if (!strcmp(r, "L")) {
-            interp_prefix = argv[optind++];
-        } else if (!strcmp(r, "p")) {
-            if (optind >= argc)
-                break;
-            qemu_host_page_size = atoi(argv[optind++]);
-            if (qemu_host_page_size == 0 ||
-                (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
-                fprintf(stderr, "page size must be a power of two\n");
-                exit(1);
-            }
-        } else if (!strcmp(r, "g")) {
-            if (optind >= argc)
-                break;
-            gdbstub_port = atoi(argv[optind++]);
-	} else if (!strcmp(r, "r")) {
-	    qemu_uname_release = argv[optind++];
-        } else if (!strcmp(r, "cpu")) {
-            cpu_model = argv[optind++];
-            if (cpu_model == NULL || strcmp(cpu_model, "?") == 0) {
-/* XXX: implement xxx_cpu_list for targets that still miss it */
-#if defined(cpu_list_id)
-                cpu_list_id(stdout, &fprintf, "");
-#elif defined(cpu_list)
-                cpu_list(stdout, &fprintf); /* deprecated */
-#endif
-                exit(1);
-            }
-#if defined(CONFIG_USE_GUEST_BASE)
-        } else if (!strcmp(r, "B")) {
-           guest_base = strtol(argv[optind++], NULL, 0);
-           have_guest_base = 1;
-        } else if (!strcmp(r, "R")) {
-            char *p;
-            int shift = 0;
-            reserved_va = strtoul(argv[optind++], &p, 0);
-            switch (*p) {
-            case 'k':
-            case 'K':
-                shift = 10;
-                break;
-            case 'M':
-                shift = 20;
-                break;
-            case 'G':
-                shift = 30;
-                break;
-            }
-            if (shift) {
-                unsigned long unshifted = reserved_va;
-                p++;
-                reserved_va <<= shift;
-                if (((reserved_va >> shift) != unshifted)
-#if HOST_LONG_BITS > TARGET_VIRT_ADDR_SPACE_BITS
-                    || (reserved_va > (1ul << TARGET_VIRT_ADDR_SPACE_BITS))
-#endif
-                    ) {
-                    fprintf(stderr, "Reserved virtual address too big\n");
-                    exit(1);
-                }
-            }
-            if (*p) {
-                fprintf(stderr, "Unrecognised -R size suffix '%s'\n", p);
-                exit(1);
-            }
-#endif
-        } else if (!strcmp(r, "drop-ld-preload")) {
-            (void) envlist_unsetenv(envlist, "LD_PRELOAD");
-        } else if (!strcmp(r, "singlestep")) {
-            singlestep = 1;
-        } else if (!strcmp(r, "strace")) {
-            do_strace = 1;
-        } else if (!strcmp(r, "version")) {
-            version();
-            exit(0);
-        } else {
-            usage();
-        }
-    }
     /* init debug */
     cpu_set_log_filename(log_file);
-    if (log_mask) {
-        int mask;
-        const CPULogItem *item;
-
-        mask = cpu_str_to_log_mask(log_mask);
-        if (!mask) {
-            printf("Log items (comma separated):\n");
-            for (item = cpu_log_items; item->mask != 0; item++) {
-                printf("%-10s %s\n", item->name, item->help);
-            }
-            exit(1);
-        }
-        cpu_set_log(mask);
-    }
-
-    if (optind >= argc) {
-        usage();
-    }
-    filename = argv[optind];
-    exec_path = argv[optind];
+    optind = parse_args(argc, argv);
 
     /* Zero out regs */
     memset(regs, 0, sizeof(struct target_pt_regs));
commit a790ae389bf779424789dc6ddc946ea268d58c42
Author: An-Cheng Huang <ancheng at ubnt.com>
Date:   Tue Aug 9 12:34:06 2011 -0700

    linux-user: Implement setxattr/getxattr/removexattr syscalls
    
    This patch implements the setxattr, getxattr, and removexattr syscalls
    if CONFIG_ATTR is enabled.
    
    Note that since libattr uses indirect syscalls for these, this change
    depends on the fix for indirect syscall handling on MIPS.
    
    Signed-off-by: Riku Voipio <riku.voipio at linaro.org>
    Reviewed-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: An-Cheng Huang <ancheng at ubnt.com>

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index ae08c9e..39a34db 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -70,6 +70,9 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
 #ifdef CONFIG_EPOLL
 #include <sys/epoll.h>
 #endif
+#ifdef CONFIG_ATTR
+#include <attr/xattr.h>
+#endif
 
 #define termios host_termios
 #define winsize host_winsize
@@ -7642,22 +7645,67 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 #endif
         break;
 #endif
+#ifdef CONFIG_ATTR
 #ifdef TARGET_NR_setxattr
-    case TARGET_NR_setxattr:
     case TARGET_NR_lsetxattr:
     case TARGET_NR_fsetxattr:
-    case TARGET_NR_getxattr:
     case TARGET_NR_lgetxattr:
     case TARGET_NR_fgetxattr:
     case TARGET_NR_listxattr:
     case TARGET_NR_llistxattr:
     case TARGET_NR_flistxattr:
-    case TARGET_NR_removexattr:
     case TARGET_NR_lremovexattr:
     case TARGET_NR_fremovexattr:
         ret = -TARGET_EOPNOTSUPP;
         break;
+    case TARGET_NR_setxattr:
+        {
+            void *p, *n, *v;
+            p = lock_user_string(arg1);
+            n = lock_user_string(arg2);
+            v = lock_user(VERIFY_READ, arg3, arg4, 1);
+            if (p && n && v) {
+                ret = get_errno(setxattr(p, n, v, arg4, arg5));
+            } else {
+                ret = -TARGET_EFAULT;
+            }
+            unlock_user(p, arg1, 0);
+            unlock_user(n, arg2, 0);
+            unlock_user(v, arg3, 0);
+        }
+        break;
+    case TARGET_NR_getxattr:
+        {
+            void *p, *n, *v;
+            p = lock_user_string(arg1);
+            n = lock_user_string(arg2);
+            v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
+            if (p && n && v) {
+                ret = get_errno(getxattr(p, n, v, arg4));
+            } else {
+                ret = -TARGET_EFAULT;
+            }
+            unlock_user(p, arg1, 0);
+            unlock_user(n, arg2, 0);
+            unlock_user(v, arg3, arg4);
+        }
+        break;
+    case TARGET_NR_removexattr:
+        {
+            void *p, *n;
+            p = lock_user_string(arg1);
+            n = lock_user_string(arg2);
+            if (p && n) {
+                ret = get_errno(removexattr(p, n));
+            } else {
+                ret = -TARGET_EFAULT;
+            }
+            unlock_user(p, arg1, 0);
+            unlock_user(n, arg2, 0);
+        }
+        break;
 #endif
+#endif /* CONFIG_ATTR */
 #ifdef TARGET_NR_set_thread_area
     case TARGET_NR_set_thread_area:
 #if defined(TARGET_MIPS)
commit 94c19610a6973ad917d9c154eabfc2ee27bc4f59
Author: An-Cheng Huang <ancheng at ubnt.com>
Date:   Tue Aug 9 12:32:38 2011 -0700

    linux-user: Verify MIPS syscall arguments
    
    On MIPS, some syscall arguments are taken from the stack. This patch adds
    verification such that do_syscall() is only invoked if all arguments
    have been successfully taken from the stack.
    
    Signed-off-by: Riku Voipio <riku.voipio at linaro.org>
    Reviewed-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: An-Cheng Huang <ancheng at ubnt.com>

diff --git a/linux-user/main.c b/linux-user/main.c
index 3df91f3..0cc9148 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -2170,11 +2170,22 @@ void cpu_loop(CPUMIPSState *env)
                 sp_reg = env->active_tc.gpr[29];
                 switch (nb_args) {
                 /* these arguments are taken from the stack */
-                /* FIXME - what to do if get_user() fails? */
-                case 8: get_user_ual(arg8, sp_reg + 28);
-                case 7: get_user_ual(arg7, sp_reg + 24);
-                case 6: get_user_ual(arg6, sp_reg + 20);
-                case 5: get_user_ual(arg5, sp_reg + 16);
+                case 8:
+                    if ((ret = get_user_ual(arg8, sp_reg + 28)) != 0) {
+                        goto done_syscall;
+                    }
+                case 7:
+                    if ((ret = get_user_ual(arg7, sp_reg + 24)) != 0) {
+                        goto done_syscall;
+                    }
+                case 6:
+                    if ((ret = get_user_ual(arg6, sp_reg + 20)) != 0) {
+                        goto done_syscall;
+                    }
+                case 5:
+                    if ((ret = get_user_ual(arg5, sp_reg + 16)) != 0) {
+                        goto done_syscall;
+                    }
                 default:
                     break;
                 }
@@ -2185,6 +2196,7 @@ void cpu_loop(CPUMIPSState *env)
                                  env->active_tc.gpr[7],
                                  arg5, arg6, arg7, arg8);
             }
+done_syscall:
             if (ret == -TARGET_QEMU_ESIGRETURN) {
                 /* Returning from a successful sigreturn syscall.
                    Avoid clobbering register state.  */
commit 29fb0f25303a76edb100362eaea59b6f74bdb823
Author: An-Cheng Huang <ancheng at ubnt.com>
Date:   Tue Aug 9 12:31:41 2011 -0700

    linux-user: Fix MIPS indirect syscall handling
    
    Change the number of argument for MIPS sys_syscall from 0 to 8. This
    allows arguments for indirect syscalls to be processed correctly.
    
    Signed-off-by: Riku Voipio <riku.voipio at linaro.org>
    Reviewed-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: An-Cheng Huang <ancheng at ubnt.com>

diff --git a/linux-user/main.c b/linux-user/main.c
index 8910d2c..3df91f3 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -1749,7 +1749,7 @@ void cpu_loop(CPUPPCState *env)
 #define MIPS_SYS(name, args) args,
 
 static const uint8_t mips_syscall_args[] = {
-	MIPS_SYS(sys_syscall	, 0)	/* 4000 */
+	MIPS_SYS(sys_syscall	, 8)	/* 4000 */
 	MIPS_SYS(sys_exit	, 1)
 	MIPS_SYS(sys_fork	, 0)
 	MIPS_SYS(sys_read	, 3)
commit ff7a981affbbc4f19f6f92143a3ddff90a1363fe
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Tue Sep 6 14:15:50 2011 +0100

    linux-user: Exit with an error if we couldn't set up gdbserver
    
    If gdbserver_start() fails (usually because we couldn't bind to the
    requested TCP port) then exit qemu rather than blithely continuing.
    This brings the linux-user behaviour in to line with system mode.
    
    Signed-off-by: Riku Voipio <riku.voipio at linaro.org>
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

diff --git a/linux-user/main.c b/linux-user/main.c
index 25cb4dd..8910d2c 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -3655,7 +3655,11 @@ int main(int argc, char **argv, char **envp)
 #endif
 
     if (gdbstub_port) {
-        gdbserver_start (gdbstub_port);
+        if (gdbserver_start(gdbstub_port) < 0) {
+            fprintf(stderr, "qemu: could not open gdbserver on port %d\n",
+                    gdbstub_port);
+            exit(1);
+        }
         gdb_handlesig(env, 0);
     }
     cpu_loop(env);
commit 97cc75606aef406e90a243cdb25347039003e7f0
Author: Dr. David Alan Gilbert <david.gilbert at linaro.org>
Date:   Wed Aug 31 17:24:34 2011 +0100

    linux-user: Implement new ARM 64 bit cmpxchg kernel helper
    
    linux-user: Implement new ARM 64 bit cmpxchg kernel helper
    
    Linux 3.1 will have a new kernel-page helper for ARM implementing
    64 bit cmpxchg. Implement this helper in QEMU linux-user mode:
     * Provide kernel helper emulation for 64bit cmpxchg
     * Allow guest to object to guest offset to ensure it can map a page
     * Populate page with kernel helper version
    
    Signed-off-by: Riku Voipio <riku.voipio at linaro.org>
    Reviewed-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Dr. David Alan Gilbert <david.gilbert at linaro.org>

diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 04e8e6e..8677bba 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -332,6 +332,49 @@ enum
     ARM_HWCAP_ARM_VFPv3D16  = 1 << 13,
 };
 
+#define TARGET_HAS_GUEST_VALIDATE_BASE
+/* We want the opportunity to check the suggested base */
+bool guest_validate_base(unsigned long guest_base)
+{
+    unsigned long real_start, test_page_addr;
+
+    /* We need to check that we can force a fault on access to the
+     * commpage at 0xffff0fxx
+     */
+    test_page_addr = guest_base + (0xffff0f00 & qemu_host_page_mask);
+    /* Note it needs to be writeable to let us initialise it */
+    real_start = (unsigned long)
+                 mmap((void *)test_page_addr, qemu_host_page_size,
+                     PROT_READ | PROT_WRITE,
+                     MAP_ANONYMOUS | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+    /* If we can't map it then try another address */
+    if (real_start == -1ul) {
+        return 0;
+    }
+
+    if (real_start != test_page_addr) {
+        /* OS didn't put the page where we asked - unmap and reject */
+        munmap((void *)real_start, qemu_host_page_size);
+        return 0;
+    }
+
+    /* Leave the page mapped
+     * Populate it (mmap should have left it all 0'd)
+     */
+
+    /* Kernel helper versions */
+    __put_user(5, (uint32_t *)g2h(0xffff0ffcul));
+
+    /* Now it's populated make it RO */
+    if (mprotect((void *)test_page_addr, qemu_host_page_size, PROT_READ)) {
+        perror("Protecting guest commpage");
+        exit(-1);
+    }
+
+    return 1; /* All good */
+}
+
 #define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF               \
                    | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT      \
                    | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP              \
@@ -1309,6 +1352,14 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
     return sp;
 }
 
+#ifndef TARGET_HAS_GUEST_VALIDATE_BASE
+/* If the guest doesn't have a validation function just agree */
+bool guest_validate_base(unsigned long guest_base)
+{
+    return 1;
+}
+#endif
+
 static void probe_guest_base(const char *image_name,
                              abi_ulong loaddr, abi_ulong hiaddr)
 {
@@ -1345,7 +1396,9 @@ static void probe_guest_base(const char *image_name,
             if (real_start == (unsigned long)-1) {
                 goto exit_perror;
             }
-            if (real_start == host_start) {
+            guest_base = real_start - loaddr;
+            if ((real_start == host_start) &&
+                guest_validate_base(guest_base)) {
                 break;
             }
             /* That address didn't work.  Unmap and try a different one.
@@ -1368,7 +1421,6 @@ static void probe_guest_base(const char *image_name,
         qemu_log("Relocating guest address space from 0x"
                  TARGET_ABI_FMT_lx " to 0x%lx\n",
                  loaddr, real_start);
-        guest_base = real_start - loaddr;
     }
     return;
 
diff --git a/linux-user/main.c b/linux-user/main.c
index 89a51d7..25cb4dd 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -456,6 +456,83 @@ void cpu_loop(CPUX86State *env)
 
 #ifdef TARGET_ARM
 
+/*
+ * See the Linux kernel's Documentation/arm/kernel_user_helpers.txt
+ * Input:
+ * r0 = pointer to oldval
+ * r1 = pointer to newval
+ * r2 = pointer to target value
+ *
+ * Output:
+ * r0 = 0 if *ptr was changed, non-0 if no exchange happened
+ * C set if *ptr was changed, clear if no exchange happened
+ *
+ * Note segv's in kernel helpers are a bit tricky, we can set the
+ * data address sensibly but the PC address is just the entry point.
+ */
+static void arm_kernel_cmpxchg64_helper(CPUARMState *env)
+{
+    uint64_t oldval, newval, val;
+    uint32_t addr, cpsr;
+    target_siginfo_t info;
+
+    /* Based on the 32 bit code in do_kernel_trap */
+
+    /* XXX: This only works between threads, not between processes.
+       It's probably possible to implement this with native host
+       operations. However things like ldrex/strex are much harder so
+       there's not much point trying.  */
+    start_exclusive();
+    cpsr = cpsr_read(env);
+    addr = env->regs[2];
+
+    if (get_user_u64(oldval, env->regs[0])) {
+        env->cp15.c6_data = env->regs[0];
+        goto segv;
+    };
+
+    if (get_user_u64(newval, env->regs[1])) {
+        env->cp15.c6_data = env->regs[1];
+        goto segv;
+    };
+
+    if (get_user_u64(val, addr)) {
+        env->cp15.c6_data = addr;
+        goto segv;
+    }
+
+    if (val == oldval) {
+        val = newval;
+
+        if (put_user_u64(val, addr)) {
+            env->cp15.c6_data = addr;
+            goto segv;
+        };
+
+        env->regs[0] = 0;
+        cpsr |= CPSR_C;
+    } else {
+        env->regs[0] = -1;
+        cpsr &= ~CPSR_C;
+    }
+    cpsr_write(env, cpsr, CPSR_C);
+    end_exclusive();
+    return;
+
+segv:
+    end_exclusive();
+    /* We get the PC of the entry address - which is as good as anything,
+       on a real kernel what you get depends on which mode it uses. */
+    info.si_signo = SIGSEGV;
+    info.si_errno = 0;
+    /* XXX: check env->error_code */
+    info.si_code = TARGET_SEGV_MAPERR;
+    info._sifields._sigfault._addr = env->cp15.c6_data;
+    queue_signal(env, info.si_signo, &info);
+
+    end_exclusive();
+}
+
 /* Handle a jump to the kernel code page.  */
 static int
 do_kernel_trap(CPUARMState *env)
@@ -495,6 +572,10 @@ do_kernel_trap(CPUARMState *env)
     case 0xffff0fe0: /* __kernel_get_tls */
         env->regs[0] = env->cp15.c13_tls2;
         break;
+    case 0xffff0f60: /* __kernel_cmpxchg64 */
+        arm_kernel_cmpxchg64_helper(env);
+        break;
+
     default:
         return 1;
     }
@@ -752,7 +833,6 @@ void cpu_loop(CPUARMState *env)
             goto do_segv;
         case EXCP_DATA_ABORT:
             addr = env->cp15.c6_data;
-            goto do_segv;
         do_segv:
             {
                 info.si_signo = SIGSEGV;
@@ -3180,6 +3260,13 @@ int main(int argc, char **argv, char **envp)
         }
         qemu_log("Reserved 0x%lx bytes of guest address space\n", reserved_va);
     }
+
+    if (reserved_va || have_guest_base) {
+        if (!guest_validate_base(guest_base)) {
+            fprintf(stderr, "Guest base/Reserved VA rejected by guest code\n");
+            exit(1);
+        }
+    }
 #endif /* CONFIG_USE_GUEST_BASE */
 
     /*
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 627c8b3..55ad9d8 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -202,6 +202,12 @@ int get_osversion(void);
 void fork_start(void);
 void fork_end(int child);
 
+/* Return true if the proposed guest_base is suitable for the guest.
+ * The guest code may leave a page mapped and populate it if the
+ * address is suitable.
+ */
+bool guest_validate_base(unsigned long guest_base);
+
 #include "qemu-log.h"
 
 /* strace.c */
commit 70afc343c75ecc8895b9308ee6a15fcc7a3b0f3e
Author: Cédric VINCENT <cedric.vincent at st.com>
Date:   Fri Aug 26 10:56:50 2011 +0200

    linux-user: Fix initialization of the heap contents when allocating new pages
    
    Technically the new mmapped pages are already initialized to zero
    since they are anonymous, however we have to take care with the
    contents that come from the remaining part of the previous page: it
    may contains garbage data due to a previous heap usage (grown then
    shrunken).
    
    This patch completes commit 55f08c84.  The problem could be reproduced
    when emulating the build process of Perl 5.12.3 on ARMedSlack 13.37:
    
        make[1]: Entering directory `/tmp/perl-5.12.3/cpan/Compress-Raw-Bzip2'
        cc -c  -I. -fno-strict-aliasing -pipe -fstack-protector                 \
               -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64  \
               -O2   -DVERSION=\"2.024\" -DXS_VERSION=\"2.024\" -fPIC "-I../.." \
               -DBZ_NO_STDIO  decompress.c
        decompress.c: In function 'BZ2_decompress':
        decompress.c:621:1: internal compiler error: Segmentation fault
    
    Signed-off-by: Riku Voipio <riku.voipio at linaro.org>
    Signed-off-by: Laurent ALFONSI <laurent.alfonsi at st.com>
    Signed-off-by: Cédric VINCENT <cedric.vincent at st.com>

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 6bdf4e6..ae08c9e 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -797,6 +797,15 @@ abi_long do_brk(abi_ulong new_brk)
                                         MAP_ANON|MAP_PRIVATE, 0, 0));
 
     if (mapped_addr == brk_page) {
+        /* Heap contents are initialized to zero, as for anonymous
+         * mapped pages.  Technically the new pages are already
+         * initialized to zero since they *are* anonymous mapped
+         * pages, however we have to take care with the contents that
+         * come from the remaining part of the previous page: it may
+         * contains garbage data due to a previous heap usage (grown
+         * then shrunken).  */
+        memset(g2h(target_brk), 0, brk_page - target_brk);
+
         target_brk = new_brk;
         brk_page = HOST_PAGE_ALIGN(target_brk);
         DEBUGF_BRK("%#010x (mapped_addr == brk_page)\n", target_brk);
commit 07ff2c4475df77e38a31d50ee7f3932631806c15
Merge: 573da34... 8278604...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Sep 8 09:25:36 2011 -0500

    Merge remote-tracking branch 'origin/master' into staging

commit 8278604134e36f7f96612c2fda3b615787e5b692
Author: Richard Henderson <rth at twiddle.net>
Date:   Thu Sep 8 09:23:11 2011 +0100

    target-i386: Compute all flag data inside %cl != 0 test.
    
    The (x << (cl - 1)) quantity is only used if CL != 0.  Move the
    computation of that quantity nearer its use.
    
    This avoids the creation of undefined TCG operations when the
    constant propagation optimization proves that CL == 0, and thus
    CL-1 is outside the range [0-wordsize).
    
    Signed-off-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: malc <av1474 at comtv.ru>

diff --git a/target-i386/translate.c b/target-i386/translate.c
index ccef381..b966762 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -1406,70 +1406,84 @@ static void gen_shift_rm_T1(DisasContext *s, int ot, int op1,
 {
     target_ulong mask;
     int shift_label;
-    TCGv t0, t1;
+    TCGv t0, t1, t2;
 
-    if (ot == OT_QUAD)
+    if (ot == OT_QUAD) {
         mask = 0x3f;
-    else
+    } else {
         mask = 0x1f;
+    }
 
     /* load */
-    if (op1 == OR_TMP0)
+    if (op1 == OR_TMP0) {
         gen_op_ld_T0_A0(ot + s->mem_index);
-    else
+    } else {
         gen_op_mov_TN_reg(ot, 0, op1);
+    }
 
-    tcg_gen_andi_tl(cpu_T[1], cpu_T[1], mask);
+    t0 = tcg_temp_local_new();
+    t1 = tcg_temp_local_new();
+    t2 = tcg_temp_local_new();
 
-    tcg_gen_addi_tl(cpu_tmp5, cpu_T[1], -1);
+    tcg_gen_andi_tl(t2, cpu_T[1], mask);
 
     if (is_right) {
         if (is_arith) {
             gen_exts(ot, cpu_T[0]);
-            tcg_gen_sar_tl(cpu_T3, cpu_T[0], cpu_tmp5);
-            tcg_gen_sar_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
+            tcg_gen_mov_tl(t0, cpu_T[0]);
+            tcg_gen_sar_tl(cpu_T[0], cpu_T[0], t2);
         } else {
             gen_extu(ot, cpu_T[0]);
-            tcg_gen_shr_tl(cpu_T3, cpu_T[0], cpu_tmp5);
-            tcg_gen_shr_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
+            tcg_gen_mov_tl(t0, cpu_T[0]);
+            tcg_gen_shr_tl(cpu_T[0], cpu_T[0], t2);
         }
     } else {
-        tcg_gen_shl_tl(cpu_T3, cpu_T[0], cpu_tmp5);
-        tcg_gen_shl_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
+        tcg_gen_mov_tl(t0, cpu_T[0]);
+        tcg_gen_shl_tl(cpu_T[0], cpu_T[0], t2);
     }
 
     /* store */
-    if (op1 == OR_TMP0)
+    if (op1 == OR_TMP0) {
         gen_op_st_T0_A0(ot + s->mem_index);
-    else
+    } else {
         gen_op_mov_reg_T0(ot, op1);
-        
+    }
+
     /* update eflags if non zero shift */
-    if (s->cc_op != CC_OP_DYNAMIC)
+    if (s->cc_op != CC_OP_DYNAMIC) {
         gen_op_set_cc_op(s->cc_op);
+    }
 
-    /* XXX: inefficient */
-    t0 = tcg_temp_local_new();
-    t1 = tcg_temp_local_new();
-
-    tcg_gen_mov_tl(t0, cpu_T[0]);
-    tcg_gen_mov_tl(t1, cpu_T3);
+    tcg_gen_mov_tl(t1, cpu_T[0]);
 
     shift_label = gen_new_label();
-    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_T[1], 0, shift_label);
+    tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, shift_label);
 
-    tcg_gen_mov_tl(cpu_cc_src, t1);
-    tcg_gen_mov_tl(cpu_cc_dst, t0);
-    if (is_right)
+    tcg_gen_addi_tl(t2, t2, -1);
+    tcg_gen_mov_tl(cpu_cc_dst, t1);
+
+    if (is_right) {
+        if (is_arith) {
+            tcg_gen_sar_tl(cpu_cc_src, t0, t2);
+        } else {
+            tcg_gen_shr_tl(cpu_cc_src, t0, t2);
+        }
+    } else {
+        tcg_gen_shl_tl(cpu_cc_src, t0, t2);
+    }
+
+    if (is_right) {
         tcg_gen_movi_i32(cpu_cc_op, CC_OP_SARB + ot);
-    else
+    } else {
         tcg_gen_movi_i32(cpu_cc_op, CC_OP_SHLB + ot);
-        
+    }
+
     gen_set_label(shift_label);
     s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
 
     tcg_temp_free(t0);
     tcg_temp_free(t1);
+    tcg_temp_free(t2);
 }
 
 static void gen_shift_rm_im(DisasContext *s, int ot, int op1, int op2,
commit 573da34a412b17b6583148de56d50b59a76c382c
Merge: 13baae8... 22b626e...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Sep 8 09:07:57 2011 -0500

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

commit 13baae8aff88dc6b0268a6078b6916eb951e316f
Merge: 220724c... 69faeee...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Sep 8 09:07:13 2011 -0500

    Merge remote-tracking branch 'qmp/queue/qmp' into staging

commit 220724ca4ada4e30bcfff326b62822a69c23e181
Merge: d8ac46d... cfc606d...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Sep 8 09:05:14 2011 -0500

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

diff --cc hw/pflash_cfi02.c
index 4dbec87,919cfc4..e5a63da
--- a/hw/pflash_cfi02.c
+++ b/hw/pflash_cfi02.c
@@@ -641,10 -642,9 +641,11 @@@ pflash_t *pflash_cfi02_register(target_
              g_free(pfl);
              return NULL;
          }
+         bdrv_attach_dev_nofail(pfl->bs, pfl);
      }
 +    pflash_setup_mappings(pfl);
 +    pfl->rom_mode = 1;
 +    memory_region_add_subregion(get_system_memory(), pfl->base, &pfl->mem);
  #if 0 /* XXX: there should be a bit to set up read-only,
         *      the same way the hardware does (with WP pin).
         */
commit d8ac46d950451a722fd6b1d5d0768c72bee87d47
Merge: 9d0baba... c50a6de...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Sep 8 09:03:57 2011 -0500

    Merge remote-tracking branch 'qemu-kvm-tmp/memory/batch' into staging

commit 9d0baba1104c51f5d95d632ff41406e5aca83216
Merge: a60fce0... 9f4facb...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Sep 8 08:59:32 2011 -0500

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

commit a60fce0bcc193c37c92972b8217341d81f7a9860
Merge: 63236c1... 5b1cdb4...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Sep 8 08:57:33 2011 -0500

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

commit 63236c15e93e18d37ce657171a42af1f809d0aa6
Merge: c82dc29... b9cb88b...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Thu Sep 8 08:52:59 2011 -0500

    Merge remote-tracking branch 'aneesh/for-upstream-3' into staging

commit c82dc29a9112f34e0a51cad9a412cf6d9d05dfb2
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Wed Sep 7 13:44:45 2011 -0500

    iohandlers: fix issue with qemu_set_fd_handler()
    
    As spotted by Aneesh, some users pass a NULL opaque so we need to be more
    aggressive in checking whether a user means to unregister.
    
    Also fix a double free caused by tag not being reset to zero after delete.
    
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/iohandler.c b/iohandler.c
index 5ef66fb..4cc1c5a 100644
--- a/iohandler.c
+++ b/iohandler.c
@@ -93,10 +93,6 @@ static gboolean fd_trampoline(GIOChannel *chan, GIOCondition cond, gpointer opaq
 {
     IOTrampoline *tramp = opaque;
 
-    if (tramp->opaque == NULL) {
-        return FALSE;
-    }
-
     if ((cond & G_IO_IN) && tramp->fd_read) {
         tramp->fd_read(tramp->opaque);
     }
@@ -119,9 +115,10 @@ int qemu_set_fd_handler(int fd,
     if (tramp->tag != 0) {
         g_io_channel_unref(tramp->chan);
         g_source_remove(tramp->tag);
+        tramp->tag = 0;
     }
 
-    if (opaque) {
+    if (fd_read || fd_write || opaque) {
         GIOCondition cond = 0;
 
         tramp->fd_read = fd_read;
commit 5b1cdb4ead0b3d2190492fce0a17e809ef915f26
Author: Juha Riihimäki <juha.riihimaki at nokia.com>
Date:   Wed Aug 31 21:49:41 2011 +0100

    usb-musb: Add reset function
    
    Add a separate reset function musb_reset() to the usb-musb interface,
    so that users who implement a reset function can also reset usb-musb.
    Use this in tusb6010.
    
    Signed-off-by: Juha Riihimäki <juha.riihimaki at nokia.com>
    [Riku Voipio: Fixes and restructuring patchset]
    Signed-off-by: Riku Voipio <riku.voipio at iki.fi>
    [Peter Maydell: More fixes and cleanups for upstream submission]
    Signed-off-by:  Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/tusb6010.c b/hw/tusb6010.c
index 57fe804..ce7c81f 100644
--- a/hw/tusb6010.c
+++ b/hw/tusb6010.c
@@ -771,6 +771,7 @@ static void tusb6010_reset(DeviceState *dev)
     for (i = 0; i < 15; i++) {
         s->rx_config[i] = s->tx_config[i] = 0;
     }
+    musb_reset(s->musb);
 }
 
 static int tusb6010_init(SysBusDevice *dev)
diff --git a/hw/usb-musb.c b/hw/usb-musb.c
index 640037f..01e2e7c 100644
--- a/hw/usb-musb.c
+++ b/hw/usb-musb.c
@@ -340,16 +340,12 @@ struct MUSBState {
     MUSBEndPoint ep[16];
 };
 
-struct MUSBState *musb_init(DeviceState *parent_device, int gpio_base)
+void musb_reset(MUSBState *s)
 {
-    MUSBState *s = g_malloc0(sizeof(*s));
     int i;
 
-    for (i = 0; i < musb_irq_max; i++) {
-        s->irqs[i] = qdev_get_gpio_in(parent_device, gpio_base + i);
-    }
-
     s->faddr = 0x00;
+    s->devctl = 0;
     s->power = MGC_M_POWER_HSENAB;
     s->tx_intr = 0x0000;
     s->rx_intr = 0x0000;
@@ -359,6 +355,10 @@ struct MUSBState *musb_init(DeviceState *parent_device, int gpio_base)
     s->mask = 0x06;
     s->idx = 0;
 
+    s->setup_len = 0;
+    s->session = 0;
+    memset(s->buf, 0, sizeof(s->buf));
+
     /* TODO: _DW */
     s->ep[0].config = MGC_M_CONFIGDATA_SOFTCONE | MGC_M_CONFIGDATA_DYNFIFO;
     for (i = 0; i < 16; i ++) {
@@ -370,6 +370,18 @@ struct MUSBState *musb_init(DeviceState *parent_device, int gpio_base)
         usb_packet_init(&s->ep[i].packey[0].p);
         usb_packet_init(&s->ep[i].packey[1].p);
     }
+}
+
+struct MUSBState *musb_init(DeviceState *parent_device, int gpio_base)
+{
+    MUSBState *s = g_malloc0(sizeof(*s));
+    int i;
+
+    for (i = 0; i < musb_irq_max; i++) {
+        s->irqs[i] = qdev_get_gpio_in(parent_device, gpio_base + i);
+    }
+
+    musb_reset(s);
 
     usb_bus_new(&s->bus, &musb_bus_ops, parent_device);
     usb_register_port(&s->bus, &s->port, s, 0, &musb_port_ops,
diff --git a/hw/usb.h b/hw/usb.h
index 55c061e..c08d469 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -344,6 +344,7 @@ enum musb_irq_source_e {
 
 typedef struct MUSBState MUSBState;
 MUSBState *musb_init(DeviceState *parent_device, int gpio_base);
+void musb_reset(MUSBState *s);
 uint32_t musb_core_intr_get(MUSBState *s);
 void musb_core_intr_clear(MUSBState *s, uint32_t mask);
 void musb_set_size(MUSBState *s, int epnum, int size, int is_tx);
commit 406c20754a29586f6dc1fccacbca3792be24922c
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Wed Aug 31 21:49:40 2011 +0100

    usb-musb: Take a DeviceState* in init function
    
    Initialise usb-musb by passing it a DeviceState* and the offset of the
    IRQs in its gpio array, rather than a plain pointer to an irq array.
    This is simpler for callers and also allows us to pass in a valid parent
    to usb_bus_new(), so the USB bus actually appears in the qdev tree.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/tusb6010.c b/hw/tusb6010.c
index 78814f1..57fe804 100644
--- a/hw/tusb6010.c
+++ b/hw/tusb6010.c
@@ -776,8 +776,6 @@ static void tusb6010_reset(DeviceState *dev)
 static int tusb6010_init(SysBusDevice *dev)
 {
     TUSBState *s = FROM_SYSBUS(TUSBState, dev);
-    qemu_irq *musb_irqs;
-    int i;
     s->otg_timer = qemu_new_timer_ns(vm_clock, tusb_otg_tick, s);
     s->pwr_timer = qemu_new_timer_ns(vm_clock, tusb_power_tick, s);
     memory_region_init_io(&s->iomem[1], &tusb_async_ops, s, "tusb-async",
@@ -786,11 +784,7 @@ static int tusb6010_init(SysBusDevice *dev)
     sysbus_init_mmio_region(dev, &s->iomem[1]);
     sysbus_init_irq(dev, &s->irq);
     qdev_init_gpio_in(&dev->qdev, tusb6010_irq, musb_irq_max + 1);
-    musb_irqs = g_new0(qemu_irq, musb_irq_max);
-    for (i = 0; i < musb_irq_max; i++) {
-        musb_irqs[i] = qdev_get_gpio_in(&dev->qdev, i + 1);
-    }
-    s->musb = musb_init(musb_irqs);
+    s->musb = musb_init(&dev->qdev, 1);
     return 0;
 }
 
diff --git a/hw/usb-musb.c b/hw/usb-musb.c
index 799fa6e..640037f 100644
--- a/hw/usb-musb.c
+++ b/hw/usb-musb.c
@@ -314,7 +314,7 @@ struct MUSBEndPoint {
 };
 
 struct MUSBState {
-    qemu_irq *irqs;
+    qemu_irq irqs[musb_irq_max];
     USBBus bus;
     USBPort port;
 
@@ -340,12 +340,14 @@ struct MUSBState {
     MUSBEndPoint ep[16];
 };
 
-struct MUSBState *musb_init(qemu_irq *irqs)
+struct MUSBState *musb_init(DeviceState *parent_device, int gpio_base)
 {
     MUSBState *s = g_malloc0(sizeof(*s));
     int i;
 
-    s->irqs = irqs;
+    for (i = 0; i < musb_irq_max; i++) {
+        s->irqs[i] = qdev_get_gpio_in(parent_device, gpio_base + i);
+    }
 
     s->faddr = 0x00;
     s->power = MGC_M_POWER_HSENAB;
@@ -369,7 +371,7 @@ struct MUSBState *musb_init(qemu_irq *irqs)
         usb_packet_init(&s->ep[i].packey[1].p);
     }
 
-    usb_bus_new(&s->bus, &musb_bus_ops, NULL /* FIXME */);
+    usb_bus_new(&s->bus, &musb_bus_ops, parent_device);
     usb_register_port(&s->bus, &s->port, s, 0, &musb_port_ops,
                       USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
 
diff --git a/hw/usb.h b/hw/usb.h
index e251e61..55c061e 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -343,7 +343,7 @@ enum musb_irq_source_e {
 };
 
 typedef struct MUSBState MUSBState;
-MUSBState *musb_init(qemu_irq *irqs);
+MUSBState *musb_init(DeviceState *parent_device, int gpio_base);
 uint32_t musb_core_intr_get(MUSBState *s);
 void musb_core_intr_clear(MUSBState *s, uint32_t mask);
 void musb_set_size(MUSBState *s, int epnum, int size, int is_tx);
commit 9147b752887d65dfe2431f0fbff1d4a2545344d0
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Wed Aug 31 21:49:39 2011 +0100

    usb: Remove leading underscores from __musb_irq_max
    
    Identifiers with double leading underscore are reserved, so rename
    __musb_irq_max so we don't encroach on reserved namespace.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/tusb6010.c b/hw/tusb6010.c
index de6ffc6..78814f1 100644
--- a/hw/tusb6010.c
+++ b/hw/tusb6010.c
@@ -785,9 +785,9 @@ static int tusb6010_init(SysBusDevice *dev)
     sysbus_init_mmio_region(dev, &s->iomem[0]);
     sysbus_init_mmio_region(dev, &s->iomem[1]);
     sysbus_init_irq(dev, &s->irq);
-    qdev_init_gpio_in(&dev->qdev, tusb6010_irq, __musb_irq_max + 1);
-    musb_irqs = g_new0(qemu_irq, __musb_irq_max);
-    for (i = 0; i < __musb_irq_max; i++) {
+    qdev_init_gpio_in(&dev->qdev, tusb6010_irq, musb_irq_max + 1);
+    musb_irqs = g_new0(qemu_irq, musb_irq_max);
+    for (i = 0; i < musb_irq_max; i++) {
         musb_irqs[i] = qdev_get_gpio_in(&dev->qdev, i + 1);
     }
     s->musb = musb_init(musb_irqs);
diff --git a/hw/usb.h b/hw/usb.h
index 73479d6..e251e61 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -338,7 +338,8 @@ enum musb_irq_source_e {
     musb_irq_tx,
     musb_set_vbus,
     musb_set_session,
-    __musb_irq_max,
+    /* Add new interrupts here */
+    musb_irq_max, /* total number of interrupts defined */
 };
 
 typedef struct MUSBState MUSBState;
commit d67915786822b42094ce99768e595994cf6de0bf
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Aug 31 11:44:24 2011 +0200

    usb-host: tag as unmigratable
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/usb-linux.c b/usb-linux.c
index 67639f3..2075c4c 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -1354,10 +1354,16 @@ out:
     return 0;
 }
 
+static const VMStateDescription vmstate_usb_host = {
+    .name = "usb-host",
+    .unmigratable = 1,
+};
+
 static struct USBDeviceInfo usb_host_dev_info = {
     .product_desc   = "USB Host Device",
     .qdev.name      = "usb-host",
     .qdev.size      = sizeof(USBHostDevice),
+    .qdev.vmsd      = &vmstate_usb_host,
     .init           = usb_host_initfn,
     .handle_packet  = usb_generic_handle_packet,
     .cancel_packet  = usb_host_async_cancel,
commit 891fb2cd4592b6fe76106a69e0ca40efbf82726a
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Sep 1 13:56:37 2011 +0200

    usb: claim port at device initialization time.
    
    This patch makes qemu assign a port when creating the device, not when
    attaching it.  For most usb devices this isn't a noticable difference
    because they are in attached state all the time.
    
    The change affects usb-host devices which live in detached state while
    the real device is unplugged from the host.  They have a fixed port
    assigned all the time now instead of getting grabbing one on attach and
    releasing it at detach, i.e. they stop floating around at the usb bus.
    
    The change also allows to simplify usb-hub.  It doesn't need the
    handle_attach() callback any more to configure the downstream ports.
    This can be done at device initialitation time now.  The changed
    initialization order (first grab upstream port, then register downstream
    ports) also fixes some icky corner cases.  For example it is not possible
    any more to plug the hub into one of its own downstream ports.
    
    The usb host adapters must care too.  USBPort->dev being non-NULL
    doesn't imply any more the device is in attached state.  The host
    adapters must additionally check the USBPort->dev->attached flag.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-bus.c b/hw/usb-bus.c
index c0bbc7c..93f640d 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -3,6 +3,7 @@
 #include "qdev.h"
 #include "sysemu.h"
 #include "monitor.h"
+#include "trace.h"
 
 static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);
 
@@ -73,9 +74,13 @@ static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base)
     dev->info = info;
     dev->auto_attach = 1;
     QLIST_INIT(&dev->strings);
-    rc = dev->info->init(dev);
-    if (rc == 0 && dev->auto_attach)
+    rc = usb_claim_port(dev);
+    if (rc == 0) {
+        rc = dev->info->init(dev);
+    }
+    if (rc == 0 && dev->auto_attach) {
         rc = usb_device_attach(dev);
+    }
     return rc;
 }
 
@@ -89,6 +94,9 @@ static int usb_qdev_exit(DeviceState *qdev)
     if (dev->info->handle_destroy) {
         dev->info->handle_destroy(dev);
     }
+    if (dev->port) {
+        usb_release_port(dev);
+    }
     return 0;
 }
 
@@ -205,21 +213,13 @@ void usb_unregister_port(USBBus *bus, USBPort *port)
     bus->nfree--;
 }
 
-static int do_attach(USBDevice *dev)
+int usb_claim_port(USBDevice *dev)
 {
     USBBus *bus = usb_bus_from_device(dev);
     USBPort *port;
 
-    if (dev->attached) {
-        error_report("Error: tried to attach usb device %s twice\n",
-                dev->product_desc);
-        return -1;
-    }
-    if (bus->nfree == 0) {
-        error_report("Error: tried to attach usb device %s to a bus with no free ports\n",
-                dev->product_desc);
-        return -1;
-    }
+    assert(dev->port == NULL);
+
     if (dev->port_path) {
         QTAILQ_FOREACH(port, &bus->free, next) {
             if (strcmp(port->path, dev->port_path) == 0) {
@@ -227,68 +227,86 @@ static int do_attach(USBDevice *dev)
             }
         }
         if (port == NULL) {
-            error_report("Error: usb port %s (bus %s) not found\n",
-                    dev->port_path, bus->qbus.name);
+            error_report("Error: usb port %s (bus %s) not found (in use?)\n",
+                         dev->port_path, bus->qbus.name);
             return -1;
         }
     } else {
+        if (bus->nfree == 1 && strcmp(dev->qdev.info->name, "usb-hub") != 0) {
+            /* Create a new hub and chain it on */
+            usb_create_simple(bus, "usb-hub");
+        }
+        if (bus->nfree == 0) {
+            error_report("Error: tried to attach usb device %s to a bus "
+                         "with no free ports\n", dev->product_desc);
+            return -1;
+        }
         port = QTAILQ_FIRST(&bus->free);
     }
-    if (!(port->speedmask & dev->speedmask)) {
-        error_report("Warning: speed mismatch trying to attach usb device %s to bus %s\n",
-                dev->product_desc, bus->qbus.name);
-        return -1;
-    }
+    trace_usb_port_claim(bus->busnr, port->path);
 
-    dev->attached++;
     QTAILQ_REMOVE(&bus->free, port, next);
     bus->nfree--;
 
-    usb_attach(port, dev);
+    dev->port = port;
+    port->dev = dev;
 
     QTAILQ_INSERT_TAIL(&bus->used, port, next);
     bus->nused++;
-
     return 0;
 }
 
-int usb_device_attach(USBDevice *dev)
+void usb_release_port(USBDevice *dev)
 {
     USBBus *bus = usb_bus_from_device(dev);
+    USBPort *port = dev->port;
 
-    if (bus->nfree == 1 && dev->port_path == NULL) {
-        /* Create a new hub and chain it on
-           (unless a physical port location is specified). */
-        usb_create_simple(bus, "usb-hub");
-    }
-    return do_attach(dev);
+    assert(port != NULL);
+    trace_usb_port_release(bus->busnr, port->path);
+
+    QTAILQ_REMOVE(&bus->used, port, next);
+    bus->nused--;
+
+    dev->port = NULL;
+    port->dev = NULL;
+
+    QTAILQ_INSERT_TAIL(&bus->free, port, next);
+    bus->nfree++;
 }
 
-int usb_device_detach(USBDevice *dev)
+int usb_device_attach(USBDevice *dev)
 {
     USBBus *bus = usb_bus_from_device(dev);
-    USBPort *port;
+    USBPort *port = dev->port;
 
-    if (!dev->attached) {
-        error_report("Error: tried to detach unattached usb device %s\n",
-                dev->product_desc);
+    assert(port != NULL);
+    assert(!dev->attached);
+    trace_usb_port_attach(bus->busnr, port->path);
+
+    if (!(port->speedmask & dev->speedmask)) {
+        error_report("Warning: speed mismatch trying to attach "
+                     "usb device %s to bus %s\n",
+                     dev->product_desc, bus->qbus.name);
         return -1;
     }
-    dev->attached--;
 
-    QTAILQ_FOREACH(port, &bus->used, next) {
-        if (port->dev == dev)
-            break;
-    }
-    assert(port != NULL);
+    dev->attached++;
+    usb_attach(port);
 
-    QTAILQ_REMOVE(&bus->used, port, next);
-    bus->nused--;
+    return 0;
+}
+
+int usb_device_detach(USBDevice *dev)
+{
+    USBBus *bus = usb_bus_from_device(dev);
+    USBPort *port = dev->port;
 
-    usb_attach(port, NULL);
+    assert(port != NULL);
+    assert(dev->attached);
+    trace_usb_port_detach(bus->busnr, port->path);
 
-    QTAILQ_INSERT_TAIL(&bus->free, port, next);
-    bus->nfree++;
+    usb_detach(port);
+    dev->attached--;
     return 0;
 }
 
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index d8ef0cb..e9e0789 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -857,8 +857,8 @@ static void ehci_reset(void *opaque)
      */
     for(i = 0; i < NB_PORTS; i++) {
         devs[i] = s->ports[i].dev;
-        if (devs[i]) {
-            usb_attach(&s->ports[i], NULL);
+        if (devs[i] && devs[i]->attached) {
+            usb_detach(&s->ports[i]);
         }
     }
 
@@ -878,8 +878,8 @@ static void ehci_reset(void *opaque)
         } else {
             s->portsc[i] = PORTSC_PPOWER;
         }
-        if (devs[i]) {
-            usb_attach(&s->ports[i], devs[i]);
+        if (devs[i] && devs[i]->attached) {
+            usb_attach(&s->ports[i]);
         }
     }
     ehci_queues_rip_all(s);
@@ -945,15 +945,15 @@ static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner)
         return;
     }
 
-    if (dev) {
-        usb_attach(&s->ports[port], NULL);
+    if (dev && dev->attached) {
+        usb_detach(&s->ports[port]);
     }
 
     *portsc &= ~PORTSC_POWNER;
     *portsc |= owner;
 
-    if (dev) {
-        usb_attach(&s->ports[port], dev);
+    if (dev && dev->attached) {
+        usb_attach(&s->ports[port]);
     }
 }
 
@@ -977,8 +977,8 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val)
 
     if (!(val & PORTSC_PRESET) &&(*portsc & PORTSC_PRESET)) {
         trace_usb_ehci_port_reset(port, 0);
-        if (dev) {
-            usb_attach(&s->ports[port], dev);
+        if (dev && dev->attached) {
+            usb_attach(&s->ports[port]);
             usb_send_msg(dev, USB_MSG_RESET);
             *portsc &= ~PORTSC_CSC;
         }
@@ -987,7 +987,7 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val)
          *  Table 2.16 Set the enable bit(and enable bit change) to indicate
          *  to SW that this port has a high speed device attached
          */
-        if (dev && (dev->speedmask & USB_SPEED_MASK_HIGH)) {
+        if (dev && dev->attached && (dev->speedmask & USB_SPEED_MASK_HIGH)) {
             val |= PORTSC_PED;
         }
     }
diff --git a/hw/usb-hub.c b/hw/usb-hub.c
index c49c547..286e3ad 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -213,16 +213,6 @@ static void usb_hub_complete(USBPort *port, USBPacket *packet)
     usb_packet_complete(&s->dev, packet);
 }
 
-static void usb_hub_handle_attach(USBDevice *dev)
-{
-    USBHubState *s = DO_UPCAST(USBHubState, dev, dev);
-    int i;
-
-    for (i = 0; i < NUM_PORTS; i++) {
-        usb_port_location(&s->ports[i].port, dev->port, i+1);
-    }
-}
-
 static void usb_hub_handle_reset(USBDevice *dev)
 {
     /* XXX: do it */
@@ -499,6 +489,7 @@ static int usb_hub_initfn(USBDevice *dev)
         usb_register_port(usb_bus_from_device(dev),
                           &port->port, s, i, &usb_hub_port_ops,
                           USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
+        usb_port_location(&port->port, dev->port, i+1);
         port->wPortStatus = PORT_STAT_POWER;
         port->wPortChange = 0;
     }
@@ -537,7 +528,6 @@ static struct USBDeviceInfo hub_info = {
     .usb_desc       = &desc_hub,
     .init           = usb_hub_initfn,
     .handle_packet  = usb_hub_handle_packet,
-    .handle_attach  = usb_hub_handle_attach,
     .handle_reset   = usb_hub_handle_reset,
     .handle_control = usb_hub_handle_control,
     .handle_data    = usb_hub_handle_data,
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index d30db3f..503ca2d 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -448,8 +448,8 @@ static void ohci_reset(void *opaque)
       {
         port = &ohci->rhport[i];
         port->ctrl = 0;
-        if (port->port.dev) {
-            usb_attach(&port->port, port->port.dev);
+        if (port->port.dev && port->port.dev->attached) {
+            usb_attach(&port->port);
         }
       }
     if (ohci->async_td) {
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index 6ca7ca8..64f7b36 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -340,8 +340,8 @@ static void uhci_reset(void *opaque)
     for(i = 0; i < NB_PORTS; i++) {
         port = &s->ports[i];
         port->ctrl = 0x0080;
-        if (port->port.dev) {
-            usb_attach(&port->port, port->port.dev);
+        if (port->port.dev && port->port.dev->attached) {
+            usb_attach(&port->port);
         }
     }
 
@@ -446,7 +446,7 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
             for(i = 0; i < NB_PORTS; i++) {
                 port = &s->ports[i];
                 dev = port->port.dev;
-                if (dev) {
+                if (dev && dev->attached) {
                     usb_send_msg(dev, USB_MSG_RESET);
                 }
             }
@@ -486,7 +486,7 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
                 return;
             port = &s->ports[n];
             dev = port->port.dev;
-            if (dev) {
+            if (dev && dev->attached) {
                 /* port reset */
                 if ( (val & UHCI_PORT_RESET) &&
                      !(port->ctrl & UHCI_PORT_RESET) ) {
@@ -660,8 +660,9 @@ static int uhci_broadcast_packet(UHCIState *s, USBPacket *p)
         UHCIPort *port = &s->ports[i];
         USBDevice *dev = port->port.dev;
 
-        if (dev && (port->ctrl & UHCI_PORT_EN))
+        if (dev && dev->attached && (port->ctrl & UHCI_PORT_EN)) {
             ret = usb_handle_packet(dev, p);
+        }
     }
 
     DPRINTF("uhci: packet exit. ret %d len %zd\n", ret, p->iov.size);
diff --git a/hw/usb.c b/hw/usb.c
index a091e4e..fa90204 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -27,26 +27,23 @@
 #include "usb.h"
 #include "iov.h"
 
-void usb_attach(USBPort *port, USBDevice *dev)
+void usb_attach(USBPort *port)
 {
-    if (dev != NULL) {
-        /* attach */
-        if (port->dev) {
-            usb_attach(port, NULL);
-        }
-        dev->port = port;
-        port->dev = dev;
-        port->ops->attach(port);
-        usb_send_msg(dev, USB_MSG_ATTACH);
-    } else {
-        /* detach */
-        dev = port->dev;
-        assert(dev);
-        port->ops->detach(port);
-        usb_send_msg(dev, USB_MSG_DETACH);
-        dev->port = NULL;
-        port->dev = NULL;
-    }
+    USBDevice *dev = port->dev;
+
+    assert(dev != NULL);
+    assert(dev->attached);
+    port->ops->attach(port);
+    usb_send_msg(dev, USB_MSG_ATTACH);
+}
+
+void usb_detach(USBPort *port)
+{
+    USBDevice *dev = port->dev;
+
+    assert(dev != NULL);
+    port->ops->detach(port);
+    usb_send_msg(dev, USB_MSG_DETACH);
 }
 
 void usb_wakeup(USBDevice *dev)
diff --git a/hw/usb.h b/hw/usb.h
index d784448..73479d6 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -304,7 +304,8 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p);
 void usb_packet_complete(USBDevice *dev, USBPacket *p);
 void usb_cancel_packet(USBPacket * p);
 
-void usb_attach(USBPort *port, USBDevice *dev);
+void usb_attach(USBPort *port);
+void usb_detach(USBPort *port);
 void usb_wakeup(USBDevice *dev);
 int usb_generic_handle_packet(USBDevice *s, USBPacket *p);
 void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p);
@@ -378,6 +379,8 @@ int usb_register_companion(const char *masterbus, USBPort *ports[],
                            void *opaque, USBPortOps *ops, int speedmask);
 void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr);
 void usb_unregister_port(USBBus *bus, USBPort *port);
+int usb_claim_port(USBDevice *dev);
+void usb_release_port(USBDevice *dev);
 int usb_device_attach(USBDevice *dev);
 int usb_device_detach(USBDevice *dev);
 int usb_device_delete_addr(int busnr, int addr);
diff --git a/trace-events b/trace-events
index 5936192..3fdd60f 100644
--- a/trace-events
+++ b/trace-events
@@ -209,6 +209,12 @@ sun4m_iommu_page_get_flags(uint64_t pa, uint64_t iopte, uint32_t ret) "get flags
 sun4m_iommu_translate_pa(uint64_t addr, uint64_t pa, uint32_t iopte) "xlate dva %"PRIx64" => pa %"PRIx64" iopte = %x"
 sun4m_iommu_bad_addr(uint64_t addr) "bad addr %"PRIx64""
 
+# hw/usb-bus.c
+usb_port_claim(int bus, const char *port) "bus %d, port %s"
+usb_port_attach(int bus, const char *port) "bus %d, port %s"
+usb_port_detach(int bus, const char *port) "bus %d, port %s"
+usb_port_release(int bus, const char *port) "bus %d, port %s"
+
 # hw/usb-ehci.c
 usb_ehci_reset(void) "=== RESET ==="
 usb_ehci_mmio_readl(uint32_t addr, const char *str, uint32_t val) "rd mmio %04x [%s] = %x"
commit 7755260f015dcbb8fa47bcc6f1e2ca317b2205aa
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Aug 30 12:15:53 2011 +0200

    usb-ccid: remote wakeup support
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c
index d40977b..cd349f3 100644
--- a/hw/usb-ccid.c
+++ b/hw/usb-ccid.c
@@ -447,7 +447,7 @@ static const USBDescDevice desc_device = {
         {
             .bNumInterfaces        = 1,
             .bConfigurationValue   = 1,
-            .bmAttributes          = 0x80,
+            .bmAttributes          = 0xa0,
             .bMaxPower             = 50,
             .nif = 1,
             .ifs = &desc_iface0,
@@ -811,6 +811,7 @@ static void ccid_on_slot_change(USBCCIDState *s, bool full)
         s->bmSlotICCState |= SLOT_0_CHANGED_MASK;
     }
     s->notify_slot_change = true;
+    usb_wakeup(&s->dev);
 }
 
 static void ccid_write_data_block_error(
commit 97237e0a5a95123a072a49eddd3bc5e20534f7fa
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Aug 30 11:49:05 2011 +0200

    usb-ccid: switch to USBDesc*
    
    Switch the smard card emulation to use the USBDesc*
    structs for the usb descriptors.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c
index c2f9241..d40977b 100644
--- a/hw/usb-ccid.c
+++ b/hw/usb-ccid.c
@@ -37,6 +37,7 @@
 #include "qemu-common.h"
 #include "qemu-error.h"
 #include "usb.h"
+#include "usb-desc.h"
 #include "monitor.h"
 
 #include "hw/ccid.h"
@@ -306,56 +307,7 @@ typedef struct USBCCIDState {
  *   0dc3:1004 Athena Smartcard Solutions, Inc.
  */
 
-static const uint8_t qemu_ccid_dev_descriptor[] = {
-        0x12,       /*  u8 bLength; */
-        USB_DT_DEVICE, /*  u8 bDescriptorType; Device */
-        0x10, 0x01, /*  u16 bcdUSB; v1.1 */
-
-        0x00,       /*  u8  bDeviceClass; */
-        0x00,       /*  u8  bDeviceSubClass; */
-        0x00,       /*  u8  bDeviceProtocol; [ low/full speeds only ] */
-        0x40,       /*  u8  bMaxPacketSize0; 8 Bytes (valid: 8,16,32,64) */
-
-        /* Vendor and product id are arbitrary.  */
-                    /*  u16 idVendor  */
-        CCID_VENDOR_ID & 0xff, CCID_VENDOR_ID >> 8,
-                    /*  u16 idProduct */
-        CCID_PRODUCT_ID & 0xff, CCID_PRODUCT_ID >> 8,
-                    /*  u16 bcdDevice */
-        CCID_DEVICE_VERSION & 0xff, CCID_DEVICE_VERSION >> 8,
-        0x01,       /*  u8  iManufacturer; */
-        0x02,       /*  u8  iProduct; */
-        0x03,       /*  u8  iSerialNumber; */
-        0x01,       /*  u8  bNumConfigurations; */
-};
-
-static const uint8_t qemu_ccid_config_descriptor[] = {
-
-        /* one configuration */
-        0x09,       /* u8  bLength; */
-        USB_DT_CONFIG, /* u8  bDescriptorType; Configuration */
-        0x5d, 0x00, /* u16 wTotalLength; 9+9+54+7+7+7 */
-        0x01,       /* u8  bNumInterfaces; (1) */
-        0x01,       /* u8  bConfigurationValue; */
-        0x00,       /* u8  iConfiguration; */
-        0xe0,       /* u8  bmAttributes;
-                                 Bit 7: must be set,
-                                     6: Self-powered,
-                                     5: Remote wakeup,
-                                     4..0: resvd */
-        100/2,      /* u8  MaxPower; 50 == 100mA */
-
-        /* one interface */
-        0x09,       /* u8  if_bLength; */
-        USB_DT_INTERFACE, /* u8  if_bDescriptorType; Interface */
-        0x00,       /* u8  if_bInterfaceNumber; */
-        0x00,       /* u8  if_bAlternateSetting; */
-        0x03,       /* u8  if_bNumEndpoints; */
-        0x0b,       /* u8  if_bInterfaceClass; Smart Card Device Class */
-        0x00,       /* u8  if_bInterfaceSubClass; Subclass code */
-        0x00,       /* u8  if_bInterfaceProtocol; Protocol code */
-        0x04,       /* u8  if_iInterface; Index of string descriptor */
-
+static const uint8_t qemu_ccid_descriptor[] = {
         /* Smart Card Device Class Descriptor */
         0x36,       /* u8  bLength; */
         0x21,       /* u8  bDescriptorType; Functional */
@@ -439,38 +391,81 @@ static const uint8_t qemu_ccid_config_descriptor[] = {
                      *                  02h PIN Modification
                      */
         0x01,       /* u8  bMaxCCIDBusySlots; */
+};
 
-        /* Interrupt-IN endpoint */
-        0x07,       /* u8  ep_bLength; */
-                    /* u8  ep_bDescriptorType; Endpoint */
-        USB_DT_ENDPOINT,
-                    /* u8  ep_bEndpointAddress; IN Endpoint 1 */
-        0x80 | CCID_INT_IN_EP,
-        0x03,       /* u8  ep_bmAttributes; Interrupt */
-                    /* u16 ep_wMaxPacketSize; */
-        CCID_MAX_PACKET_SIZE & 0xff, (CCID_MAX_PACKET_SIZE >> 8),
-        0xff,       /* u8  ep_bInterval; */
-
-        /* Bulk-In endpoint */
-        0x07,       /* u8  ep_bLength; */
-                    /* u8  ep_bDescriptorType; Endpoint */
-        USB_DT_ENDPOINT,
-                    /* u8  ep_bEndpointAddress; IN Endpoint 2 */
-        0x80 | CCID_BULK_IN_EP,
-        0x02,       /* u8  ep_bmAttributes; Bulk */
-        0x40, 0x00, /* u16 ep_wMaxPacketSize; */
-        0x00,       /* u8  ep_bInterval; */
-
-        /* Bulk-Out endpoint */
-        0x07,       /* u8  ep_bLength; */
-                    /* u8  ep_bDescriptorType; Endpoint */
-        USB_DT_ENDPOINT,
-                    /* u8  ep_bEndpointAddress; OUT Endpoint 3 */
-        CCID_BULK_OUT_EP,
-        0x02,       /* u8  ep_bmAttributes; Bulk */
-        0x40, 0x00, /* u16 ep_wMaxPacketSize; */
-        0x00,       /* u8  ep_bInterval; */
+enum {
+    STR_MANUFACTURER = 1,
+    STR_PRODUCT,
+    STR_SERIALNUMBER,
+    STR_INTERFACE,
+};
 
+static const USBDescStrings desc_strings = {
+    [STR_MANUFACTURER]  = "QEMU " QEMU_VERSION,
+    [STR_PRODUCT]       = "QEMU USB CCID",
+    [STR_SERIALNUMBER]  = "1",
+    [STR_INTERFACE]     = "CCID Interface",
+};
+
+static const USBDescIface desc_iface0 = {
+    .bInterfaceNumber              = 0,
+    .bNumEndpoints                 = 3,
+    .bInterfaceClass               = 0x0b,
+    .bInterfaceSubClass            = 0x00,
+    .bInterfaceProtocol            = 0x00,
+    .iInterface                    = STR_INTERFACE,
+    .ndesc                         = 1,
+    .descs = (USBDescOther[]) {
+        {
+            /* smartcard descriptor */
+            .data = qemu_ccid_descriptor,
+        },
+    },
+    .eps = (USBDescEndpoint[]) {
+        {
+            .bEndpointAddress      = USB_DIR_IN | CCID_INT_IN_EP,
+            .bmAttributes          = USB_ENDPOINT_XFER_INT,
+            .bInterval             = 255,
+            .wMaxPacketSize        = 64,
+        },{
+            .bEndpointAddress      = USB_DIR_IN | CCID_BULK_IN_EP,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 64,
+        },{
+            .bEndpointAddress      = USB_DIR_OUT | CCID_BULK_OUT_EP,
+            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
+            .wMaxPacketSize        = 64,
+        },
+    }
+};
+
+static const USBDescDevice desc_device = {
+    .bcdUSB                        = 0x0110,
+    .bMaxPacketSize0               = 64,
+    .bNumConfigurations            = 1,
+    .confs = (USBDescConfig[]) {
+        {
+            .bNumInterfaces        = 1,
+            .bConfigurationValue   = 1,
+            .bmAttributes          = 0x80,
+            .bMaxPower             = 50,
+            .nif = 1,
+            .ifs = &desc_iface0,
+        },
+    },
+};
+
+static const USBDesc desc_ccid = {
+    .id = {
+        .idVendor          = CCID_VENDOR_ID,
+        .idProduct         = CCID_PRODUCT_ID,
+        .bcdDevice         = CCID_DEVICE_VERSION,
+        .iManufacturer     = STR_MANUFACTURER,
+        .iProduct          = STR_PRODUCT,
+        .iSerialNumber     = STR_SERIALNUMBER,
+    },
+    .full = &desc_device,
+    .str  = desc_strings,
 };
 
 static bool ccid_has_pending_answers(USBCCIDState *s)
@@ -610,87 +605,12 @@ static int ccid_handle_control(USBDevice *dev, USBPacket *p, int request,
     int ret = 0;
 
     DPRINTF(s, 1, "got control %x, value %x\n", request, value);
+    ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
+    if (ret >= 0) {
+        return ret;
+    }
+
     switch (request) {
-    case DeviceRequest | USB_REQ_GET_STATUS:
-        data[0] = (1 << USB_DEVICE_SELF_POWERED) |
-            (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
-        data[1] = 0x00;
-        ret = 2;
-        break;
-    case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
-        if (value == USB_DEVICE_REMOTE_WAKEUP) {
-            dev->remote_wakeup = 0;
-        } else {
-            goto fail;
-        }
-        ret = 0;
-        break;
-    case DeviceOutRequest | USB_REQ_SET_FEATURE:
-        if (value == USB_DEVICE_REMOTE_WAKEUP) {
-            dev->remote_wakeup = 1;
-        } else {
-            goto fail;
-        }
-        ret = 0;
-        break;
-    case DeviceOutRequest | USB_REQ_SET_ADDRESS:
-        dev->addr = value;
-        ret = 0;
-        break;
-    case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
-        switch (value >> 8) {
-        case USB_DT_DEVICE:
-            memcpy(data, qemu_ccid_dev_descriptor,
-                   sizeof(qemu_ccid_dev_descriptor));
-            ret = sizeof(qemu_ccid_dev_descriptor);
-            break;
-        case USB_DT_CONFIG:
-            memcpy(data, qemu_ccid_config_descriptor,
-                   sizeof(qemu_ccid_config_descriptor));
-            ret = sizeof(qemu_ccid_config_descriptor);
-            break;
-        case USB_DT_STRING:
-            switch (value & 0xff) {
-            case 0:
-                /* language ids */
-                data[0] = 4;
-                data[1] = 3;
-                data[2] = 0x09;
-                data[3] = 0x04;
-                ret = 4;
-                break;
-            case 1:
-                /* vendor description */
-                ret = set_usb_string(data, CCID_VENDOR_DESCRIPTION);
-                break;
-            case 2:
-                /* product description */
-                ret = set_usb_string(data, CCID_PRODUCT_DESCRIPTION);
-                break;
-            case 3:
-                /* serial number */
-                ret = set_usb_string(data, CCID_SERIAL_NUMBER_STRING);
-                break;
-            case 4:
-                /* interface name */
-                ret = set_usb_string(data, CCID_INTERFACE_NAME);
-                break;
-            default:
-                goto fail;
-            }
-            break;
-        default:
-            goto fail;
-        }
-        break;
-    case DeviceRequest | USB_REQ_GET_CONFIGURATION:
-        data[0] = 1;
-        ret = 1;
-        break;
-    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
-        /* Only one configuration - we just ignore the request */
-        ret = 0;
-        break;
     case DeviceRequest | USB_REQ_GET_INTERFACE:
         data[0] = 0;
         ret = 1;
@@ -698,9 +618,6 @@ static int ccid_handle_control(USBDevice *dev, USBPacket *p, int request,
     case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
         ret = 0;
         break;
-    case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
-        ret = 0;
-        break;
 
         /* Class specific requests.  */
     case InterfaceOutClass | CCID_CONTROL_ABORT:
@@ -716,7 +633,6 @@ static int ccid_handle_control(USBDevice *dev, USBPacket *p, int request,
         ret = USB_RET_STALL;
         break;
     default:
-fail:
         DPRINTF(s, 1, "got unsupported/bogus control %x, value %x\n",
                 request, value);
         ret = USB_RET_STALL;
@@ -1075,6 +991,7 @@ static int ccid_handle_data(USBDevice *dev, USBPacket *p)
             break;
         default:
             DPRINTF(s, 1, "Bad endpoint\n");
+            ret = USB_RET_STALL;
             break;
         }
         break;
@@ -1256,6 +1173,7 @@ static int ccid_initfn(USBDevice *dev)
 {
     USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
 
+    usb_desc_init(dev);
     qbus_create_inplace(&s->bus.qbus, &ccid_bus_info, &dev->qdev, NULL);
     s->bus.qbus.allow_hotplug = 1;
     s->card = NULL;
@@ -1381,6 +1299,7 @@ static struct USBDeviceInfo ccid_info = {
     .qdev.desc      = "CCID Rev 1.1 smartcard reader",
     .qdev.size      = sizeof(USBCCIDState),
     .init           = ccid_initfn,
+    .usb_desc       = &desc_ccid,
     .handle_packet  = usb_generic_handle_packet,
     .handle_reset   = ccid_handle_reset,
     .handle_control = ccid_handle_control,
diff --git a/hw/usb-desc.h b/hw/usb-desc.h
index 9d7ed59..5c14e4a 100644
--- a/hw/usb-desc.h
+++ b/hw/usb-desc.h
@@ -75,7 +75,7 @@ struct USBDescEndpoint {
 
 struct USBDescOther {
     uint8_t                   length;
-    uint8_t                   *data;
+    const uint8_t             *data;
 };
 
 typedef const char *USBDescStrings[256];
commit 4d8debba766265d70cb7bf11570e3622512641d6
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Aug 25 16:43:15 2011 +0200

    usb: fix use after free
    
    The ->complete() callback might have released the USBPacket (uhci
    actually does), so we must not touch it after the callback returns.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb.c b/hw/usb.c
index 685e775..a091e4e 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -338,8 +338,8 @@ void usb_packet_complete(USBDevice *dev, USBPacket *p)
 {
     /* Note: p->owner != dev is possible in case dev is a hub */
     assert(p->owner != NULL);
-    dev->port->ops->complete(dev->port, p);
     p->owner = NULL;
+    dev->port->ops->complete(dev->port, p);
 }
 
 /* Cancel an active packet.  The packed must have been deferred by
commit 0c402e5abb8c2755390eee864b43a98280fc2453
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Aug 17 23:36:46 2011 +0200

    usb-host: parse port in /proc/bus/usb/devices scan
    
    Unfortunaly this is limited to root ports.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/usb-linux.c b/usb-linux.c
index ef29a76..67639f3 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -1483,7 +1483,8 @@ static int usb_host_scan_dev(void *opaque, USBScanFunc *func)
     FILE *f = NULL;
     char line[1024];
     char buf[1024];
-    int bus_num, addr, speed, device_count, class_id, product_id, vendor_id;
+    int bus_num, addr, speed, device_count;
+    int class_id, product_id, vendor_id, port;
     char product_name[512];
     int ret = 0;
 
@@ -1499,7 +1500,7 @@ static int usb_host_scan_dev(void *opaque, USBScanFunc *func)
     }
 
     device_count = 0;
-    bus_num = addr = class_id = product_id = vendor_id = 0;
+    bus_num = addr = class_id = product_id = vendor_id = port = 0;
     speed = -1; /* Can't get the speed from /[proc|dev]/bus/usb/devices */
     for(;;) {
         if (fgets(line, sizeof(line), f) == NULL) {
@@ -1521,6 +1522,10 @@ static int usb_host_scan_dev(void *opaque, USBScanFunc *func)
                 goto fail;
             }
             bus_num = atoi(buf);
+            if (get_tag_value(buf, sizeof(buf), line, "Port=", " ") < 0) {
+                goto fail;
+            }
+            port = atoi(buf);
             if (get_tag_value(buf, sizeof(buf), line, "Dev#=", " ") < 0) {
                 goto fail;
             }
@@ -1566,7 +1571,12 @@ static int usb_host_scan_dev(void *opaque, USBScanFunc *func)
     }
     if (device_count && (vendor_id || product_id)) {
         /* Add the last device.  */
-        ret = func(opaque, bus_num, addr, 0, class_id, vendor_id,
+        if (port > 0) {
+            snprintf(buf, sizeof(buf), "%d", port);
+        } else {
+            snprintf(buf, sizeof(buf), "?");
+        }
+        ret = func(opaque, bus_num, addr, buf, class_id, vendor_id,
                    product_id, product_name, speed);
     }
  the_end:
commit ba9acab9bfc23bedbf639217af7c68142f022a07
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Aug 17 23:35:45 2011 +0200

    usb-host: constify port
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/usb-linux.c b/usb-linux.c
index 6490582..ef29a76 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -54,7 +54,7 @@ struct usb_ctrltransfer {
     void *data;
 };
 
-typedef int USBScanFunc(void *opaque, int bus_num, int addr, char *port,
+typedef int USBScanFunc(void *opaque, int bus_num, int addr, const char *port,
                         int class_id, int vendor_id, int product_id,
                         const char *product_name, int speed);
 
@@ -1141,7 +1141,8 @@ static int usb_linux_full_speed_compat(USBHostDevice *dev)
 }
 
 static int usb_host_open(USBHostDevice *dev, int bus_num,
-                        int addr, char *port, const char *prod_name, int speed)
+                         int addr, const char *port,
+                         const char *prod_name, int speed)
 {
     int fd = -1, ret;
     char buf[1024];
@@ -1774,7 +1775,8 @@ static int usb_host_scan(void *opaque, USBScanFunc *func)
 
 static QEMUTimer *usb_auto_timer;
 
-static int usb_host_auto_scan(void *opaque, int bus_num, int addr, char *port,
+static int usb_host_auto_scan(void *opaque, int bus_num,
+                              int addr, const char *port,
                               int class_id, int vendor_id, int product_id,
                               const char *product_name, int speed)
 {
@@ -1948,7 +1950,8 @@ static const char *usb_class_str(uint8_t class)
     return p->class_name;
 }
 
-static void usb_info_device(Monitor *mon, int bus_num, int addr, char *port,
+static void usb_info_device(Monitor *mon, int bus_num,
+                            int addr, const char *port,
                             int class_id, int vendor_id, int product_id,
                             const char *product_name,
                             int speed)
@@ -1989,7 +1992,7 @@ static void usb_info_device(Monitor *mon, int bus_num, int addr, char *port,
 }
 
 static int usb_host_info_device(void *opaque, int bus_num, int addr,
-                                char *path, int class_id,
+                                const char *path, int class_id,
                                 int vendor_id, int product_id,
                                 const char *product_name,
                                 int speed)
commit 2fe80192ba82fe298fe656c80d7e5981929393a6
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Aug 26 14:13:48 2011 +0200

    usb-ehci: handle siTDs
    
    This patch adds code to do minimal siTD handling, which is basically
    just following the next pointer.  This is good enougth to handle the
    inactive siTDs used by FreeBSD.  Active siTDs are skipped too as we
    don't have split transfer support in qemu, additionally a warning is
    printed.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 47a7fb9..d8ef0cb 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -149,6 +149,7 @@ typedef enum {
     EST_FETCHENTRY,
     EST_FETCHQH,
     EST_FETCHITD,
+    EST_FETCHSITD,
     EST_ADVANCEQUEUE,
     EST_FETCHQTD,
     EST_EXECUTE,
@@ -646,6 +647,13 @@ static void ehci_trace_itd(EHCIState *s, target_phys_addr_t addr, EHCIitd *itd)
                        get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR));
 }
 
+static void ehci_trace_sitd(EHCIState *s, target_phys_addr_t addr,
+                            EHCIsitd *sitd)
+{
+    trace_usb_ehci_sitd(addr, sitd->next,
+                        (bool)(sitd->results & SITD_RESULTS_ACTIVE));
+}
+
 /* queue management */
 
 static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, int async)
@@ -1584,8 +1592,13 @@ static int ehci_state_fetchentry(EHCIState *ehci, int async)
         again = 1;
         break;
 
+    case NLPTR_TYPE_STITD:
+        ehci_set_state(ehci, async, EST_FETCHSITD);
+        again = 1;
+        break;
+
     default:
-        // TODO: handle siTD and FSTN types
+        /* TODO: handle FSTN type */
         fprintf(stderr, "FETCHENTRY: entry at %X is of type %d "
                 "which is not supported yet\n", entry, NLPTR_TYPE_GET(entry));
         return -1;
@@ -1701,6 +1714,30 @@ static int ehci_state_fetchitd(EHCIState *ehci, int async)
     return 1;
 }
 
+static int ehci_state_fetchsitd(EHCIState *ehci, int async)
+{
+    uint32_t entry;
+    EHCIsitd sitd;
+
+    assert(!async);
+    entry = ehci_get_fetch_addr(ehci, async);
+
+    get_dwords(NLPTR_GET(entry), (uint32_t *)&sitd,
+               sizeof(EHCIsitd) >> 2);
+    ehci_trace_sitd(ehci, entry, &sitd);
+
+    if (!(sitd.results & SITD_RESULTS_ACTIVE)) {
+        /* siTD is not active, nothing to do */;
+    } else {
+        /* TODO: split transfers are not implemented */
+        fprintf(stderr, "WARNING: Skipping active siTD\n");
+    }
+
+    ehci_set_fetch_addr(ehci, async, sitd.next);
+    ehci_set_state(ehci, async, EST_FETCHENTRY);
+    return 1;
+}
+
 /* Section 4.10.2 - paragraph 3 */
 static int ehci_state_advqueue(EHCIQueue *q, int async)
 {
@@ -1976,6 +2013,10 @@ static void ehci_advance_state(EHCIState *ehci,
             again = ehci_state_fetchitd(ehci, async);
             break;
 
+        case EST_FETCHSITD:
+            again = ehci_state_fetchsitd(ehci, async);
+            break;
+
         case EST_ADVANCEQUEUE:
             again = ehci_state_advqueue(q, async);
             break;
diff --git a/trace-events b/trace-events
index a6e0cb4..5936192 100644
--- a/trace-events
+++ b/trace-events
@@ -223,6 +223,7 @@ usb_ehci_qtd_ptrs(void *q, uint32_t addr, uint32_t nxt, uint32_t altnext) "q %p
 usb_ehci_qtd_fields(uint32_t addr, int tbytes, int cpage, int cerr, int pid) "QTD @ %08x - tbytes %d, cpage %d, cerr %d, pid %d"
 usb_ehci_qtd_bits(uint32_t addr, int ioc, int active, int halt, int babble, int xacterr) "QTD @ %08x - ioc %d, active %d, halt %d, babble %d, xacterr %d"
 usb_ehci_itd(uint32_t addr, uint32_t nxt, uint32_t mplen, uint32_t mult, uint32_t ep, uint32_t devaddr) "ITD @ %08x: next %08x - mplen %d, mult %d, ep %d, dev %d"
+usb_ehci_sitd(uint32_t addr, uint32_t nxt, uint32_t active) "ITD @ %08x: next %08x - active %d"
 usb_ehci_port_attach(uint32_t port, const char *device) "attach port #%d - %s"
 usb_ehci_port_detach(uint32_t port) "detach port #%d"
 usb_ehci_port_reset(uint32_t port, int enable) "reset port #%d - %d"
commit c0e5750bc35366b7231693d9ae433bea9a485ef0
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Aug 26 16:27:41 2011 +0200

    usb-host: endpoint table fixup
    
    USB Devices can have up to 15 IN and 15 OUT endpoints, not 15 endpoints
    total.  Move from one array to two arrays (one IN, one OUT) to maintain
    the endpoint state.

diff --git a/usb-linux.c b/usb-linux.c
index ce0eadd..6490582 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -125,7 +125,8 @@ typedef struct USBHostDevice {
     uint32_t  iso_urb_count;
     Notifier  exit;
 
-    struct endp_data endp_table[MAX_ENDPOINTS];
+    struct endp_data ep_in[MAX_ENDPOINTS];
+    struct endp_data ep_out[MAX_ENDPOINTS];
     QLIST_HEAD(, AsyncURB) aurbs;
 
     /* Host side address */
@@ -147,52 +148,57 @@ static int usb_host_read_file(char *line, size_t line_size,
                             const char *device_file, const char *device_name);
 static int usb_linux_update_endp_table(USBHostDevice *s);
 
-static struct endp_data *get_endp(USBHostDevice *s, int ep)
+static struct endp_data *get_endp(USBHostDevice *s, int pid, int ep)
 {
-    return s->endp_table + ep - 1;
+    struct endp_data *eps = pid == USB_TOKEN_IN ? s->ep_in : s->ep_out;
+    assert(pid == USB_TOKEN_IN || pid == USB_TOKEN_OUT);
+    assert(ep > 0 && ep <= MAX_ENDPOINTS);
+    return eps + ep - 1;
 }
 
-static int is_isoc(USBHostDevice *s, int ep)
+static int is_isoc(USBHostDevice *s, int pid, int ep)
 {
-    return get_endp(s, ep)->type == USBDEVFS_URB_TYPE_ISO;
+    return get_endp(s, pid, ep)->type == USBDEVFS_URB_TYPE_ISO;
 }
 
-static int is_valid(USBHostDevice *s, int ep)
+static int is_valid(USBHostDevice *s, int pid, int ep)
 {
-    return get_endp(s, ep)->type != INVALID_EP_TYPE;
+    return get_endp(s, pid, ep)->type != INVALID_EP_TYPE;
 }
 
-static int is_halted(USBHostDevice *s, int ep)
+static int is_halted(USBHostDevice *s, int pid, int ep)
 {
-    return get_endp(s, ep)->halted;
+    return get_endp(s, pid, ep)->halted;
 }
 
-static void clear_halt(USBHostDevice *s, int ep)
+static void clear_halt(USBHostDevice *s, int pid, int ep)
 {
     trace_usb_host_ep_clear_halt(s->bus_num, s->addr, ep);
-    get_endp(s, ep)->halted = 0;
+    get_endp(s, pid, ep)->halted = 0;
 }
 
-static void set_halt(USBHostDevice *s, int ep)
+static void set_halt(USBHostDevice *s, int pid, int ep)
 {
-    trace_usb_host_ep_set_halt(s->bus_num, s->addr, ep);
-    get_endp(s, ep)->halted = 1;
+    if (ep != 0) {
+        trace_usb_host_ep_set_halt(s->bus_num, s->addr, ep);
+        get_endp(s, pid, ep)->halted = 1;
+    }
 }
 
-static int is_iso_started(USBHostDevice *s, int ep)
+static int is_iso_started(USBHostDevice *s, int pid, int ep)
 {
-    return get_endp(s, ep)->iso_started;
+    return get_endp(s, pid, ep)->iso_started;
 }
 
-static void clear_iso_started(USBHostDevice *s, int ep)
+static void clear_iso_started(USBHostDevice *s, int pid, int ep)
 {
     trace_usb_host_ep_stop_iso(s->bus_num, s->addr, ep);
-    get_endp(s, ep)->iso_started = 0;
+    get_endp(s, pid, ep)->iso_started = 0;
 }
 
-static void set_iso_started(USBHostDevice *s, int ep)
+static void set_iso_started(USBHostDevice *s, int pid, int ep)
 {
-    struct endp_data *e = get_endp(s, ep);
+    struct endp_data *e = get_endp(s, pid, ep);
 
     trace_usb_host_ep_start_iso(s->bus_num, s->addr, ep);
     if (!e->iso_started) {
@@ -201,45 +207,46 @@ static void set_iso_started(USBHostDevice *s, int ep)
     }
 }
 
-static int change_iso_inflight(USBHostDevice *s, int ep, int value)
+static int change_iso_inflight(USBHostDevice *s, int pid, int ep, int value)
 {
-    struct endp_data *e = get_endp(s, ep);
+    struct endp_data *e = get_endp(s, pid, ep);
 
     e->inflight += value;
     return e->inflight;
 }
 
-static void set_iso_urb(USBHostDevice *s, int ep, AsyncURB *iso_urb)
+static void set_iso_urb(USBHostDevice *s, int pid, int ep, AsyncURB *iso_urb)
 {
-    get_endp(s, ep)->iso_urb = iso_urb;
+    get_endp(s, pid, ep)->iso_urb = iso_urb;
 }
 
-static AsyncURB *get_iso_urb(USBHostDevice *s, int ep)
+static AsyncURB *get_iso_urb(USBHostDevice *s, int pid, int ep)
 {
-    return get_endp(s, ep)->iso_urb;
+    return get_endp(s, pid, ep)->iso_urb;
 }
 
-static void set_iso_urb_idx(USBHostDevice *s, int ep, int i)
+static void set_iso_urb_idx(USBHostDevice *s, int pid, int ep, int i)
 {
-    get_endp(s, ep)->iso_urb_idx = i;
+    get_endp(s, pid, ep)->iso_urb_idx = i;
 }
 
-static int get_iso_urb_idx(USBHostDevice *s, int ep)
+static int get_iso_urb_idx(USBHostDevice *s, int pid, int ep)
 {
-    return get_endp(s, ep)->iso_urb_idx;
+    return get_endp(s, pid, ep)->iso_urb_idx;
 }
 
-static void set_iso_buffer_used(USBHostDevice *s, int ep, int i)
+static void set_iso_buffer_used(USBHostDevice *s, int pid, int ep, int i)
 {
-    get_endp(s, ep)->iso_buffer_used = i;
+    get_endp(s, pid, ep)->iso_buffer_used = i;
 }
 
-static int get_iso_buffer_used(USBHostDevice *s, int ep)
+static int get_iso_buffer_used(USBHostDevice *s, int pid, int ep)
 {
-    return get_endp(s, ep)->iso_buffer_used;
+    return get_endp(s, pid, ep)->iso_buffer_used;
 }
 
-static void set_max_packet_size(USBHostDevice *s, int ep, uint8_t *descriptor)
+static void set_max_packet_size(USBHostDevice *s, int pid, int ep,
+                                uint8_t *descriptor)
 {
     int raw = descriptor[4] + (descriptor[5] << 8);
     int size, microframes;
@@ -250,12 +257,12 @@ static void set_max_packet_size(USBHostDevice *s, int ep, uint8_t *descriptor)
     case 2:  microframes = 3; break;
     default: microframes = 1; break;
     }
-    get_endp(s, ep)->max_packet_size = size * microframes;
+    get_endp(s, pid, ep)->max_packet_size = size * microframes;
 }
 
-static int get_max_packet_size(USBHostDevice *s, int ep)
+static int get_max_packet_size(USBHostDevice *s, int pid, int ep)
 {
-    return get_endp(s, ep)->max_packet_size;
+    return get_endp(s, pid, ep)->max_packet_size;
 }
 
 /*
@@ -334,13 +341,16 @@ static void async_complete(void *opaque)
            anything else (it is handled further in usb_host_handle_iso_data) */
         if (aurb->iso_frame_idx == -1) {
             int inflight;
+            int pid = (aurb->urb.endpoint & USB_DIR_IN) ?
+                USB_TOKEN_IN : USB_TOKEN_OUT;
+            int ep = aurb->urb.endpoint & 0xf;
             if (aurb->urb.status == -EPIPE) {
-                set_halt(s, aurb->urb.endpoint & 0xf);
+                set_halt(s, pid, ep);
             }
             aurb->iso_frame_idx = 0;
             urbs++;
-            inflight = change_iso_inflight(s, aurb->urb.endpoint & 0xf, -1);
-            if (inflight == 0 && is_iso_started(s, aurb->urb.endpoint & 0xf)) {
+            inflight = change_iso_inflight(s, pid, ep, -1);
+            if (inflight == 0 && is_iso_started(s, pid, ep)) {
                 fprintf(stderr, "husb: out of buffers for iso stream\n");
             }
             continue;
@@ -357,7 +367,7 @@ static void async_complete(void *opaque)
                 break;
 
             case -EPIPE:
-                set_halt(s, p->devep);
+                set_halt(s, p->pid, p->devep);
                 p->result = USB_RET_STALL;
                 break;
 
@@ -536,10 +546,10 @@ static void usb_host_handle_destroy(USBDevice *dev)
 /* iso data is special, we need to keep enough urbs in flight to make sure
    that the controller never runs out of them, otherwise the device will
    likely suffer a buffer underrun / overrun. */
-static AsyncURB *usb_host_alloc_iso(USBHostDevice *s, uint8_t ep, int in)
+static AsyncURB *usb_host_alloc_iso(USBHostDevice *s, int pid, uint8_t ep)
 {
     AsyncURB *aurb;
-    int i, j, len = get_max_packet_size(s, ep);
+    int i, j, len = get_max_packet_size(s, pid, ep);
 
     aurb = g_malloc0(s->iso_urb_count * sizeof(*aurb));
     for (i = 0; i < s->iso_urb_count; i++) {
@@ -551,23 +561,23 @@ static AsyncURB *usb_host_alloc_iso(USBHostDevice *s, uint8_t ep, int in)
         aurb[i].urb.number_of_packets = ISO_FRAME_DESC_PER_URB;
         for (j = 0 ; j < ISO_FRAME_DESC_PER_URB; j++)
             aurb[i].urb.iso_frame_desc[j].length = len;
-        if (in) {
+        if (pid == USB_TOKEN_IN) {
             aurb[i].urb.endpoint |= 0x80;
             /* Mark as fully consumed (idle) */
             aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB;
         }
     }
-    set_iso_urb(s, ep, aurb);
+    set_iso_urb(s, pid, ep, aurb);
 
     return aurb;
 }
 
-static void usb_host_stop_n_free_iso(USBHostDevice *s, uint8_t ep)
+static void usb_host_stop_n_free_iso(USBHostDevice *s, int pid, uint8_t ep)
 {
     AsyncURB *aurb;
     int i, ret, killed = 0, free = 1;
 
-    aurb = get_iso_urb(s, ep);
+    aurb = get_iso_urb(s, pid, ep);
     if (!aurb) {
         return;
     }
@@ -598,9 +608,9 @@ static void usb_host_stop_n_free_iso(USBHostDevice *s, uint8_t ep)
         g_free(aurb);
     else
         printf("husb: leaking iso urbs because of discard failure\n");
-    set_iso_urb(s, ep, NULL);
-    set_iso_urb_idx(s, ep, 0);
-    clear_iso_started(s, ep);
+    set_iso_urb(s, pid, ep, NULL);
+    set_iso_urb_idx(s, pid, ep, 0);
+    clear_iso_started(s, pid, ep);
 }
 
 static int urb_status_to_usb_ret(int status)
@@ -619,16 +629,16 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
     int i, j, ret, max_packet_size, offset, len = 0;
     uint8_t *buf;
 
-    max_packet_size = get_max_packet_size(s, p->devep);
+    max_packet_size = get_max_packet_size(s, p->pid, p->devep);
     if (max_packet_size == 0)
         return USB_RET_NAK;
 
-    aurb = get_iso_urb(s, p->devep);
+    aurb = get_iso_urb(s, p->pid, p->devep);
     if (!aurb) {
-        aurb = usb_host_alloc_iso(s, p->devep, in);
+        aurb = usb_host_alloc_iso(s, p->pid, p->devep);
     }
 
-    i = get_iso_urb_idx(s, p->devep);
+    i = get_iso_urb_idx(s, p->pid, p->devep);
     j = aurb[i].iso_frame_idx;
     if (j >= 0 && j < ISO_FRAME_DESC_PER_URB) {
         if (in) {
@@ -655,7 +665,7 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
             }
         } else {
             len = p->iov.size;
-            offset = (j == 0) ? 0 : get_iso_buffer_used(s, p->devep);
+            offset = (j == 0) ? 0 : get_iso_buffer_used(s, p->pid, p->devep);
 
             /* Check the frame fits */
             if (len > max_packet_size) {
@@ -667,27 +677,27 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
             usb_packet_copy(p, aurb[i].urb.buffer + offset, len);
             aurb[i].urb.iso_frame_desc[j].length = len;
             offset += len;
-            set_iso_buffer_used(s, p->devep, offset);
+            set_iso_buffer_used(s, p->pid, p->devep, offset);
 
             /* Start the stream once we have buffered enough data */
-            if (!is_iso_started(s, p->devep) && i == 1 && j == 8) {
-                set_iso_started(s, p->devep);
+            if (!is_iso_started(s, p->pid, p->devep) && i == 1 && j == 8) {
+                set_iso_started(s, p->pid, p->devep);
             }
         }
         aurb[i].iso_frame_idx++;
         if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
             i = (i + 1) % s->iso_urb_count;
-            set_iso_urb_idx(s, p->devep, i);
+            set_iso_urb_idx(s, p->pid, p->devep, i);
         }
     } else {
         if (in) {
-            set_iso_started(s, p->devep);
+            set_iso_started(s, p->pid, p->devep);
         } else {
             DPRINTF("hubs: iso out error no free buffer, dropping packet\n");
         }
     }
 
-    if (is_iso_started(s, p->devep)) {
+    if (is_iso_started(s, p->pid, p->devep)) {
         /* (Re)-submit all fully consumed / filled urbs */
         for (i = 0; i < s->iso_urb_count; i++) {
             if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
@@ -707,7 +717,7 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
                     break;
                 }
                 aurb[i].iso_frame_idx = -1;
-                change_iso_inflight(s, p->devep, +1);
+                change_iso_inflight(s, p->pid, p->devep, 1);
             }
         }
     }
@@ -728,7 +738,7 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
                             p->pid == USB_TOKEN_IN,
                             p->devep, p->iov.size);
 
-    if (!is_valid(s, p->devep)) {
+    if (!is_valid(s, p->pid, p->devep)) {
         trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
         return USB_RET_NAK;
     }
@@ -739,7 +749,7 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
         ep = p->devep;
     }
 
-    if (is_halted(s, p->devep)) {
+    if (is_halted(s, p->pid, p->devep)) {
         unsigned int arg = ep;
         ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &arg);
         if (ret < 0) {
@@ -747,10 +757,10 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
             trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
             return USB_RET_NAK;
         }
-        clear_halt(s, p->devep);
+        clear_halt(s, p->pid, p->devep);
     }
 
-    if (is_isoc(s, p->devep)) {
+    if (is_isoc(s, p->pid, p->devep)) {
         return usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN);
     }
 
@@ -854,8 +864,11 @@ static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
     trace_usb_host_set_interface(s->bus_num, s->addr, iface, alt);
 
     for (i = 1; i <= MAX_ENDPOINTS; i++) {
-        if (is_isoc(s, i)) {
-            usb_host_stop_n_free_iso(s, i);
+        if (is_isoc(s, USB_TOKEN_IN, i)) {
+            usb_host_stop_n_free_iso(s, USB_TOKEN_IN, i);
+        }
+        if (is_isoc(s, USB_TOKEN_OUT, i)) {
+            usb_host_stop_n_free_iso(s, USB_TOKEN_OUT, i);
         }
     }
 
@@ -995,10 +1008,13 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
 {
     uint8_t *descriptors;
     uint8_t devep, type, alt_interface;
-    int interface, length, i;
+    int interface, length, i, ep, pid;
+    struct endp_data *epd;
 
-    for (i = 0; i < MAX_ENDPOINTS; i++)
-        s->endp_table[i].type = INVALID_EP_TYPE;
+    for (i = 0; i < MAX_ENDPOINTS; i++) {
+        s->ep_in[i].type = INVALID_EP_TYPE;
+        s->ep_out[i].type = INVALID_EP_TYPE;
+    }
 
     if (s->configuration == 0) {
         /* not configured yet -- leave all endpoints disabled */
@@ -1052,7 +1068,9 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
             }
 
             devep = descriptors[i + 2];
-            if ((devep & 0x0f) == 0) {
+            pid = (devep & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT;
+            ep = devep & 0xf;
+            if (ep == 0) {
                 fprintf(stderr, "usb-linux: invalid ep descriptor, ep == 0\n");
                 return 1;
             }
@@ -1063,7 +1081,7 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
                 break;
             case 0x01:
                 type = USBDEVFS_URB_TYPE_ISO;
-                set_max_packet_size(s, (devep & 0xf), descriptors + i);
+                set_max_packet_size(s, pid, ep, descriptors + i);
                 break;
             case 0x02:
                 type = USBDEVFS_URB_TYPE_BULK;
@@ -1075,8 +1093,10 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
                 DPRINTF("usb_host: malformed endpoint type\n");
                 type = USBDEVFS_URB_TYPE_BULK;
             }
-            s->endp_table[(devep & 0xf) - 1].type = type;
-            s->endp_table[(devep & 0xf) - 1].halted = 0;
+            epd = get_endp(s, pid, ep);
+            assert(epd->type == INVALID_EP_TYPE);
+            epd->type = type;
+            epd->halted = 0;
 
             i += descriptors[i];
         }
@@ -1242,8 +1262,11 @@ static int usb_host_close(USBHostDevice *dev)
     qemu_set_fd_handler(dev->fd, NULL, NULL, NULL);
     dev->closing = 1;
     for (i = 1; i <= MAX_ENDPOINTS; i++) {
-        if (is_isoc(dev, i)) {
-            usb_host_stop_n_free_iso(dev, i);
+        if (is_isoc(dev, USB_TOKEN_IN, i)) {
+            usb_host_stop_n_free_iso(dev, USB_TOKEN_IN, i);
+        }
+        if (is_isoc(dev, USB_TOKEN_OUT, i)) {
+            usb_host_stop_n_free_iso(dev, USB_TOKEN_OUT, i);
         }
     }
     async_complete(dev);
commit 9516bb4772815f3bbf94d4779905681a7d254850
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Aug 24 13:34:17 2011 +0200

    usb-host: claim port
    
    When configured to pass through a specific host port (using hostbus and
    hostport properties), try to claim the port if supported by the kernel.
    That will avoid any kernel drivers binding to devices plugged into that
    port.  It will not stop any userspace apps (such as usb_modeswitch)
    access the device via usbfs though.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/trace-events b/trace-events
index e473aef..a6e0cb4 100644
--- a/trace-events
+++ b/trace-events
@@ -263,6 +263,7 @@ usb_host_ep_stop_iso(int bus, int addr, int ep) "dev %d:%d, ep %d"
 usb_host_reset(int bus, int addr) "dev %d:%d"
 usb_host_auto_scan_enabled(void)
 usb_host_auto_scan_disabled(void)
+usb_host_claim_port(int bus, int hub, int port) "bus %d, hub addr %d, port %d"
 
 # hw/scsi-bus.c
 scsi_req_alloc(int target, int lun, int tag) "target %d lun %d tag %d"
diff --git a/usb-linux.c b/usb-linux.c
index a903023..ce0eadd 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -115,6 +115,7 @@ struct USBAutoFilter {
 typedef struct USBHostDevice {
     USBDevice dev;
     int       fd;
+    int       hub_fd;
 
     uint8_t   descr[8192];
     int       descr_len;
@@ -525,6 +526,9 @@ static void usb_host_handle_destroy(USBDevice *dev)
     USBHostDevice *s = (USBHostDevice *)dev;
 
     usb_host_close(s);
+    if (s->hub_fd != -1) {
+        close(s->hub_fd);
+    }
     QTAILQ_REMOVE(&hostdevs, s, next);
     qemu_remove_exit_notifier(&s->exit);
 }
@@ -1266,10 +1270,63 @@ static int usb_host_initfn(USBDevice *dev)
 
     dev->auto_attach = 0;
     s->fd = -1;
+    s->hub_fd = -1;
+
     QTAILQ_INSERT_TAIL(&hostdevs, s, next);
     s->exit.notify = usb_host_exit_notifier;
     qemu_add_exit_notifier(&s->exit);
     usb_host_auto_check(NULL);
+
+#ifdef USBDEVFS_CLAIM_PORT
+    if (s->match.bus_num != 0 && s->match.port != NULL) {
+        char *h, hub_name[64], line[1024];
+        int hub_addr, portnr, ret;
+
+        snprintf(hub_name, sizeof(hub_name), "%d-%s",
+                 s->match.bus_num, s->match.port);
+
+        /* try strip off last ".$portnr" to get hub */
+        h = strrchr(hub_name, '.');
+        if (h != NULL) {
+            portnr = atoi(h+1);
+            *h = '\0';
+        } else {
+            /* no dot in there -> it is the root hub */
+            snprintf(hub_name, sizeof(hub_name), "usb%d",
+                     s->match.bus_num);
+            portnr = atoi(s->match.port);
+        }
+
+        if (!usb_host_read_file(line, sizeof(line), "devnum",
+                                hub_name)) {
+            goto out;
+        }
+        if (sscanf(line, "%d", &hub_addr) != 1) {
+            goto out;
+        }
+
+        if (!usb_host_device_path) {
+            goto out;
+        }
+        snprintf(line, sizeof(line), "%s/%03d/%03d",
+                 usb_host_device_path, s->match.bus_num, hub_addr);
+        s->hub_fd = open(line, O_RDWR | O_NONBLOCK);
+        if (s->hub_fd < 0) {
+            goto out;
+        }
+
+        ret = ioctl(s->hub_fd, USBDEVFS_CLAIM_PORT, &portnr);
+        if (ret < 0) {
+            close(s->hub_fd);
+            s->hub_fd = -1;
+            goto out;
+        }
+
+        trace_usb_host_claim_port(s->match.bus_num, hub_addr, portnr);
+    }
+out:
+#endif
+
     return 0;
 }
 
commit eb7700bb999544151d6e4350362b9b6d9d20abe8
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Aug 24 14:45:07 2011 +0200

    usb-host: fix configuration tracking.
    
    It is perfectly fine to leave the usb device in unconfigured state
    (USBHostDevice->configuration == 0).  Just do that and wait for the
    guest to explicitly set a configuration.  This is closer to what real
    hardware does and it also simplifies the device initialization.  There
    is no need to figure how the device is configured on the host.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/usb-linux.c b/usb-linux.c
index 36d25d7..a903023 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -407,8 +407,11 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
     int interface, nb_interfaces;
     int ret, i;
 
-    if (configuration == 0) /* address state - ignore */
+    if (configuration == 0) { /* address state - ignore */
+        dev->ninterfaces   = 0;
+        dev->configuration = 0;
         return 1;
+    }
 
     DPRINTF("husb: claiming interfaces. config %d\n", configuration);
 
@@ -433,7 +436,7 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
 
         DPRINTF("husb: config #%d need %d\n", dev->descr[i + 5], configuration);
 
-        if (configuration < 0 || configuration == dev->descr[i + 5]) {
+        if (configuration == dev->descr[i + 5]) {
             configuration = dev->descr[i + 5];
             break;
         }
@@ -513,7 +516,7 @@ static void usb_host_handle_reset(USBDevice *dev)
 
     ioctl(s->fd, USBDEVFS_RESET);
 
-    usb_host_claim_interfaces(s, s->configuration);
+    usb_host_claim_interfaces(s, 0);
     usb_linux_update_endp_table(s);
 }
 
@@ -835,6 +838,7 @@ static int usb_host_set_config(USBHostDevice *s, int config)
         return ctrl_error();
     }
     usb_host_claim_interfaces(s, config);
+    usb_linux_update_endp_table(s);
     return 0;
 }
 
@@ -941,51 +945,6 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
     return USB_RET_ASYNC;
 }
 
-static int usb_linux_get_configuration(USBHostDevice *s)
-{
-    uint8_t configuration;
-    struct usb_ctrltransfer ct;
-    int ret;
-
-    if (usb_fs_type == USB_FS_SYS) {
-        char device_name[32], line[1024];
-        int configuration;
-
-        sprintf(device_name, "%d-%s", s->bus_num, s->port);
-
-        if (!usb_host_read_file(line, sizeof(line), "bConfigurationValue",
-                                device_name)) {
-            goto usbdevfs;
-        }
-        if (sscanf(line, "%d", &configuration) != 1) {
-            goto usbdevfs;
-        }
-        return configuration;
-    }
-
-usbdevfs:
-    ct.bRequestType = USB_DIR_IN;
-    ct.bRequest = USB_REQ_GET_CONFIGURATION;
-    ct.wValue = 0;
-    ct.wIndex = 0;
-    ct.wLength = 1;
-    ct.data = &configuration;
-    ct.timeout = 50;
-
-    ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
-    if (ret < 0) {
-        perror("usb_linux_get_configuration");
-        return -1;
-    }
-
-    /* in address state */
-    if (configuration == 0) {
-        return -1;
-    }
-
-    return configuration;
-}
-
 static uint8_t usb_linux_get_alt_setting(USBHostDevice *s,
     uint8_t configuration, uint8_t interface)
 {
@@ -1031,16 +990,16 @@ usbdevfs:
 static int usb_linux_update_endp_table(USBHostDevice *s)
 {
     uint8_t *descriptors;
-    uint8_t devep, type, configuration, alt_interface;
+    uint8_t devep, type, alt_interface;
     int interface, length, i;
 
     for (i = 0; i < MAX_ENDPOINTS; i++)
         s->endp_table[i].type = INVALID_EP_TYPE;
 
-    i = usb_linux_get_configuration(s);
-    if (i < 0)
-        return 1;
-    configuration = i;
+    if (s->configuration == 0) {
+        /* not configured yet -- leave all endpoints disabled */
+        return 0;
+    }
 
     /* get the desired configuration, interface, and endpoint descriptors
      * from device description */
@@ -1049,8 +1008,9 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
     i = 0;
 
     if (descriptors[i + 1] != USB_DT_CONFIG ||
-        descriptors[i + 5] != configuration) {
-        DPRINTF("invalid descriptor data - configuration\n");
+        descriptors[i + 5] != s->configuration) {
+        fprintf(stderr, "invalid descriptor data - configuration %d\n",
+                s->configuration);
         return 1;
     }
     i += descriptors[i];
@@ -1064,7 +1024,8 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
         }
 
         interface = descriptors[i + 2];
-        alt_interface = usb_linux_get_alt_setting(s, configuration, interface);
+        alt_interface = usb_linux_get_alt_setting(s, s->configuration,
+                                                  interface);
 
         /* the current interface descriptor is the active interface
          * and has endpoints */
@@ -1204,13 +1165,8 @@ static int usb_host_open(USBHostDevice *dev, int bus_num,
 #endif
 
 
-    /*
-     * Initial configuration is -1 which makes us claim first
-     * available config. We used to start with 1, which does not
-     * always work. I've seen devices where first config starts
-     * with 2.
-     */
-    if (!usb_host_claim_interfaces(dev, -1)) {
+    /* start unconfigured -- we'll wait for the guest to set a configuration */
+    if (!usb_host_claim_interfaces(dev, 0)) {
         goto fail;
     }
 
commit 3ee886c5ba77a65d6b2c2a372a091d6796ed502b
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Aug 24 13:45:06 2011 +0200

    usb-host: limit open retries
    
    Limit the number of times qemu tries to open host devices to three.
    Reset error counter when the device goes away, after un-plugging and
    re-plugging the device qemu will try again three times.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/usb-linux.c b/usb-linux.c
index 344af22..36d25d7 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -132,6 +132,7 @@ typedef struct USBHostDevice {
     int addr;
     char port[MAX_PORTLEN];
     struct USBAutoFilter match;
+    int seen, errcount;
 
     QTAILQ_ENTRY(USBHostDevice) next;
 } USBHostDevice;
@@ -1769,6 +1770,10 @@ static int usb_host_auto_scan(void *opaque, int bus_num, int addr, char *port,
             continue;
         }
         /* We got a match */
+        s->seen++;
+        if (s->errcount >= 3) {
+            return 0;
+        }
 
         /* Already attached ? */
         if (s->fd != -1) {
@@ -1776,7 +1781,9 @@ static int usb_host_auto_scan(void *opaque, int bus_num, int addr, char *port,
         }
         DPRINTF("husb: auto open: bus_num %d addr %d\n", bus_num, addr);
 
-        usb_host_open(s, bus_num, addr, port, product_name, speed);
+        if (usb_host_open(s, bus_num, addr, port, product_name, speed) < 0) {
+            s->errcount++;
+        }
         break;
     }
 
@@ -1794,6 +1801,10 @@ static void usb_host_auto_check(void *unused)
         if (s->fd == -1) {
             unconnected++;
         }
+        if (s->seen == 0) {
+            s->errcount = 0;
+        }
+        s->seen = 0;
     }
 
     if (unconnected == 0) {
commit 9b87e19bc7adea69bd55ae9c64b8a7fb81214726
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Aug 24 10:55:40 2011 +0200

    usb-host: fix halted endpoints
    
    Two fixes for the price of one ;)
    
    First, reinitialize the endpoint table after device reset.
    This is needed anyway as the reset might have switched interfaces.
    It also clears the endpoint halted state.
    
    Second the CLEAR_HALT ioctl wants a unsigned int passed in as
    argument, not uint8_t.
    
    This gets my usb sd card reader (sandisk micromate) going.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/usb-linux.c b/usb-linux.c
index 12e8772..344af22 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -143,6 +143,7 @@ static int parse_filter(const char *spec, struct USBAutoFilter *f);
 static void usb_host_auto_check(void *unused);
 static int usb_host_read_file(char *line, size_t line_size,
                             const char *device_file, const char *device_name);
+static int usb_linux_update_endp_table(USBHostDevice *s);
 
 static struct endp_data *get_endp(USBHostDevice *s, int ep)
 {
@@ -512,6 +513,7 @@ static void usb_host_handle_reset(USBDevice *dev)
     ioctl(s->fd, USBDEVFS_RESET);
 
     usb_host_claim_interfaces(s, s->configuration);
+    usb_linux_update_endp_table(s);
 }
 
 static void usb_host_handle_destroy(USBDevice *dev)
@@ -523,8 +525,6 @@ static void usb_host_handle_destroy(USBDevice *dev)
     qemu_remove_exit_notifier(&s->exit);
 }
 
-static int usb_linux_update_endp_table(USBHostDevice *s);
-
 /* iso data is special, we need to keep enough urbs in flight to make sure
    that the controller never runs out of them, otherwise the device will
    likely suffer a buffer underrun / overrun. */
@@ -732,7 +732,8 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
     }
 
     if (is_halted(s, p->devep)) {
-        ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &ep);
+        unsigned int arg = ep;
+        ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &arg);
         if (ret < 0) {
             perror("USBDEVFS_CLEAR_HALT");
             trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
commit 40197c359b1f06cbaae5460336bca241c35f266e
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Mon Aug 22 14:18:21 2011 +0200

    usb-host: reapurb error report fix
    
    Don't report errors on devices which are in disconnected
    and closing state.

diff --git a/usb-linux.c b/usb-linux.c
index 4e4df61..12e8772 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -312,9 +312,11 @@ static void async_complete(void *opaque)
                 }
                 return;
             }
-            if (errno == ENODEV && !s->closing) {
-                trace_usb_host_disconnect(s->bus_num, s->addr);
-                do_disconnect(s);
+            if (errno == ENODEV) {
+                if (!s->closing) {
+                    trace_usb_host_disconnect(s->bus_num, s->addr);
+                    do_disconnect(s);
+                }
                 return;
             }
 
commit e6a2f50042580796de2df38e7eb7a907f4305839
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Mon Aug 22 14:13:20 2011 +0200

    usb-host: start tracing support
    
    Add a bunch of trace points to usb-linux.c  Drop a bunch of DPRINTK's in
    favor of the trace points.  Also cleanup error reporting a bit while being
    at it.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/trace-events b/trace-events
index 08ffedf..e473aef 100644
--- a/trace-events
+++ b/trace-events
@@ -240,6 +240,30 @@ usb_set_config(int addr, int config, int ret) "dev %d, config %d, ret %d"
 usb_clear_device_feature(int addr, int feature, int ret) "dev %d, feature %d, ret %d"
 usb_set_device_feature(int addr, int feature, int ret) "dev %d, feature %d, ret %d"
 
+# usb-linux.c
+usb_host_open_started(int bus, int addr) "dev %d:%d"
+usb_host_open_success(int bus, int addr) "dev %d:%d"
+usb_host_open_failure(int bus, int addr) "dev %d:%d"
+usb_host_disconnect(int bus, int addr) "dev %d:%d"
+usb_host_close(int bus, int addr) "dev %d:%d"
+usb_host_set_address(int bus, int addr, int config) "dev %d:%d, address %d"
+usb_host_set_config(int bus, int addr, int config) "dev %d:%d, config %d"
+usb_host_set_interface(int bus, int addr, int interface, int alt) "dev %d:%d, interface %d, alt %d"
+usb_host_claim_interfaces(int bus, int addr, int config, int nif) "dev %d:%d, config %d, nif %d"
+usb_host_release_interfaces(int bus, int addr) "dev %d:%d"
+usb_host_req_control(int bus, int addr, int req, int value, int index) "dev %d:%d, req 0x%x, value %d, index %d"
+usb_host_req_data(int bus, int addr, int in, int ep, int size) "dev %d:%d, in %d, ep %d, size %d"
+usb_host_req_complete(int bus, int addr, int status) "dev %d:%d, status %d"
+usb_host_urb_submit(int bus, int addr, void *aurb, int length, int more) "dev %d:%d, aurb %p, length %d, more %d"
+usb_host_urb_complete(int bus, int addr, void *aurb, int status, int length, int more) "dev %d:%d, aurb %p, status %d, length %d, more %d"
+usb_host_ep_set_halt(int bus, int addr, int ep) "dev %d:%d, ep %d"
+usb_host_ep_clear_halt(int bus, int addr, int ep) "dev %d:%d, ep %d"
+usb_host_ep_start_iso(int bus, int addr, int ep) "dev %d:%d, ep %d"
+usb_host_ep_stop_iso(int bus, int addr, int ep) "dev %d:%d, ep %d"
+usb_host_reset(int bus, int addr) "dev %d:%d"
+usb_host_auto_scan_enabled(void)
+usb_host_auto_scan_disabled(void)
+
 # hw/scsi-bus.c
 scsi_req_alloc(int target, int lun, int tag) "target %d lun %d tag %d"
 scsi_req_data(int target, int lun, int tag, int len) "target %d lun %d tag %d len %d"
diff --git a/usb-linux.c b/usb-linux.c
index 2e20f8e..4e4df61 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -34,6 +34,7 @@
 #include "qemu-timer.h"
 #include "monitor.h"
 #include "sysemu.h"
+#include "trace.h"
 
 #include <dirent.h>
 #include <sys/ioctl.h>
@@ -165,11 +166,13 @@ static int is_halted(USBHostDevice *s, int ep)
 
 static void clear_halt(USBHostDevice *s, int ep)
 {
+    trace_usb_host_ep_clear_halt(s->bus_num, s->addr, ep);
     get_endp(s, ep)->halted = 0;
 }
 
 static void set_halt(USBHostDevice *s, int ep)
 {
+    trace_usb_host_ep_set_halt(s->bus_num, s->addr, ep);
     get_endp(s, ep)->halted = 1;
 }
 
@@ -180,12 +183,15 @@ static int is_iso_started(USBHostDevice *s, int ep)
 
 static void clear_iso_started(USBHostDevice *s, int ep)
 {
+    trace_usb_host_ep_stop_iso(s->bus_num, s->addr, ep);
     get_endp(s, ep)->iso_started = 0;
 }
 
 static void set_iso_started(USBHostDevice *s, int ep)
 {
     struct endp_data *e = get_endp(s, ep);
+
+    trace_usb_host_ep_start_iso(s->bus_num, s->addr, ep);
     if (!e->iso_started) {
         e->iso_started = 1;
         e->inflight = 0;
@@ -285,8 +291,6 @@ static void async_free(AsyncURB *aurb)
 
 static void do_disconnect(USBHostDevice *s)
 {
-    printf("husb: device %d.%d disconnected\n",
-           s->bus_num, s->addr);
     usb_host_close(s);
     usb_host_auto_check(NULL);
 }
@@ -309,11 +313,12 @@ static void async_complete(void *opaque)
                 return;
             }
             if (errno == ENODEV && !s->closing) {
+                trace_usb_host_disconnect(s->bus_num, s->addr);
                 do_disconnect(s);
                 return;
             }
 
-            DPRINTF("husb: async. reap urb failed errno %d\n", errno);
+            perror("USBDEVFS_REAPURBNDELAY");
             return;
         }
 
@@ -337,6 +342,8 @@ static void async_complete(void *opaque)
         }
 
         p = aurb->packet;
+        trace_usb_host_urb_complete(s->bus_num, s->addr, aurb, aurb->urb.status,
+                                    aurb->urb.actual_length, aurb->more);
 
         if (p) {
             switch (aurb->urb.status) {
@@ -355,8 +362,10 @@ static void async_complete(void *opaque)
             }
 
             if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
+                trace_usb_host_req_complete(s->bus_num, s->addr, p->result);
                 usb_generic_async_ctrl_complete(&s->dev, p);
             } else if (!aurb->more) {
+                trace_usb_host_req_complete(s->bus_num, s->addr, p->result);
                 usb_packet_complete(&s->dev, p);
             }
         }
@@ -418,7 +427,7 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
         }
         config_descr_len = dev->descr[i];
 
-        printf("husb: config #%d need %d\n", dev->descr[i + 5], configuration);
+        DPRINTF("husb: config #%d need %d\n", dev->descr[i + 5], configuration);
 
         if (configuration < 0 || configuration == dev->descr[i + 5]) {
             configuration = dev->descr[i + 5];
@@ -457,17 +466,12 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
         op = "USBDEVFS_CLAIMINTERFACE";
         ret = ioctl(dev->fd, USBDEVFS_CLAIMINTERFACE, &interface);
         if (ret < 0) {
-            if (errno == EBUSY) {
-                printf("husb: update iface. device already grabbed\n");
-            } else {
-                perror("husb: failed to claim interface");
-            }
             goto fail;
         }
     }
 
-    printf("husb: %d interfaces claimed for configuration %d\n",
-           nb_interfaces, configuration);
+    trace_usb_host_claim_interfaces(dev->bus_num, dev->addr,
+                                    nb_interfaces, configuration);
 
     dev->ninterfaces   = nb_interfaces;
     dev->configuration = configuration;
@@ -485,16 +489,15 @@ static int usb_host_release_interfaces(USBHostDevice *s)
 {
     int ret, i;
 
-    DPRINTF("husb: releasing interfaces\n");
+    trace_usb_host_release_interfaces(s->bus_num, s->addr);
 
     for (i = 0; i < s->ninterfaces; i++) {
         ret = ioctl(s->fd, USBDEVFS_RELEASEINTERFACE, &i);
         if (ret < 0) {
-            perror("husb: failed to release interface");
+            perror("USBDEVFS_RELEASEINTERFACE");
             return 0;
         }
     }
-
     return 1;
 }
 
@@ -502,7 +505,7 @@ static void usb_host_handle_reset(USBDevice *dev)
 {
     USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
 
-    DPRINTF("husb: reset device %u.%u\n", s->bus_num, s->addr);
+    trace_usb_host_reset(s->bus_num, s->addr);
 
     ioctl(s->fd, USBDEVFS_RESET);
 
@@ -564,7 +567,7 @@ static void usb_host_stop_n_free_iso(USBHostDevice *s, uint8_t ep)
         if (aurb[i].iso_frame_idx == -1) {
             ret = ioctl(s->fd, USBDEVFS_DISCARDURB, &aurb[i]);
             if (ret < 0) {
-                printf("husb: discard isoc in urb failed errno %d\n", errno);
+                perror("USBDEVFS_DISCARDURB");
                 free = 0;
                 continue;
             }
@@ -680,7 +683,7 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
             if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
                 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, &aurb[i]);
                 if (ret < 0) {
-                    printf("husb error submitting iso urb %d: %d\n", i, errno);
+                    perror("USBDEVFS_SUBMITURB");
                     if (!in || len == 0) {
                         switch(errno) {
                         case ETIMEDOUT:
@@ -711,7 +714,12 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
     uint8_t *pbuf;
     uint8_t ep;
 
+    trace_usb_host_req_data(s->bus_num, s->addr,
+                            p->pid == USB_TOKEN_IN,
+                            p->devep, p->iov.size);
+
     if (!is_valid(s, p->devep)) {
+        trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
         return USB_RET_NAK;
     }
 
@@ -724,8 +732,8 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
     if (is_halted(s, p->devep)) {
         ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &ep);
         if (ret < 0) {
-            DPRINTF("husb: failed to clear halt. ep 0x%x errno %d\n",
-                   ep, errno);
+            perror("USBDEVFS_CLEAR_HALT");
+            trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
             return USB_RET_NAK;
         }
         clear_halt(s, p->devep);
@@ -767,20 +775,24 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
             aurb->more         = 1;
         }
 
+        trace_usb_host_urb_submit(s->bus_num, s->addr, aurb,
+                                  urb->buffer_length, aurb->more);
         ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
 
         DPRINTF("husb: data submit: ep 0x%x, len %u, more %d, packet %p, aurb %p\n",
                 urb->endpoint, urb->buffer_length, aurb->more, p, aurb);
 
         if (ret < 0) {
-            DPRINTF("husb: submit failed. errno %d\n", errno);
+            perror("USBDEVFS_SUBMITURB");
             async_free(aurb);
 
             switch(errno) {
             case ETIMEDOUT:
+                trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
                 return USB_RET_NAK;
             case EPIPE:
             default:
+                trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_STALL);
                 return USB_RET_STALL;
             }
         }
@@ -800,13 +812,15 @@ static int ctrl_error(void)
 
 static int usb_host_set_address(USBHostDevice *s, int addr)
 {
-    DPRINTF("husb: ctrl set addr %u\n", addr);
+    trace_usb_host_set_address(s->bus_num, s->addr, addr);
     s->dev.addr = addr;
     return 0;
 }
 
 static int usb_host_set_config(USBHostDevice *s, int config)
 {
+    trace_usb_host_set_config(s->bus_num, s->addr, config);
+
     usb_host_release_interfaces(s);
 
     int ret = ioctl(s->fd, USBDEVFS_SETCONFIGURATION, &config);
@@ -825,6 +839,8 @@ static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
     struct usbdevfs_setinterface si;
     int i, ret;
 
+    trace_usb_host_set_interface(s->bus_num, s->addr, iface, alt);
+
     for (i = 1; i <= MAX_ENDPOINTS; i++) {
         if (is_isoc(s, i)) {
             usb_host_stop_n_free_iso(s, i);
@@ -859,8 +875,7 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
      */
 
     /* Note request is (bRequestType << 8) | bRequest */
-    DPRINTF("husb: ctrl type 0x%x req 0x%x val 0x%x index %u len %u\n",
-            request >> 8, request & 0xff, value, index, length);
+    trace_usb_host_req_control(s->bus_num, s->addr, request, value, index);
 
     switch (request) {
     case DeviceOutRequest | USB_REQ_SET_ADDRESS:
@@ -900,6 +915,8 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
 
     urb->usercontext = s;
 
+    trace_usb_host_urb_submit(s->bus_num, s->addr, aurb,
+                              urb->buffer_length, aurb->more);
     ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
 
     DPRINTF("husb: submit ctrl. len %u aurb %p\n", urb->buffer_length, aurb);
@@ -1140,10 +1157,11 @@ static int usb_host_open(USBHostDevice *dev, int bus_num,
     int fd = -1, ret;
     char buf[1024];
 
+    trace_usb_host_open_started(bus_num, addr);
+
     if (dev->fd != -1) {
         goto fail;
     }
-    printf("husb: open device %d.%d\n", bus_num, addr);
 
     if (!usb_host_device_path) {
         perror("husb: USB Host Device Path not set");
@@ -1218,7 +1236,7 @@ static int usb_host_open(USBHostDevice *dev, int bus_num,
         dev->dev.speedmask |= USB_SPEED_MASK_FULL;
     }
 
-    printf("husb: grabbed usb device %d.%d\n", bus_num, addr);
+    trace_usb_host_open_success(bus_num, addr);
 
     if (!prod_name || prod_name[0] == '\0') {
         snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc),
@@ -1239,6 +1257,7 @@ static int usb_host_open(USBHostDevice *dev, int bus_num,
     return 0;
 
 fail:
+    trace_usb_host_open_failure(bus_num, addr);
     if (dev->fd != -1) {
         close(dev->fd);
         dev->fd = -1;
@@ -1254,6 +1273,8 @@ static int usb_host_close(USBHostDevice *dev)
         return -1;
     }
 
+    trace_usb_host_close(dev->bus_num, dev->addr);
+
     qemu_set_fd_handler(dev->fd, NULL, NULL, NULL);
     dev->closing = 1;
     for (i = 1; i <= MAX_ENDPOINTS; i++) {
@@ -1776,6 +1797,7 @@ static void usb_host_auto_check(void *unused)
         /* nothing to watch */
         if (usb_auto_timer) {
             qemu_del_timer(usb_auto_timer);
+            trace_usb_host_auto_scan_disabled();
         }
         return;
     }
@@ -1785,6 +1807,7 @@ static void usb_host_auto_check(void *unused)
         if (!usb_auto_timer) {
             return;
         }
+        trace_usb_host_auto_scan_enabled();
     }
     qemu_mod_timer(usb_auto_timer, qemu_get_clock_ms(rt_clock) + 2000);
 }
commit 22b626e28e9895cc65c1e2023323bda5138716dc
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Sep 2 15:03:28 2011 +0200

    spice: workaround a spice server bug.
    
    spice server might call the channel_event callback from spice server
    thread context.  Detect that and aquire iothread lock if needed,

diff --git a/ui/spice-core.c b/ui/spice-core.c
index dba11f0..3cbc721 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -19,6 +19,7 @@
 #include <spice-experimental.h>
 
 #include <netdb.h>
+#include <pthread.h>
 
 #include "qemu-common.h"
 #include "qemu-spice.h"
@@ -44,6 +45,8 @@ static char *auth_passwd;
 static time_t auth_expires = TIME_MAX;
 int using_spice = 0;
 
+static pthread_t me;
+
 struct SpiceTimer {
     QEMUTimer *timer;
     QTAILQ_ENTRY(SpiceTimer) next;
@@ -217,6 +220,20 @@ static void channel_event(int event, SpiceChannelEventInfo *info)
     QDict *server, *client;
     QObject *data;
 
+    /*
+     * Spice server might have called us from spice worker thread
+     * context (happens on display channel disconnects).  Spice should
+     * not do that.  It isn't that easy to fix it in spice and even
+     * when it is fixed we still should cover the already released
+     * spice versions.  So detect that we've been called from another
+     * thread and grab the iothread lock if so before calling qemu
+     * functions.
+     */
+    bool need_lock = !pthread_equal(me, pthread_self());
+    if (need_lock) {
+        qemu_mutex_lock_iothread();
+    }
+
     client = qdict_new();
     add_addr_info(client, &info->paddr, info->plen);
 
@@ -236,6 +253,10 @@ static void channel_event(int event, SpiceChannelEventInfo *info)
                               QOBJECT(client), QOBJECT(server));
     monitor_protocol_event(qevent[event], data);
     qobject_decref(data);
+
+    if (need_lock) {
+        qemu_mutex_unlock_iothread();
+    }
 }
 
 #else /* SPICE_INTERFACE_CORE_MINOR >= 3 */
@@ -482,7 +503,9 @@ void qemu_spice_init(void)
     spice_image_compression_t compression;
     spice_wan_compression_t wan_compr;
 
-    if (!opts) {
+    me = pthread_self();
+
+   if (!opts) {
         return;
     }
     port = qemu_opt_get_number(opts, "port", 0);
commit 7e79cf4083efa399b43f30edf23434b137fcb197
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Mon Sep 5 17:39:50 2011 +0300

    spice: set qxl->ssd.running=true before telling spice to start, RHBZ #733993
    
    If qxl->ssd.running=true is set after telling spice to start, the spice server
    thread can call qxl_send_events while qxl->ssd.running is still false. This leads to
    assert(d->ssd.running).
    
    Signed-off-by: Yonit Halperin <yhalperi at redhat.com>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/ui/spice-display.c b/ui/spice-display.c
index 4983963..e385361 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -260,11 +260,12 @@ void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason)
     SimpleSpiceDisplay *ssd = opaque;
 
     if (running) {
+        ssd->running = true;
         qemu_spice_start(ssd);
     } else {
         qemu_spice_stop(ssd);
+        ssd->running = false;
     }
-    ssd->running = running;
 }
 
 void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd, DisplayState *ds)
commit 40010aea63bb7d507caf24c9ac74c13ece47eec2
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Mon Sep 5 08:45:59 2011 +0300

    qxl: s/qxl_set_irq/qxl_update_irq/
    
    Signed-off-by: Yonit Halperin <yhalperi at redhat.com>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/qxl.c b/hw/qxl.c
index 7bb2560..a282d23 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -808,7 +808,7 @@ static void qxl_exit_vga_mode(PCIQXLDevice *d)
     qxl_destroy_primary(d, QXL_SYNC);
 }
 
-static void qxl_set_irq(PCIQXLDevice *d)
+static void qxl_update_irq(PCIQXLDevice *d)
 {
     uint32_t pending = le32_to_cpu(d->ram->int_pending);
     uint32_t mask    = le32_to_cpu(d->ram->int_mask);
@@ -1209,7 +1209,7 @@ async_common:
         qemu_spice_wakeup(&d->ssd);
         break;
     case QXL_IO_UPDATE_IRQ:
-        qxl_set_irq(d);
+        qxl_update_irq(d);
         break;
     case QXL_IO_NOTIFY_OOM:
         if (!SPICE_RING_IS_EMPTY(&d->ram->release_ring)) {
@@ -1359,7 +1359,7 @@ static void pipe_read(void *opaque)
     do {
         len = read(d->pipe[0], &dummy, sizeof(dummy));
     } while (len == sizeof(dummy));
-    qxl_set_irq(d);
+    qxl_update_irq(d);
 }
 
 static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
@@ -1373,7 +1373,7 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
         return;
     }
     if (pthread_self() == d->main) {
-        qxl_set_irq(d);
+        qxl_update_irq(d);
     } else {
         if (write(d->pipe[1], d, 1) != 1) {
             dprint(d, 1, "%s: write to pipe failed\n", __FUNCTION__);
@@ -1461,10 +1461,10 @@ static void qxl_vm_change_state_handler(void *opaque, int running, int reason)
     if (running) {
         /*
          * if qxl_send_events was called from spice server context before
-         * migration ended, qxl_set_irq for these events might not have been
+         * migration ended, qxl_update_irq for these events might not have been
          * called
          */
-         qxl_set_irq(qxl);
+         qxl_update_irq(qxl);
     } else if (qxl->mode == QXL_MODE_NATIVE) {
         /* dirty all vram (which holds surfaces) and devram (primary surface)
          * to make sure they are saved */
commit efbf2950f52d467695db2944eea7664ede19fa9b
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Mon Sep 5 08:45:58 2011 +0300

    qxl: send interrupt after migration in case ram->int_pending != 0, RHBZ #732949
    
    if qxl_send_events was called from spice server context, and then
    migration had completed before a call to pipe_read, the target
    guest qxl driver didn't get the interrupt. In addition,
    qxl_send_events ignored further interrupts of the same kind, since
    ram->int_pending was set. As a result, the guest driver was stacked
    or very slow (when the waiting for the interrupt was with timeout).
    
    Signed-off-by: Yonit Halperin <yhalperi at redhat.com>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/qxl.c b/hw/qxl.c
index 1fe0b53..7bb2560 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -1362,7 +1362,6 @@ static void pipe_read(void *opaque)
     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;
@@ -1459,7 +1458,14 @@ 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) {
+    if (running) {
+        /*
+         * if qxl_send_events was called from spice server context before
+         * migration ended, qxl_set_irq for these events might not have been
+         * called
+         */
+         qxl_set_irq(qxl);
+    } else if (qxl->mode == QXL_MODE_NATIVE) {
         /* dirty all vram (which holds surfaces) and devram (primary surface)
          * to make sure they are saved */
         /* FIXME #1: should go out during "live" stage */
commit a680f7e7cbe8bebd15de2d974989d4e58810837d
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Sat Sep 3 14:48:25 2011 +0100

    hw/qxl: Fix format string errors
    
    Fix format string errors causing compile failure on 32 bit hosts
    when spice is enabled.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/qxl-logger.c b/hw/qxl-logger.c
index 74cadba..367aad1 100644
--- a/hw/qxl-logger.c
+++ b/hw/qxl-logger.c
@@ -224,7 +224,7 @@ void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext)
     if (!qxl->cmdlog) {
         return;
     }
-    fprintf(stderr, "%ld qxl-%d/%s:", qemu_get_clock_ns(vm_clock),
+    fprintf(stderr, "%" PRId64 " qxl-%d/%s:", qemu_get_clock_ns(vm_clock),
             qxl->id, ring);
     fprintf(stderr, " cmd @ 0x%" PRIx64 " %s%s", ext->cmd.data,
             qxl_name(qxl_type, ext->cmd.type),
diff --git a/hw/qxl.c b/hw/qxl.c
index 45e2401..1fe0b53 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -959,7 +959,7 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t 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",
+    dprint(d, 1, "%s: slot %d: host virt 0x%lx - 0x%lx\n",
            __FUNCTION__, memslot.slot_id,
            memslot.virt_start, memslot.virt_end);
 
@@ -1090,8 +1090,8 @@ static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm)
         .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);
+    dprint(d, 1, "%s: mode %d  [ %d x %d @ %d bpp devmem 0x%" PRIx64 " ]\n",
+           __func__, modenr, mode->x_res, mode->y_res, mode->bits, devmem);
     if (!loadvm) {
         qxl_hard_reset(d, 0);
     }
@@ -1229,7 +1229,7 @@ async_common:
         break;
     case QXL_IO_LOG:
         if (d->guestdebug) {
-            fprintf(stderr, "qxl/guest-%d: %ld: %s", d->id,
+            fprintf(stderr, "qxl/guest-%d: %" PRId64 ": %s", d->id,
                     qemu_get_clock_ns(vm_clock), d->ram->log_buf);
         }
         break;
commit 7b6c73690e4eb5c56abba1904ec71455b28074a3
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Tue Aug 9 23:04:35 2011 +0100

    spice-qemu-char.c: Use correct printf format char for ssize_t
    
    Use the correct printf format string character (%z) for ssize_t.
    This fixes a compile failure on 32 bit Linux with spice enabled.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/spice-qemu-char.c b/spice-qemu-char.c
index a9323f3..ac52202 100644
--- a/spice-qemu-char.c
+++ b/spice-qemu-char.c
@@ -45,7 +45,7 @@ static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
         p += last_out;
     }
 
-    dprintf(scd, 3, "%s: %lu/%zd\n", __func__, out, len + out);
+    dprintf(scd, 3, "%s: %zu/%zd\n", __func__, out, len + out);
     trace_spice_vmc_write(out, len + out);
     return out;
 }
commit cfc606da0ddcef1f7228317b9f7dfa6c94c6c64f
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Tue Sep 6 12:31:44 2011 +0200

    scsi: improve MODE SENSE emulation
    
    - do not return extra pages when requesting all pages (PAGE CODE = 0x3f)
    
    - return correct sense code for PC = 3 (saved parameters not supported)
    
    - do not return geometry pages for CD devices
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index ead4163..9724d0f 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -546,12 +546,12 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
     return buflen;
 }
 
-static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p,
+static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
                            int page_control)
 {
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
     BlockDriverState *bdrv = s->bs;
     int cylinders, heads, secs;
+    uint8_t *p = *p_outbuf;
 
     /*
      * If Changeable Values are requested, a mask denoting those mode parameters
@@ -561,10 +561,13 @@ static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p,
      */
     switch (page) {
     case 4: /* Rigid disk device geometry page. */
+        if (s->qdev.type == TYPE_ROM) {
+            return -1;
+        }
         p[0] = 4;
         p[1] = 0x16;
         if (page_control == 1) { /* Changeable Values */
-            return p[1] + 2;
+            break;
         }
         /* if a geometry hint is available, use it */
         bdrv_get_geometry_hint(bdrv, &cylinders, &heads, &secs);
@@ -590,13 +593,16 @@ static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p,
         /* Medium rotation rate [rpm], 5400 rpm */
         p[20] = (5400 >> 8) & 0xff;
         p[21] = 5400 & 0xff;
-        return p[1] + 2;
+        break;
 
     case 5: /* Flexible disk device geometry page. */
+        if (s->qdev.type == TYPE_ROM) {
+            return -1;
+        }
         p[0] = 5;
         p[1] = 0x1e;
         if (page_control == 1) { /* Changeable Values */
-            return p[1] + 2;
+            break;
         }
         /* Transfer rate [kbit/s], 5Mbit/s */
         p[2] = 5000 >> 8;
@@ -629,26 +635,27 @@ static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p,
         /* Medium rotation rate [rpm], 5400 rpm */
         p[28] = (5400 >> 8) & 0xff;
         p[29] = 5400 & 0xff;
-        return p[1] + 2;
+        break;
 
     case 8: /* Caching page.  */
         p[0] = 8;
         p[1] = 0x12;
         if (page_control == 1) { /* Changeable Values */
-            return p[1] + 2;
+            break;
         }
         if (bdrv_enable_write_cache(s->bs)) {
             p[2] = 4; /* WCE */
         }
-        return p[1] + 2;
+        break;
 
     case 0x2a: /* CD Capabilities and Mechanical Status page. */
-        if (s->qdev.type != TYPE_ROM)
-            return 0;
+        if (s->qdev.type != TYPE_ROM) {
+            return -1;
+        }
         p[0] = 0x2a;
         p[1] = 0x14;
         if (page_control == 1) { /* Changeable Values */
-            return p[1] + 2;
+            break;
         }
         p[2] = 3; // CD-R & CD-RW read
         p[3] = 0; // Writing not supported
@@ -673,27 +680,30 @@ static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p,
         p[19] = (16 * 176) & 0xff;
         p[20] = (16 * 176) >> 8; // 16x write speed current
         p[21] = (16 * 176) & 0xff;
-        return p[1] + 2;
+        break;
 
     default:
-        return 0;
+        return -1;
     }
+
+    *p_outbuf += p[1] + 2;
+    return p[1] + 2;
 }
 
-static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf)
+static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
 {
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
     uint64_t nb_sectors;
-    int page, dbd, buflen, page_control;
+    int page, dbd, buflen, ret, page_control;
     uint8_t *p;
     uint8_t dev_specific_param;
 
-    dbd = req->cmd.buf[1]  & 0x8;
-    page = req->cmd.buf[2] & 0x3f;
-    page_control = (req->cmd.buf[2] & 0xc0) >> 6;
+    dbd = r->req.cmd.buf[1]  & 0x8;
+    page = r->req.cmd.buf[2] & 0x3f;
+    page_control = (r->req.cmd.buf[2] & 0xc0) >> 6;
     DPRINTF("Mode Sense(%d) (page %d, xfer %zd, page_control %d)\n",
-        (req->cmd.buf[0] == MODE_SENSE) ? 6 : 10, page, req->cmd.xfer, page_control);
-    memset(outbuf, 0, req->cmd.xfer);
+        (r->req.cmd.buf[0] == MODE_SENSE) ? 6 : 10, page, r->req.cmd.xfer, page_control);
+    memset(outbuf, 0, r->req.cmd.xfer);
     p = outbuf;
 
     if (bdrv_is_read_only(s->bs)) {
@@ -702,7 +712,7 @@ static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf)
         dev_specific_param = 0x00;
     }
 
-    if (req->cmd.buf[0] == MODE_SENSE) {
+    if (r->req.cmd.buf[0] == MODE_SENSE) {
         p[1] = 0; /* Default media type.  */
         p[2] = dev_specific_param;
         p[3] = 0; /* Block descriptor length.  */
@@ -716,7 +726,7 @@ static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf)
 
     bdrv_get_geometry(s->bs, &nb_sectors);
     if (!dbd && nb_sectors) {
-        if (req->cmd.buf[0] == MODE_SENSE) {
+        if (r->req.cmd.buf[0] == MODE_SENSE) {
             outbuf[3] = 8; /* Block descriptor length  */
         } else { /* MODE_SENSE_10 */
             outbuf[7] = 8; /* Block descriptor length  */
@@ -735,23 +745,21 @@ static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf)
         p += 8;
     }
 
-    if (page_control == 3) { /* Saved Values */
-        return -1; /* ILLEGAL_REQUEST */
+    if (page_control == 3) {
+        /* Saved Values */
+        scsi_check_condition(r, SENSE_CODE(SAVING_PARAMS_NOT_SUPPORTED));
+        return -1;
     }
 
-    switch (page) {
-    case 0x04:
-    case 0x05:
-    case 0x08:
-    case 0x2a:
-        p += mode_sense_page(req, page, p, page_control);
-        break;
-    case 0x3f:
-        p += mode_sense_page(req, 0x08, p, page_control);
-        p += mode_sense_page(req, 0x2a, p, page_control);
-        break;
-    default:
-        return -1; /* ILLEGAL_REQUEST */
+    if (page == 0x3f) {
+        for (page = 0; page <= 0x3e; page++) {
+            mode_sense_page(s, page, &p, page_control);
+        }
+    } else {
+        ret = mode_sense_page(s, page, &p, page_control);
+        if (ret == -1) {
+            return -1;
+        }
     }
 
     buflen = p - outbuf;
@@ -760,14 +768,14 @@ static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf)
      * following data that is available to be transferred. The mode data
      * length does not include itself.
      */
-    if (req->cmd.buf[0] == MODE_SENSE) {
+    if (r->req.cmd.buf[0] == MODE_SENSE) {
         outbuf[0] = buflen - 1;
     } else { /* MODE_SENSE_10 */
         outbuf[0] = ((buflen - 2) >> 8) & 0xff;
         outbuf[1] = (buflen - 2) & 0xff;
     }
-    if (buflen > req->cmd.xfer)
-        buflen = req->cmd.xfer;
+    if (buflen > r->req.cmd.xfer)
+        buflen = r->req.cmd.xfer;
     return buflen;
 }
 
@@ -825,7 +833,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
         break;
     case MODE_SENSE:
     case MODE_SENSE_10:
-        buflen = scsi_disk_emulate_mode_sense(req, outbuf);
+        buflen = scsi_disk_emulate_mode_sense(r, outbuf);
         if (buflen < 0)
             goto illegal_request;
         break;
@@ -946,7 +954,9 @@ not_ready:
     return -1;
 
 illegal_request:
-    scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
+    if (r->req.status == -1) {
+        scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
+    }
     return -1;
 }
 
commit eae31cb99810c362955f37f82573f2e3849bcd32
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Tue Sep 6 12:31:43 2011 +0200

    scsi: fill in additional sense length correctly
    
    Even though we do not use them, we should include the last three
    bytes of sense data in the additional sense length.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index d6fd19a..160eaee 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -498,6 +498,7 @@ void scsi_req_build_sense(SCSIRequest *req, SCSISense sense)
     memset(req->sense, 0, 18);
     req->sense[0] = 0xf0;
     req->sense[2] = sense.key;
+    req->sense[7] = 10;
     req->sense[12] = sense.asc;
     req->sense[13] = sense.ascq;
     req->sense_len = 18;
@@ -883,7 +884,7 @@ int scsi_build_sense(uint8_t *in_buf, int in_len,
         /* Return fixed format sense buffer */
         buf[0] = 0xf0;
         buf[2] = sense.key;
-        buf[7] = 7;
+        buf[7] = 10;
         buf[12] = sense.asc;
         buf[13] = sense.ascq;
         return MIN(len, 18);
commit 69faeee12aee8f54870dbea78d9d1e98e30bd773
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date:   Fri Aug 26 19:52:11 2011 +0200

    Fix qjson test of solidus encoding
    
    "\/" is supposed to be decoded as "/", but there is no need to encode
    "/" via escape. Fix the existing test and add a second one expressing
    this.
    
    Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
    Acked-by: Michael Roth <mdroth at linux.vnet.ibm.com>
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/check-qjson.c b/check-qjson.c
index 64fcdcb..36d4ac2 100644
--- a/check-qjson.c
+++ b/check-qjson.c
@@ -33,7 +33,8 @@ START_TEST(escaped_string)
         { "\"\\n\"", "\n" },
         { "\"\\r\"", "\r" },
         { "\"\\t\"", "\t" },
-        { "\"\\/\"", "\\/" },
+        { "\"/\"", "/" },
+        { "\"\\/\"", "/", .skip = 1 },
         { "\"\\\\\"", "\\" },
         { "\"\\\"\"", "\"" },
         { "\"hello world \\\"embedded string\\\"\"",
commit 70371cfbf1b5bac6471928f5e30356cb6f7d1187
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date:   Fri Aug 26 15:00:13 2011 -0300

    configure: Copy test data to build directory
    
    The QDict unit-tests (check-qdict) will fail when ran on a different
    build directory. That's, it only works when ran on the source dir.
    
    This happens because its data file (qdict-test-data.txt) is not
    copied to the build dir. Fix it.
    
    Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>

diff --git a/configure b/configure
index c3044c7..fe3147b 100755
--- a/configure
+++ b/configure
@@ -3614,7 +3614,7 @@ DIRS="$DIRS roms/seabios roms/vgabios"
 DIRS="$DIRS fsdev ui"
 DIRS="$DIRS qapi"
 DIRS="$DIRS qga trace"
-FILES="Makefile tests/Makefile"
+FILES="Makefile tests/Makefile qdict-test-data.txt"
 FILES="$FILES tests/cris/Makefile tests/cris/.gdbinit"
 FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps"
 FILES="$FILES pc-bios/spapr-rtas/Makefile"
commit f651526271fb0b3d12f07f0810d80512edf384ad
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Tue Sep 6 12:31:42 2011 +0200

    scsi: refine constants for READ CAPACITY 16
    
    Rename SERVICE_ACTION_IN to SERVICE_ACTION_IN_16 to distinguish
    from the 12-byte CDB variant, and add a constant for the subcommand.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 6f0d039..d6fd19a 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -977,7 +977,7 @@ static const char *scsi_command_name(uint8_t cmd)
         [ LOCATE_16                ] = "LOCATE_16",
         [ WRITE_SAME_16            ] = "WRITE_SAME_16",
         [ ERASE_16                 ] = "ERASE_16",
-        [ SERVICE_ACTION_IN        ] = "SERVICE_ACTION_IN",
+        [ SERVICE_ACTION_IN_16     ] = "SERVICE_ACTION_IN_16",
         [ WRITE_LONG_16            ] = "WRITE_LONG_16",
         [ REPORT_LUNS              ] = "REPORT_LUNS",
         [ BLANK                    ] = "BLANK",
@@ -987,6 +987,7 @@ static const char *scsi_command_name(uint8_t cmd)
         [ LOAD_UNLOAD              ] = "LOAD_UNLOAD",
         [ READ_12                  ] = "READ_12",
         [ WRITE_12                 ] = "WRITE_12",
+        [ SERVICE_ACTION_IN_12     ] = "SERVICE_ACTION_IN_12",
         [ WRITE_VERIFY_12          ] = "WRITE_VERIFY_12",
         [ VERIFY_12                ] = "VERIFY_12",
         [ SEARCH_HIGH_12           ] = "SEARCH_HIGH_12",
diff --git a/hw/scsi-defs.h b/hw/scsi-defs.h
index ea288fa..bfe9392 100644
--- a/hw/scsi-defs.h
+++ b/hw/scsi-defs.h
@@ -102,7 +102,7 @@
 #define LOCATE_16             0x92
 #define WRITE_SAME_16         0x93
 #define ERASE_16              0x93
-#define SERVICE_ACTION_IN     0x9e
+#define SERVICE_ACTION_IN_16  0x9e
 #define WRITE_LONG_16         0x9f
 #define REPORT_LUNS           0xa0
 #define BLANK                 0xa1
@@ -112,6 +112,7 @@
 #define LOAD_UNLOAD           0xa6
 #define READ_12               0xa8
 #define WRITE_12              0xaa
+#define SERVICE_ACTION_IN_12  0xab
 #define WRITE_VERIFY_12       0xae
 #define VERIFY_12             0xaf
 #define SEARCH_HIGH_12        0xb0
@@ -123,6 +124,11 @@
 #define SET_CD_SPEED          0xbb
 
 /*
+ * SERVICE ACTION IN subcodes
+ */
+#define SAI_READ_CAPACITY_16  0x10
+
+/*
  *  SAM Status codes
  */
 
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index c23c2b8..ead4163 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -890,9 +890,9 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
         outbuf[7] = 8; // CD-ROM
         buflen = 8;
         break;
-    case SERVICE_ACTION_IN:
+    case SERVICE_ACTION_IN_16:
         /* Service Action In subcommands. */
-        if ((req->cmd.buf[1] & 31) == 0x10) {
+        if ((req->cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
             DPRINTF("SAI READ CAPACITY(16)\n");
             memset(outbuf, 0, req->cmd.xfer);
             bdrv_get_geometry(s->bs, &nb_sectors);
@@ -992,7 +992,7 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
     case READ_CAPACITY_10:
     case READ_TOC:
     case GET_CONFIGURATION:
-    case SERVICE_ACTION_IN:
+    case SERVICE_ACTION_IN_16:
     case VERIFY_10:
         rc = scsi_disk_emulate_command(r, outbuf);
         if (rc < 0) {
commit 8e321cc622a5583243b7641c84a5aeef66c07bb3
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Mon Sep 5 18:11:51 2011 +0200

    scsi: fix accounting of writes
    
    Writes go through scsi_write_complete at least twice, the first time
    to get some data without having actually written anything.  Because
    of this, the first time scsi_write_complete is called it will call
    bdrv_acct_done and account a read incorrectly.  Fix this by looking
    at the aiocb.  I am doing the same in scsi_read_complete for symmetry,
    but it is only needed in the (bogus) case of bdrv_aio_readv returning
    NULL.
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 5c652a2..c23c2b8 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -111,9 +111,10 @@ static void scsi_read_complete(void * opaque, int ret)
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
     int n;
 
-    r->req.aiocb = NULL;
-
-    bdrv_acct_done(s->bs, &r->acct);
+    if (r->req.aiocb != NULL) {
+        r->req.aiocb = NULL;
+        bdrv_acct_done(s->bs, &r->acct);
+    }
 
     if (ret) {
         if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_READ)) {
@@ -235,9 +236,10 @@ static void scsi_write_complete(void * opaque, int ret)
     uint32_t len;
     uint32_t n;
 
-    r->req.aiocb = NULL;
-
-    bdrv_acct_done(s->bs, &r->acct);
+    if (r->req.aiocb != NULL) {
+        r->req.aiocb = NULL;
+        bdrv_acct_done(s->bs, &r->acct);
+    }
 
     if (ret) {
         if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_WRITE)) {
commit 0a4ac106f780e2ddab27d6ab4e2880fa52a2c704
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Tue Sep 6 09:08:34 2011 +0200

    scsi: execute SYNCHRONIZE_CACHE asynchronously
    
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 3cc830f..5c652a2 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -129,6 +129,24 @@ static void scsi_read_complete(void * opaque, int ret)
     scsi_req_data(&r->req, r->iov.iov_len);
 }
 
+static void scsi_flush_complete(void * opaque, int ret)
+{
+    SCSIDiskReq *r = (SCSIDiskReq *)opaque;
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+
+    if (r->req.aiocb != NULL) {
+        r->req.aiocb = NULL;
+        bdrv_acct_done(s->bs, &r->acct);
+    }
+
+    if (ret < 0) {
+        if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_FLUSH)) {
+            return;
+        }
+    }
+
+    scsi_req_complete(&r->req, GOOD);
+}
 
 /* Read more data from scsi device into buffer.  */
 static void scsi_read_data(SCSIRequest *req)
@@ -792,7 +810,6 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
     uint64_t nb_sectors;
     int buflen = 0;
-    int ret;
 
     switch (req->cmd.buf[0]) {
     case TEST_UNIT_READY:
@@ -864,20 +881,6 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
         outbuf[7] = 0;
         buflen = 8;
         break;
-    case SYNCHRONIZE_CACHE:
-    {
-        BlockAcctCookie acct;
-
-        bdrv_acct_start(s->bs, &acct, 0, BDRV_ACCT_FLUSH);
-        ret = bdrv_flush(s->bs);
-        bdrv_acct_done(s->bs, &acct);
-        if (ret < 0) {
-            if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_FLUSH)) {
-                return -1;
-            }
-        }
-        break;
-    }
     case GET_CONFIGURATION:
         memset(outbuf, 0, 8);
         /* ??? This should probably return much more information.  For now
@@ -985,7 +988,6 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
     case START_STOP:
     case ALLOW_MEDIUM_REMOVAL:
     case READ_CAPACITY_10:
-    case SYNCHRONIZE_CACHE:
     case READ_TOC:
     case GET_CONFIGURATION:
     case SERVICE_ACTION_IN:
@@ -997,6 +999,13 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
 
         r->iov.iov_len = rc;
         break;
+    case SYNCHRONIZE_CACHE:
+        bdrv_acct_start(s->bs, &r->acct, 0, BDRV_ACCT_FLUSH);
+        r->req.aiocb = bdrv_aio_flush(s->bs, scsi_flush_complete, r);
+        if (r->req.aiocb == NULL) {
+            scsi_flush_complete(r, -EIO);
+        }
+        return 0;
     case READ_6:
     case READ_10:
     case READ_12:
commit bb45ded93115ad4303471c9a492579dc36716547
Author: Fam Zheng <famcool at gmail.com>
Date:   Fri Aug 12 23:19:34 2011 +0800

    VMDK: bugfix, opening vSphere 4 exported image
    
    The vSphere 4 exported image is streamOptimized extent, which is not
    quite correctly handled. Ignore rdgOffset when RGD flag bit not set.
    
    Signed-off-by: Fam Zheng <famcool at gmail.com>
    Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/vmdk.c b/block/vmdk.c
index 892b18e..6c8edfc 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -31,6 +31,7 @@
 #define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D')
 #define VMDK4_MAGIC (('K' << 24) | ('D' << 16) | ('M' << 8) | 'V')
 #define VMDK4_COMPRESSION_DEFLATE 1
+#define VMDK4_FLAG_RGD (1 << 1)
 #define VMDK4_FLAG_COMPRESS (1 << 16)
 #define VMDK4_FLAG_MARKER (1 << 17)
 
@@ -55,8 +56,8 @@ typedef struct {
     int64_t desc_offset;
     int64_t desc_size;
     int32_t num_gtes_per_gte;
-    int64_t rgd_offset;
     int64_t gd_offset;
+    int64_t rgd_offset;
     int64_t grain_offset;
     char filler[1];
     char check_bytes[4];
@@ -420,6 +421,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
     uint32_t l1_size, l1_entry_sectors;
     VMDK4Header header;
     VmdkExtent *extent;
+    int64_t l1_backup_offset = 0;
 
     ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header));
     if (ret < 0) {
@@ -435,10 +437,13 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
     }
     l1_size = (le64_to_cpu(header.capacity) + l1_entry_sectors - 1)
                 / l1_entry_sectors;
+    if (le32_to_cpu(header.flags) & VMDK4_FLAG_RGD) {
+        l1_backup_offset = le64_to_cpu(header.rgd_offset) << 9;
+    }
     extent = vmdk_add_extent(bs, file, false,
                           le64_to_cpu(header.capacity),
                           le64_to_cpu(header.gd_offset) << 9,
-                          le64_to_cpu(header.rgd_offset) << 9,
+                          l1_backup_offset,
                           l1_size,
                           le32_to_cpu(header.num_gtes_per_gte),
                           le64_to_cpu(header.granularity));
commit f16f509d17de295300404f94598b558ac5b8cfdd
Author: Fam Zheng <famcool at gmail.com>
Date:   Fri Aug 12 23:19:33 2011 +0800

    VMDK: bugfix, open Haiku vmdk image
    
    Haiku provides a specially formed vmdk image, which let qemu abort. It a
    combination of sparse header and flat data (i.e. with not l1/l2 table at
    all). The fix is turn to descriptor when sparse header is zero in field
    'capacity'.
    
    Signed-off-by: Fam Zheng <famcool at gmail.com>
    Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/vmdk.c b/block/vmdk.c
index 54f7441..892b18e 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -408,6 +408,9 @@ static int vmdk_open_vmdk3(BlockDriverState *bs,
     return ret;
 }
 
+static int vmdk_open_desc_file(BlockDriverState *bs, int flags,
+                               int64_t desc_offset);
+
 static int vmdk_open_vmdk4(BlockDriverState *bs,
                            BlockDriverState *file,
                            int flags)
@@ -422,6 +425,9 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
     if (ret < 0) {
         return ret;
     }
+    if (header.capacity == 0 && header.desc_offset) {
+        return vmdk_open_desc_file(bs, flags, header.desc_offset << 9);
+    }
     l1_entry_sectors = le32_to_cpu(header.num_gtes_per_gte)
                         * le64_to_cpu(header.granularity);
     if (l1_entry_sectors <= 0) {
@@ -559,7 +565,7 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
 
             extent = vmdk_add_extent(bs, extent_file, true, sectors,
                             0, 0, 0, 0, sectors);
-            extent->flat_start_offset = flat_offset;
+            extent->flat_start_offset = flat_offset << 9;
         } else if (!strcmp(type, "SPARSE")) {
             /* SPARSE extent */
             ret = vmdk_open_sparse(bs, extent_file, bs->open_flags);
@@ -582,14 +588,15 @@ next_line:
     return 0;
 }
 
-static int vmdk_open_desc_file(BlockDriverState *bs, int flags)
+static int vmdk_open_desc_file(BlockDriverState *bs, int flags,
+                               int64_t desc_offset)
 {
     int ret;
     char buf[2048];
     char ct[128];
     BDRVVmdkState *s = bs->opaque;
 
-    ret = bdrv_pread(bs->file, 0, buf, sizeof(buf));
+    ret = bdrv_pread(bs->file, desc_offset, buf, sizeof(buf));
     if (ret < 0) {
         return ret;
     }
@@ -635,7 +642,7 @@ static int vmdk_open(BlockDriverState *bs, int flags)
         s->parent_cid = vmdk_read_cid(bs, 1);
         return 0;
     } else {
-        return vmdk_open_desc_file(bs, flags);
+        return vmdk_open_desc_file(bs, flags, 0);
     }
 }
 
commit 6c031aac4d697d7acbfd5eaa73f47d494cee9937
Author: Fam Zheng <famcool at gmail.com>
Date:   Fri Aug 12 23:19:32 2011 +0800

    VMDK: creating streamOptimized subformat
    
    Creating streamOptimized subformat. Added subformat option
    'streamOptimized', to create a image with compression enabled and each
    cluster with a GrainMarker.
    
    Signed-off-by: Fam Zheng <famcool at gmail.com>
    Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/vmdk.c b/block/vmdk.c
index 36a761f..54f7441 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -1090,7 +1090,8 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
 }
 
 
-static int vmdk_create_extent(const char *filename, int64_t filesize, bool flat)
+static int vmdk_create_extent(const char *filename, int64_t filesize,
+                              bool flat, bool compress)
 {
     int ret, i;
     int fd = 0;
@@ -1114,7 +1115,9 @@ static int vmdk_create_extent(const char *filename, int64_t filesize, bool flat)
     magic = cpu_to_be32(VMDK4_MAGIC);
     memset(&header, 0, sizeof(header));
     header.version = 1;
-    header.flags = 3; /* ?? */
+    header.flags =
+        3 | (compress ? VMDK4_FLAG_COMPRESS | VMDK4_FLAG_MARKER : 0);
+    header.compressAlgorithm = compress ? VMDK4_COMPRESSION_DEFLATE : 0;
     header.capacity = filesize / 512;
     header.granularity = 128;
     header.num_gtes_per_gte = 512;
@@ -1144,6 +1147,7 @@ static int vmdk_create_extent(const char *filename, int64_t filesize, bool flat)
     header.rgd_offset = cpu_to_le64(header.rgd_offset);
     header.gd_offset = cpu_to_le64(header.gd_offset);
     header.grain_offset = cpu_to_le64(header.grain_offset);
+    header.compressAlgorithm = cpu_to_le16(header.compressAlgorithm);
 
     header.check_bytes[0] = 0xa;
     header.check_bytes[1] = 0x20;
@@ -1285,7 +1289,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
     const char *fmt = NULL;
     int flags = 0;
     int ret = 0;
-    bool flat, split;
+    bool flat, split, compress;
     char ext_desc_lines[BUF_SIZE] = "";
     char path[PATH_MAX], prefix[PATH_MAX], postfix[PATH_MAX];
     const int64_t split_size = 0x80000000;  /* VMDK has constant split size */
@@ -1334,7 +1338,8 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
     } else if (strcmp(fmt, "monolithicFlat") &&
                strcmp(fmt, "monolithicSparse") &&
                strcmp(fmt, "twoGbMaxExtentSparse") &&
-               strcmp(fmt, "twoGbMaxExtentFlat")) {
+               strcmp(fmt, "twoGbMaxExtentFlat") &&
+               strcmp(fmt, "streamOptimized")) {
         fprintf(stderr, "VMDK: Unknown subformat: %s\n", fmt);
         return -EINVAL;
     }
@@ -1342,6 +1347,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
               strcmp(fmt, "twoGbMaxExtentSparse"));
     flat = !(strcmp(fmt, "monolithicFlat") &&
              strcmp(fmt, "twoGbMaxExtentFlat"));
+    compress = !strcmp(fmt, "streamOptimized");
     if (flat) {
         desc_extent_line = "RW %lld FLAT \"%s\" 0\n";
     } else {
@@ -1396,7 +1402,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
         snprintf(ext_filename, sizeof(ext_filename), "%s%s",
                 path, desc_filename);
 
-        if (vmdk_create_extent(ext_filename, size, flat)) {
+        if (vmdk_create_extent(ext_filename, size, flat, compress)) {
             return -EINVAL;
         }
         filesize -= size;
@@ -1510,7 +1516,7 @@ static QEMUOptionParameter vmdk_create_options[] = {
         .type = OPT_STRING,
         .help =
             "VMDK flat extent format, can be one of "
-            "{monolithicSparse (default) | monolithicFlat | twoGbMaxExtentSparse | twoGbMaxExtentFlat} "
+            "{monolithicSparse (default) | monolithicFlat | twoGbMaxExtentSparse | twoGbMaxExtentFlat | streamOptimized} "
     },
     { NULL }
 };
commit 2b2c8c5dec6ba0834a70ac1533272ff244a0abe1
Author: Fam Zheng <famcool at gmail.com>
Date:   Fri Aug 12 23:19:31 2011 +0800

    VMDK: read/write compressed extent
    
    Add support for reading/writing compressed extent.
    
    Signed-off-by: Fam Zheng <famcool at gmail.com>
    Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/vmdk.c b/block/vmdk.c
index 8a96cfd..36a761f 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -775,10 +775,12 @@ static int get_cluster_offset(BlockDriverState *bs,
 
         /* Avoid the L2 tables update for the images that have snapshots. */
         *cluster_offset = bdrv_getlength(extent->file);
-        bdrv_truncate(
-            extent->file,
-            *cluster_offset + (extent->cluster_sectors << 9)
-        );
+        if (!extent->compressed) {
+            bdrv_truncate(
+                extent->file,
+                *cluster_offset + (extent->cluster_sectors << 9)
+            );
+        }
 
         *cluster_offset >>= 9;
         tmp = cpu_to_le32(*cluster_offset);
@@ -854,9 +856,28 @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset,
                             int nb_sectors, int64_t sector_num)
 {
     int ret;
+    VmdkGrainMarker *data = NULL;
+    uLongf buf_len;
     const uint8_t *write_buf = buf;
     int write_len = nb_sectors * 512;
 
+    if (extent->compressed) {
+        if (!extent->has_marker) {
+            ret = -EINVAL;
+            goto out;
+        }
+        buf_len = (extent->cluster_sectors << 9) * 2;
+        data = g_malloc(buf_len + sizeof(VmdkGrainMarker));
+        if (compress(data->data, &buf_len, buf, nb_sectors << 9) != Z_OK ||
+                buf_len == 0) {
+            ret = -EINVAL;
+            goto out;
+        }
+        data->lba = sector_num;
+        data->size = buf_len;
+        write_buf = (uint8_t *)data;
+        write_len = buf_len + sizeof(VmdkGrainMarker);
+    }
     ret = bdrv_pwrite(extent->file,
                         cluster_offset + offset_in_cluster,
                         write_buf,
@@ -867,6 +888,7 @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset,
     }
     ret = 0;
  out:
+    g_free(data);
     return ret;
 }
 
@@ -875,15 +897,65 @@ static int vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset,
                             int nb_sectors)
 {
     int ret;
+    int cluster_bytes, buf_bytes;
+    uint8_t *cluster_buf, *compressed_data;
+    uint8_t *uncomp_buf;
+    uint32_t data_len;
+    VmdkGrainMarker *marker;
+    uLongf buf_len;
 
+
+    if (!extent->compressed) {
+        ret = bdrv_pread(extent->file,
+                          cluster_offset + offset_in_cluster,
+                          buf, nb_sectors * 512);
+        if (ret == nb_sectors * 512) {
+            return 0;
+        } else {
+            return -EIO;
+        }
+    }
+    cluster_bytes = extent->cluster_sectors * 512;
+    /* Read two clusters in case GrainMarker + compressed data > one cluster */
+    buf_bytes = cluster_bytes * 2;
+    cluster_buf = g_malloc(buf_bytes);
+    uncomp_buf = g_malloc(cluster_bytes);
     ret = bdrv_pread(extent->file,
-                      cluster_offset + offset_in_cluster,
-                      buf, nb_sectors * 512);
-    if (ret == nb_sectors * 512) {
-        return 0;
-    } else {
-        return -EIO;
+                cluster_offset,
+                cluster_buf, buf_bytes);
+    if (ret < 0) {
+        goto out;
     }
+    compressed_data = cluster_buf;
+    buf_len = cluster_bytes;
+    data_len = cluster_bytes;
+    if (extent->has_marker) {
+        marker = (VmdkGrainMarker *)cluster_buf;
+        compressed_data = marker->data;
+        data_len = le32_to_cpu(marker->size);
+    }
+    if (!data_len || data_len > buf_bytes) {
+        ret = -EINVAL;
+        goto out;
+    }
+    ret = uncompress(uncomp_buf, &buf_len, compressed_data, data_len);
+    if (ret != Z_OK) {
+        ret = -EINVAL;
+        goto out;
+
+    }
+    if (offset_in_cluster < 0 ||
+            offset_in_cluster + nb_sectors * 512 > buf_len) {
+        ret = -EINVAL;
+        goto out;
+    }
+    memcpy(buf, uncomp_buf + offset_in_cluster, nb_sectors * 512);
+    ret = 0;
+
+ out:
+    g_free(uncomp_buf);
+    g_free(cluster_buf);
+    return ret;
 }
 
 static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
@@ -963,8 +1035,25 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
                                 bs,
                                 extent,
                                 &m_data,
-                                sector_num << 9, 1,
+                                sector_num << 9, !extent->compressed,
                                 &cluster_offset);
+        if (extent->compressed) {
+            if (ret == 0) {
+                /* Refuse write to allocated cluster for streamOptimized */
+                fprintf(stderr,
+                        "VMDK: can't write to allocated cluster"
+                        " for streamOptimized\n");
+                return -EIO;
+            } else {
+                /* allocate */
+                ret = get_cluster_offset(
+                                        bs,
+                                        extent,
+                                        &m_data,
+                                        sector_num << 9, 1,
+                                        &cluster_offset);
+            }
+        }
         if (ret) {
             return -EINVAL;
         }
commit 432bb170afd168304ddff111fa3881b2458a67ac
Author: Fam Zheng <famcool at gmail.com>
Date:   Fri Aug 12 23:19:30 2011 +0800

    VMDK: Opening compressed extent.
    
    Added flags field for compressed/streamOptimized extents, open and save
    image configuration.
    
    Signed-off-by: Fam Zheng <famcool at gmail.com>
    Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/vmdk.c b/block/vmdk.c
index 106fdbd..8a96cfd 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -26,9 +26,13 @@
 #include "qemu-common.h"
 #include "block_int.h"
 #include "module.h"
+#include "zlib.h"
 
 #define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D')
 #define VMDK4_MAGIC (('K' << 24) | ('D' << 16) | ('M' << 8) | 'V')
+#define VMDK4_COMPRESSION_DEFLATE 1
+#define VMDK4_FLAG_COMPRESS (1 << 16)
+#define VMDK4_FLAG_MARKER (1 << 17)
 
 typedef struct {
     uint32_t version;
@@ -56,6 +60,7 @@ typedef struct {
     int64_t grain_offset;
     char filler[1];
     char check_bytes[4];
+    uint16_t compressAlgorithm;
 } QEMU_PACKED VMDK4Header;
 
 #define L2_CACHE_SIZE 16
@@ -63,6 +68,8 @@ typedef struct {
 typedef struct VmdkExtent {
     BlockDriverState *file;
     bool flat;
+    bool compressed;
+    bool has_marker;
     int64_t sectors;
     int64_t end_sector;
     int64_t flat_start_offset;
@@ -98,6 +105,12 @@ typedef struct VmdkMetaData {
     int valid;
 } VmdkMetaData;
 
+typedef struct VmdkGrainMarker {
+    uint64_t lba;
+    uint32_t size;
+    uint8_t  data[0];
+} VmdkGrainMarker;
+
 static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
 {
     uint32_t magic;
@@ -423,6 +436,9 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
                           l1_size,
                           le32_to_cpu(header.num_gtes_per_gte),
                           le64_to_cpu(header.granularity));
+    extent->compressed =
+        le16_to_cpu(header.compressAlgorithm) == VMDK4_COMPRESSION_DEFLATE;
+    extent->has_marker = le32_to_cpu(header.flags) & VMDK4_FLAG_MARKER;
     ret = vmdk_init_tables(bs, extent);
     if (ret) {
         /* free extent allocated by vmdk_add_extent */
commit dd3f6ee211d248bc8cf27cc839e94dfa42348cd9
Author: Fam Zheng <famcool at gmail.com>
Date:   Fri Aug 12 23:19:29 2011 +0800

    VMDK: separate vmdk_read_extent/vmdk_write_extent
    
    Factor out read/write extent code, since there will be more things to
    take care of once reading/writing compressed clusters is introduced.
    
    Signed-off-by: Fam Zheng <famcool at gmail.com>
    Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/vmdk.c b/block/vmdk.c
index 49473f6..106fdbd 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -833,6 +833,43 @@ static int vmdk_is_allocated(BlockDriverState *bs, int64_t sector_num,
     return ret;
 }
 
+static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset,
+                            int64_t offset_in_cluster, const uint8_t *buf,
+                            int nb_sectors, int64_t sector_num)
+{
+    int ret;
+    const uint8_t *write_buf = buf;
+    int write_len = nb_sectors * 512;
+
+    ret = bdrv_pwrite(extent->file,
+                        cluster_offset + offset_in_cluster,
+                        write_buf,
+                        write_len);
+    if (ret != write_len) {
+        ret = ret < 0 ? ret : -EIO;
+        goto out;
+    }
+    ret = 0;
+ out:
+    return ret;
+}
+
+static int vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset,
+                            int64_t offset_in_cluster, uint8_t *buf,
+                            int nb_sectors)
+{
+    int ret;
+
+    ret = bdrv_pread(extent->file,
+                      cluster_offset + offset_in_cluster,
+                      buf, nb_sectors * 512);
+    if (ret == nb_sectors * 512) {
+        return 0;
+    } else {
+        return -EIO;
+    }
+}
+
 static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
                     uint8_t *buf, int nb_sectors)
 {
@@ -869,10 +906,10 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
                 memset(buf, 0, 512 * n);
             }
         } else {
-            ret = bdrv_pread(extent->file,
-                            cluster_offset + index_in_cluster * 512,
-                            buf, n * 512);
-            if (ret < 0) {
+            ret = vmdk_read_extent(extent,
+                            cluster_offset, index_in_cluster * 512,
+                            buf, n);
+            if (ret) {
                 return ret;
             }
         }
@@ -921,11 +958,10 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
             n = nb_sectors;
         }
 
-        ret = bdrv_pwrite(extent->file,
-                        cluster_offset + index_in_cluster * 512,
-                        buf,
-                        n * 512);
-        if (ret < 0) {
+        ret = vmdk_write_extent(extent,
+                        cluster_offset, index_in_cluster * 512,
+                        buf, n, sector_num);
+        if (ret) {
             return ret;
         }
         if (m_data.valid) {
commit 86c6b429bf0df583a09fc8a3286b2467d6241e7e
Author: Fam Zheng <famcool at gmail.com>
Date:   Fri Aug 12 23:19:28 2011 +0800

    VMDK: add twoGbMaxExtentSparse support
    
    Add twoGbMaxExtentSparse support. Introduce vmdk_free_last_extent.
    
    Signed-off-by: Fam Zheng <famcool at gmail.com>
    Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/vmdk.c b/block/vmdk.c
index 1e9e8d0..49473f6 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -174,6 +174,17 @@ static void vmdk_free_extents(BlockDriverState *bs)
     g_free(s->extents);
 }
 
+static void vmdk_free_last_extent(BlockDriverState *bs)
+{
+    BDRVVmdkState *s = bs->opaque;
+
+    if (s->num_extents == 0) {
+        return;
+    }
+    s->num_extents--;
+    s->extents = g_realloc(s->extents, s->num_extents * sizeof(VmdkExtent));
+}
+
 static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
 {
     char desc[DESC_SIZE];
@@ -357,18 +368,18 @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent)
     return ret;
 }
 
-static int vmdk_open_vmdk3(BlockDriverState *bs, int flags)
+static int vmdk_open_vmdk3(BlockDriverState *bs,
+                           BlockDriverState *file,
+                           int flags)
 {
     int ret;
     uint32_t magic;
     VMDK3Header header;
-    BDRVVmdkState *s = bs->opaque;
     VmdkExtent *extent;
 
-    s->desc_offset = 0x200;
-    ret = bdrv_pread(bs->file, sizeof(magic), &header, sizeof(header));
+    ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header));
     if (ret < 0) {
-        goto fail;
+        return ret;
     }
     extent = vmdk_add_extent(bs,
                              bs->file, false,
@@ -378,58 +389,45 @@ static int vmdk_open_vmdk3(BlockDriverState *bs, int flags)
                              le32_to_cpu(header.granularity));
     ret = vmdk_init_tables(bs, extent);
     if (ret) {
-        /* vmdk_init_tables cleans up on fail, so only free allocation of
-         * vmdk_add_extent here. */
-        goto fail;
+        /* free extent allocated by vmdk_add_extent */
+        vmdk_free_last_extent(bs);
     }
-    return 0;
- fail:
-    vmdk_free_extents(bs);
     return ret;
 }
 
-static int vmdk_open_vmdk4(BlockDriverState *bs, int flags)
+static int vmdk_open_vmdk4(BlockDriverState *bs,
+                           BlockDriverState *file,
+                           int flags)
 {
     int ret;
     uint32_t magic;
     uint32_t l1_size, l1_entry_sectors;
     VMDK4Header header;
-    BDRVVmdkState *s = bs->opaque;
     VmdkExtent *extent;
 
-    s->desc_offset = 0x200;
-    ret = bdrv_pread(bs->file, sizeof(magic), &header, sizeof(header));
+    ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header));
     if (ret < 0) {
-        goto fail;
+        return ret;
     }
     l1_entry_sectors = le32_to_cpu(header.num_gtes_per_gte)
                         * le64_to_cpu(header.granularity);
+    if (l1_entry_sectors <= 0) {
+        return -EINVAL;
+    }
     l1_size = (le64_to_cpu(header.capacity) + l1_entry_sectors - 1)
                 / l1_entry_sectors;
-    extent = vmdk_add_extent(bs, bs->file, false,
+    extent = vmdk_add_extent(bs, file, false,
                           le64_to_cpu(header.capacity),
                           le64_to_cpu(header.gd_offset) << 9,
                           le64_to_cpu(header.rgd_offset) << 9,
                           l1_size,
                           le32_to_cpu(header.num_gtes_per_gte),
                           le64_to_cpu(header.granularity));
-    if (extent->l1_entry_sectors <= 0) {
-        ret = -EINVAL;
-        goto fail;
-    }
-    /* try to open parent images, if exist */
-    ret = vmdk_parent_open(bs);
-    if (ret) {
-        goto fail;
-    }
-    s->parent_cid = vmdk_read_cid(bs, 1);
     ret = vmdk_init_tables(bs, extent);
     if (ret) {
-        goto fail;
+        /* free extent allocated by vmdk_add_extent */
+        vmdk_free_last_extent(bs);
     }
-    return 0;
- fail:
-    vmdk_free_extents(bs);
     return ret;
 }
 
@@ -460,6 +458,31 @@ static int vmdk_parse_description(const char *desc, const char *opt_name,
     return 0;
 }
 
+/* Open an extent file and append to bs array */
+static int vmdk_open_sparse(BlockDriverState *bs,
+                            BlockDriverState *file,
+                            int flags)
+{
+    uint32_t magic;
+
+    if (bdrv_pread(file, 0, &magic, sizeof(magic)) != sizeof(magic)) {
+        return -EIO;
+    }
+
+    magic = be32_to_cpu(magic);
+    switch (magic) {
+        case VMDK3_MAGIC:
+            return vmdk_open_vmdk3(bs, file, flags);
+            break;
+        case VMDK4_MAGIC:
+            return vmdk_open_vmdk4(bs, file, flags);
+            break;
+        default:
+            return -EINVAL;
+            break;
+    }
+}
+
 static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
         const char *desc_file_path)
 {
@@ -470,6 +493,8 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
     const char *p = desc;
     int64_t sectors = 0;
     int64_t flat_offset;
+    char extent_path[PATH_MAX];
+    BlockDriverState *extent_file;
 
     while (*p) {
         /* parse extent line:
@@ -504,24 +529,29 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
             goto next_line;
         }
 
+        path_combine(extent_path, sizeof(extent_path),
+                desc_file_path, fname);
+        ret = bdrv_file_open(&extent_file, extent_path, bs->open_flags);
+        if (ret) {
+            return ret;
+        }
+
         /* save to extents array */
         if (!strcmp(type, "FLAT")) {
             /* FLAT extent */
-            char extent_path[PATH_MAX];
-            BlockDriverState *extent_file;
             VmdkExtent *extent;
 
-            path_combine(extent_path, sizeof(extent_path),
-                    desc_file_path, fname);
-            ret = bdrv_file_open(&extent_file, extent_path, bs->open_flags);
-            if (ret) {
-                return ret;
-            }
             extent = vmdk_add_extent(bs, extent_file, true, sectors,
                             0, 0, 0, 0, sectors);
             extent->flat_start_offset = flat_offset;
+        } else if (!strcmp(type, "SPARSE")) {
+            /* SPARSE extent */
+            ret = vmdk_open_sparse(bs, extent_file, bs->open_flags);
+            if (ret) {
+                bdrv_delete(extent_file);
+                return ret;
+            }
         } else {
-            /* SPARSE extent, not supported for now */
             fprintf(stderr,
                 "VMDK: Not supported extent type \"%s\""".\n", type);
             return -ENOTSUP;
@@ -552,6 +582,7 @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags)
         return -EINVAL;
     }
     if (strcmp(ct, "monolithicFlat") &&
+        strcmp(ct, "twoGbMaxExtentSparse") &&
         strcmp(ct, "twoGbMaxExtentFlat")) {
         fprintf(stderr,
                 "VMDK: Not supported image type \"%s\""".\n", ct);
@@ -574,17 +605,19 @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags)
 
 static int vmdk_open(BlockDriverState *bs, int flags)
 {
-    uint32_t magic;
-
-    if (bdrv_pread(bs->file, 0, &magic, sizeof(magic)) != sizeof(magic)) {
-        return -EIO;
-    }
+    int ret;
+    BDRVVmdkState *s = bs->opaque;
 
-    magic = be32_to_cpu(magic);
-    if (magic == VMDK3_MAGIC) {
-        return vmdk_open_vmdk3(bs, flags);
-    } else if (magic == VMDK4_MAGIC) {
-        return vmdk_open_vmdk4(bs, flags);
+    if (vmdk_open_sparse(bs, bs->file, flags) == 0) {
+        s->desc_offset = 0x200;
+        /* try to open parent images, if exist */
+        ret = vmdk_parent_open(bs);
+        if (ret) {
+            vmdk_free_extents(bs);
+            return ret;
+        }
+        s->parent_cid = vmdk_read_cid(bs, 1);
+        return 0;
     } else {
         return vmdk_open_desc_file(bs, flags);
     }
commit 6398de5160e3271b720190b7d6801aecffc91978
Author: Fam Zheng <famcool at gmail.com>
Date:   Fri Aug 12 23:19:27 2011 +0800

    VMDK: enable twoGbMaxExtentFlat
    
    Enable the createType 'twoGbMaxExtentFlat'. The supporting code is
    already in.
    
    Signed-off-by: Fam Zheng <famcool at gmail.com>
    Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/vmdk.c b/block/vmdk.c
index 5f673e9..1e9e8d0 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -551,7 +551,8 @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags)
     if (vmdk_parse_description(buf, "createType", ct, sizeof(ct))) {
         return -EINVAL;
     }
-    if (strcmp(ct, "monolithicFlat")) {
+    if (strcmp(ct, "monolithicFlat") &&
+        strcmp(ct, "twoGbMaxExtentFlat")) {
         fprintf(stderr,
                 "VMDK: Not supported image type \"%s\""".\n", ct);
         return -ENOTSUP;
@@ -672,6 +673,7 @@ static int get_cluster_offset(BlockDriverState *bs,
         return 0;
     }
 
+    offset -= (extent->end_sector - extent->sectors) * SECTOR_SIZE;
     l1_index = (offset >> 9) / extent->l1_entry_sectors;
     if (l1_index >= extent->l1_size) {
         return -1;
commit ba5b7ad4495a9788d0af67133186bbc7a553008f
Author: Markus Armbruster <armbru at redhat.com>
Date:   Wed Aug 3 15:08:19 2011 +0200

    block: Declare qemu_blockalign() in block.h, not block_int.h
    
    Device models should be able to use it without an unclean include of
    block_int.h.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.h b/block.h
index 7e3f587..8ec409f 100644
--- a/block.h
+++ b/block.h
@@ -258,6 +258,8 @@ 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);
 
+void *qemu_blockalign(BlockDriverState *bs, size_t size);
+
 #define BDRV_SECTORS_PER_DIRTY_CHUNK 2048
 
 void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable);
diff --git a/block_int.h b/block_int.h
index 539b4ed..5dc0074 100644
--- a/block_int.h
+++ b/block_int.h
@@ -224,8 +224,6 @@ void *qemu_aio_get(AIOPool *pool, BlockDriverState *bs,
                    BlockDriverCompletionFunc *cb, void *opaque);
 void qemu_aio_release(void *p);
 
-void *qemu_blockalign(BlockDriverState *bs, size_t size);
-
 #ifdef _WIN32
 int is_windows_drive(const char *filename);
 #endif
diff --git a/hw/sd.c b/hw/sd.c
index 45e95f9..1af62b2 100644
--- a/hw/sd.c
+++ b/hw/sd.c
@@ -31,7 +31,6 @@
 
 #include "hw.h"
 #include "block.h"
-#include "block_int.h"
 #include "sd.h"
 
 //#define DEBUG_SD 1
commit 124386cc756f6a7975562d652d0e98a379292138
Author: Markus Armbruster <armbru at redhat.com>
Date:   Wed Aug 3 15:08:13 2011 +0200

    spitz tosa: Simplify "drive is suitable for microdrive" test
    
    We try the drive defined with -drive if=ide,index=0 (or equivalent
    sugar).  We use it only if (dinfo && bdrv_is_inserted(dinfo->bdrv) &&
    !bdrv_is_removable(dinfo->bdrv)).  This is a convoluted way to test
    for "drive media can't be removed".
    
    The only way to create such a drive with -drive if=ide is media=cdrom.
    And that sets dinfo->media_cd, so just test that.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/spitz.c b/hw/spitz.c
index c05b5f7..0adae59 100644
--- a/hw/spitz.c
+++ b/hw/spitz.c
@@ -708,17 +708,13 @@ static void spitz_ssp_attach(PXA2xxState *cpu)
 static void spitz_microdrive_attach(PXA2xxState *cpu, int slot)
 {
     PCMCIACardState *md;
-    BlockDriverState *bs;
     DriveInfo *dinfo;
 
     dinfo = drive_get(IF_IDE, 0, 0);
-    if (!dinfo)
+    if (!dinfo || dinfo->media_cd)
         return;
-    bs = dinfo->bdrv;
-    if (bdrv_is_inserted(bs) && !bdrv_is_removable(bs)) {
-        md = dscm1xxxx_init(dinfo);
-        pxa2xx_pcmcia_attach(cpu->pcmcia[slot], md);
-    }
+    md = dscm1xxxx_init(dinfo);
+    pxa2xx_pcmcia_attach(cpu->pcmcia[slot], md);
 }
 
 /* Wm8750 and Max7310 on I2C */
diff --git a/hw/tosa.c b/hw/tosa.c
index a7967a2..7b407f4 100644
--- a/hw/tosa.c
+++ b/hw/tosa.c
@@ -51,17 +51,13 @@
 static void tosa_microdrive_attach(PXA2xxState *cpu)
 {
     PCMCIACardState *md;
-    BlockDriverState *bs;
     DriveInfo *dinfo;
 
     dinfo = drive_get(IF_IDE, 0, 0);
-    if (!dinfo)
+    if (!dinfo || dinfo->media_cd)
         return;
-    bs = dinfo->bdrv;
-    if (bdrv_is_inserted(bs) && !bdrv_is_removable(bs)) {
-        md = dscm1xxxx_init(dinfo);
-        pxa2xx_pcmcia_attach(cpu->pcmcia[0], md);
-    }
+    md = dscm1xxxx_init(dinfo);
+    pxa2xx_pcmcia_attach(cpu->pcmcia[0], md);
 }
 
 static void tosa_out_switch(void *opaque, int line, int level)
commit f9e8fda4796c0e8aebfc1e7ddf9bed6865adab02
Author: Markus Armbruster <armbru at redhat.com>
Date:   Wed Aug 3 15:08:12 2011 +0200

    xen: Clean up pci_piix3_xen_ide_unplug()'s test for "not a CD"
    
    pci_piix3_xen_ide_unplug() unplugs only disks, not CD-ROMs.  It peeks
    into the DriveInfo's BlockDriverState to distinguish between the two.
    Unclean; use DriveInfo member media_cd, like xen_config_dev_blk().
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index b9cdcd6..88d3181 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -27,7 +27,6 @@
 #include <hw/pci.h>
 #include <hw/isa.h>
 #include "block.h"
-#include "block_int.h"
 #include "sysemu.h"
 #include "dma.h"
 
@@ -176,7 +175,7 @@ static int pci_piix3_xen_ide_unplug(DeviceState *dev)
 
     for (; i < 3; i++) {
         di = drive_get_by_index(IF_IDE, i);
-        if (di != NULL && di->bdrv != NULL && !di->bdrv->removable) {
+        if (di != NULL && !di->media_cd) {
             DeviceState *ds = bdrv_get_attached_dev(di->bdrv);
             if (ds) {
                 bdrv_detach_dev(di->bdrv, ds);
commit 07b70bfbb3f3aea9ce7a3a1da78cbfa8ae6bbce6
Author: Markus Armbruster <armbru at redhat.com>
Date:   Wed Aug 3 15:08:11 2011 +0200

    savevm: Include writable devices with removable media
    
    savevm and loadvm silently ignore block devices with removable media,
    such as floppies and SD cards.  Rolling back a VM to a previous
    checkpoint will *not* roll back writes to block devices with removable
    media.
    
    Moreover, bdrv_is_removable() is a confused mess, and wrong in at
    least one case: it considers "-drive if=xen,media=cdrom -M xenpv"
    removable.  It'll be cleaned up later in this series.
    
    Read-only block devices are also ignored, but that's okay.
    
    Fix by ignoring only read-only block devices and empty block devices.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index 487a6a9..a8c789a 100644
--- a/block.c
+++ b/block.c
@@ -2097,7 +2097,7 @@ void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event)
 int bdrv_can_snapshot(BlockDriverState *bs)
 {
     BlockDriver *drv = bs->drv;
-    if (!drv || bdrv_is_removable(bs) || bdrv_is_read_only(bs)) {
+    if (!drv || !bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) {
         return 0;
     }
 
diff --git a/savevm.c b/savevm.c
index b06308b..1feaa70 100644
--- a/savevm.c
+++ b/savevm.c
@@ -1914,7 +1914,7 @@ void do_savevm(Monitor *mon, const QDict *qdict)
     bs = NULL;
     while ((bs = bdrv_next(bs))) {
 
-        if (bdrv_is_removable(bs) || bdrv_is_read_only(bs)) {
+        if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) {
             continue;
         }
 
@@ -2034,7 +2034,7 @@ int load_vmstate(const char *name)
     bs = NULL;
     while ((bs = bdrv_next(bs))) {
 
-        if (bdrv_is_removable(bs) || bdrv_is_read_only(bs)) {
+        if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) {
             continue;
         }
 
commit c602a489f9685407d93beab3b121408811d20ce4
Author: Markus Armbruster <armbru at redhat.com>
Date:   Wed Aug 3 15:08:10 2011 +0200

    block: Clean up bdrv_flush_all()
    
    Change (!bdrv_is_removable(bs) || bdrv_is_inserted(bs)) to just
    bdrv_is_inserted().  Rationale:
    
        The value of bdrv_is_removable(bs) matters only when
        bdrv_is_inserted(bs) is false.
    
        bdrv_is_inserted(bs) is true when bs is open (bs->drv != NULL) and
        not an empty host drive (CD-ROM or floppy).
    
        Therefore, bdrv_is_removable(bs) matters only when:
    
        1. bs is not open
           old: may call bdrv_flush(bs), which does nothing
           new: won't call
    
        2. bs is an empty host drive
           old: may call bdrv_flush(bs), which calls driver method
                raw_flush(), which calls fdatasync() or equivalent, which
                can't do anything useful while the drive is empty
           new: won't call
    
    Result is bs->drv && !bdrv_is_read_only(bs) && bdrv_is_inserted(bs).
    bdrv_is_inserted(bs) implies bs->drv.  Drop the redundant test.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index 2158f83..487a6a9 100644
--- a/block.c
+++ b/block.c
@@ -1753,8 +1753,7 @@ void bdrv_flush_all(void)
     BlockDriverState *bs;
 
     QTAILQ_FOREACH(bs, &bdrv_states, list) {
-        if (bs->drv && !bdrv_is_read_only(bs) &&
-            (!bdrv_is_removable(bs) || bdrv_is_inserted(bs))) {
+        if (!bdrv_is_read_only(bs) && bdrv_is_inserted(bs)) {
             bdrv_flush(bs);
         }
     }
commit 18d90055293adc4937c91fb7b87743b1994d8bc5
Author: Markus Armbruster <armbru at redhat.com>
Date:   Wed Aug 3 15:08:09 2011 +0200

    fdc: Make media change detection more robust
    
    fdctrl_change_cb() gets called on a virtual media change via monitor.
    It would be nice if host device block drivers called it on physical
    media change, but they don't.
    
    bdrv_media_changed() lets you poll for media change, but it returns
    "don't know" except with block driver "host_floppy".
    
    FDrive member media_changed gets set on device initialization and by
    fdctrl_change_cb(), and cleared by fdctrl_media_changed().  Thus, it's
    set on first entry to fdctrl_media_changed() since device
    initialization or virtual media change.
    
    fdctrl_media_changed() ignores media_changed unless
    bdrv_media_changed() returns "don't know".  If we change media via
    monitor (setting media_changed), and the new media's block driver
    returns 0, we lose.  Fortunately, "host_floppy" always returns 1 on
    first call.  Brittle.  Clean it up not to rely on it.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/fdc.c b/hw/fdc.c
index 4f4c621..1d44bbd 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -898,11 +898,15 @@ static int fdctrl_media_changed(FDrive *drv)
 
     if (!drv->bs)
         return 0;
-    ret = bdrv_media_changed(drv->bs);
-    if (ret < 0) {
-        ret = drv->media_changed;
+    if (drv->media_changed) {
+        drv->media_changed = 0;
+        ret = 1;
+    } else {
+        ret = bdrv_media_changed(drv->bs);
+        if (ret < 0) {
+            ret = 0;            /* we don't know, assume no */
+        }
     }
-    drv->media_changed = 0;
     if (ret) {
         fd_revalidate(drv);
     }
commit 8e49ca46249481588c881918d5bd023e16209095
Author: Markus Armbruster <armbru at redhat.com>
Date:   Wed Aug 3 15:08:08 2011 +0200

    block: Leave tracking media change to device models
    
    hw/fdc.c is the only one that cares.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index 0aba1bf..2158f83 100644
--- a/block.c
+++ b/block.c
@@ -689,7 +689,6 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
     }
 
     if (!bdrv_key_required(bs)) {
-        bs->media_changed = 1;
         bdrv_dev_change_media_cb(bs);
     }
 
@@ -726,7 +725,6 @@ void bdrv_close(BlockDriverState *bs)
             bdrv_close(bs->file);
         }
 
-        bs->media_changed = 1;
         bdrv_dev_change_media_cb(bs);
     }
 }
@@ -1665,7 +1663,6 @@ int bdrv_set_key(BlockDriverState *bs, const char *key)
     } else if (!bs->valid_key) {
         bs->valid_key = 1;
         /* call the change callback now, we skipped it on open */
-        bs->media_changed = 1;
         bdrv_dev_change_media_cb(bs);
     }
     return ret;
@@ -3040,22 +3037,17 @@ int bdrv_is_inserted(BlockDriverState *bs)
 }
 
 /**
- * Return TRUE if the media changed since the last call to this
- * function. It is currently only used for floppy disks
+ * Return whether the media changed since the last call to this
+ * function, or -ENOTSUP if we don't know.  Most drivers don't know.
  */
 int bdrv_media_changed(BlockDriverState *bs)
 {
     BlockDriver *drv = bs->drv;
-    int ret;
 
-    if (!drv || !drv->bdrv_media_changed)
-        ret = -ENOTSUP;
-    else
-        ret = drv->bdrv_media_changed(bs);
-    if (ret == -ENOTSUP)
-        ret = bs->media_changed;
-    bs->media_changed = 0;
-    return ret;
+    if (drv && drv->bdrv_media_changed) {
+        return drv->bdrv_media_changed(bs);
+    }
+    return -ENOTSUP;
 }
 
 /**
diff --git a/block_int.h b/block_int.h
index 19ae75e..539b4ed 100644
--- a/block_int.h
+++ b/block_int.h
@@ -175,7 +175,6 @@ struct BlockDriverState {
                                 this file image */
     char backing_format[16]; /* if non-zero and backing_file exists */
     int is_temporary;
-    int media_changed;
 
     BlockDriverState *backing_hd;
     BlockDriverState *file;
diff --git a/hw/fdc.c b/hw/fdc.c
index 580b657..4f4c621 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -535,30 +535,11 @@ static CPUWriteMemoryFunc * const fdctrl_mem_write_strict[3] = {
     NULL,
 };
 
-static void fdrive_media_changed_pre_save(void *opaque)
-{
-    FDrive *drive = opaque;
-
-    drive->media_changed = drive->bs->media_changed;
-}
-
-static int fdrive_media_changed_post_load(void *opaque, int version_id)
-{
-    FDrive *drive = opaque;
-
-    if (drive->bs != NULL) {
-        drive->bs->media_changed = drive->media_changed;
-    }
-
-    /* User ejected the floppy when drive->bs == NULL */
-    return 0;
-}
-
 static bool fdrive_media_changed_needed(void *opaque)
 {
     FDrive *drive = opaque;
 
-    return (drive->bs != NULL && drive->bs->media_changed != 1);
+    return (drive->bs != NULL && drive->media_changed != 1);
 }
 
 static const VMStateDescription vmstate_fdrive_media_changed = {
@@ -566,8 +547,6 @@ static const VMStateDescription vmstate_fdrive_media_changed = {
     .version_id = 1,
     .minimum_version_id = 1,
     .minimum_version_id_old = 1,
-    .pre_save = fdrive_media_changed_pre_save,
-    .post_load = fdrive_media_changed_post_load,
     .fields      = (VMStateField[]) {
         VMSTATE_UINT8(media_changed, FDrive),
         VMSTATE_END_OF_LIST()
@@ -920,6 +899,10 @@ static int fdctrl_media_changed(FDrive *drv)
     if (!drv->bs)
         return 0;
     ret = bdrv_media_changed(drv->bs);
+    if (ret < 0) {
+        ret = drv->media_changed;
+    }
+    drv->media_changed = 0;
     if (ret) {
         fd_revalidate(drv);
     }
@@ -1791,6 +1774,17 @@ static void fdctrl_result_timer(void *opaque)
     fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
 }
 
+static void fdctrl_change_cb(void *opaque)
+{
+    FDrive *drive = opaque;
+
+    drive->media_changed = 1;
+}
+
+static const BlockDevOps fdctrl_block_ops = {
+    .change_media_cb = fdctrl_change_cb,
+};
+
 /* Init functions */
 static int fdctrl_connect_drives(FDCtrl *fdctrl)
 {
@@ -1814,7 +1808,9 @@ static int fdctrl_connect_drives(FDCtrl *fdctrl)
         fd_init(drive);
         fd_revalidate(drive);
         if (drive->bs) {
+            drive->media_changed = 1;
             bdrv_set_removable(drive->bs, 1);
+            bdrv_set_dev_ops(drive->bs, &fdctrl_block_ops, drive);
         }
     }
     return 0;
commit be32f75f4dfb4e7dead9fb9cfb8a7195b1e25ebf
Author: Markus Armbruster <armbru at redhat.com>
Date:   Wed Aug 3 15:08:07 2011 +0200

    block/raw: Fix to forward method bdrv_media_changed()
    
    Block driver "raw" forwards most methods to the underlying block
    driver.  However, it doesn't implement method bdrv_media_changed().
    Makes bdrv_media_changed() always return -ENOTSUP.
    
    I believe -fda /dev/fd0 gives you raw over host_floppy, and disk
    change detection (fdc register 7 bit 7) is broken.  Testing my theory
    requires a computer museum, though.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/raw.c b/block/raw.c
index 555db4f..f197479 100644
--- a/block/raw.c
+++ b/block/raw.c
@@ -75,6 +75,11 @@ static int raw_is_inserted(BlockDriverState *bs)
     return bdrv_is_inserted(bs->file);
 }
 
+static int raw_media_changed(BlockDriverState *bs)
+{
+    return bdrv_media_changed(bs->file);
+}
+
 static void raw_eject(BlockDriverState *bs, int eject_flag)
 {
     bdrv_eject(bs->file, eject_flag);
@@ -137,8 +142,10 @@ static BlockDriver bdrv_raw = {
     .bdrv_discard       = raw_discard,
 
     .bdrv_is_inserted   = raw_is_inserted,
+    .bdrv_media_changed = raw_media_changed,
     .bdrv_eject         = raw_eject,
     .bdrv_set_locked    = raw_set_locked,
+
     .bdrv_ioctl         = raw_ioctl,
     .bdrv_aio_ioctl     = raw_aio_ioctl,
 
commit 656fbeff92f402d6dd21a048f5e9028a32fcfd40
Author: Markus Armbruster <armbru at redhat.com>
Date:   Wed Aug 3 15:08:04 2011 +0200

    ide: Give vmstate structs internal linkage where possible
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/ide/core.c b/hw/ide/core.c
index ff59a45..1806e00 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -2010,7 +2010,7 @@ static bool ide_error_needed(void *opaque)
 }
 
 /* Fields for GET_EVENT_STATUS_NOTIFICATION ATAPI command */
-const VMStateDescription vmstate_ide_atapi_gesn_state = {
+static const VMStateDescription vmstate_ide_atapi_gesn_state = {
     .name ="ide_drive/atapi/gesn_state",
     .version_id = 1,
     .minimum_version_id = 1,
@@ -2022,7 +2022,7 @@ const VMStateDescription vmstate_ide_atapi_gesn_state = {
     }
 };
 
-const VMStateDescription vmstate_ide_drive_pio_state = {
+static const VMStateDescription vmstate_ide_drive_pio_state = {
     .name = "ide_drive/pio_state",
     .version_id = 1,
     .minimum_version_id = 1,
@@ -2084,7 +2084,7 @@ const VMStateDescription vmstate_ide_drive = {
     }
 };
 
-const VMStateDescription vmstate_ide_error_status = {
+static const VMStateDescription vmstate_ide_error_status = {
     .name ="ide_bus/error",
     .version_id = 1,
     .minimum_version_id = 1,
commit 814839c00b717743128f06e875a7f664e872c167
Author: Markus Armbruster <armbru at redhat.com>
Date:   Wed Aug 3 15:07:44 2011 +0200

    ide: Clean up case label indentation in ide_exec_cmd()
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/ide/core.c b/hw/ide/core.c
index d1cbfe7..ff59a45 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -979,7 +979,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
         s->status = READY_STAT | SEEK_STAT;
         ide_set_irq(s->bus);
         break;
-	case WIN_READ_EXT:
+    case WIN_READ_EXT:
 	lba48 = 1;
     case WIN_READ:
     case WIN_READ_ONCE:
@@ -989,7 +989,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
         s->req_nb_sectors = 1;
         ide_sector_read(s);
         break;
-	case WIN_WRITE_EXT:
+    case WIN_WRITE_EXT:
 	lba48 = 1;
     case WIN_WRITE:
     case WIN_WRITE_ONCE:
@@ -1002,7 +1002,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
         ide_transfer_start(s, s->io_buffer, 512, ide_sector_write);
         s->media_changed = 1;
         break;
-	case WIN_MULTREAD_EXT:
+    case WIN_MULTREAD_EXT:
 	lba48 = 1;
     case WIN_MULTREAD:
         if (!s->mult_sectors)
@@ -1027,7 +1027,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
         ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_write);
         s->media_changed = 1;
         break;
-	case WIN_READDMA_EXT:
+    case WIN_READDMA_EXT:
 	lba48 = 1;
     case WIN_READDMA:
     case WIN_READDMA_ONCE:
@@ -1036,7 +1036,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
 	ide_cmd_lba48_transform(s, lba48);
         ide_sector_start_dma(s, IDE_DMA_READ);
         break;
-	case WIN_WRITEDMA_EXT:
+    case WIN_WRITEDMA_EXT:
 	lba48 = 1;
     case WIN_WRITEDMA:
     case WIN_WRITEDMA_ONCE:
@@ -1261,7 +1261,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
         ide_set_irq(s->bus);
         break;
 
-	case WIN_SMART:
+    case WIN_SMART:
 	if (s->drive_kind == IDE_CD)
 		goto abort_cmd;
 	if (s->hcyl != 0xc2 || s->lcyl != 0x4f)
commit 1d4316d38517b0961d2c4474978ce7bde3176741
Author: Markus Armbruster <armbru at redhat.com>
Date:   Wed Aug 3 15:07:43 2011 +0200

    ide: Update command code definitions as per ACS-2 Table B.2
    
    Drop WIN_SRST, it has the same value as WIN_DEVICE_RESET.
    
    Drop unused WIN_RESTORE, it has the same value as WIN_RECAL.
    
    Drop codes that are not implemented and long obsolete: WIN_READ_LONG,
    WIN_READ_LONG_ONCE, WIN_WRITE_LONG, WIN_WRITE_LONG_ONCE, WIN_FORMAT
    (all obsolete since ATA4), WIN_ACKMEDIACHANGE, WIN_POSTBOOT,
    WIN_PREBOOT (obsolete since ATA3), WIN_WRITE_SAME (obsolete since
    ATA3, code reused for something else in ACS2), WIN_IDENTIFY_DMA
    (obsolete since ATA4).
    
    Drop codes that are not implemented and vendor-specific:
    EXABYTE_ENABLE_NEST, DISABLE_SEAGATE.
    
    Drop WIN_INIT, it isn't implemented, its value used to be reserved,
    and is used for something else since ATA8.
    
    CFA_IDLEIMMEDIATE isn't specific to CFATA.  ACS-2 shows it as a
    defined command in ATA-1, -2 and -3.  Rename to WIN_IDLEIMMEDIATE2.
    
    Mark vendor specific, retired, and obsolete codes.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/hw/ide/core.c b/hw/ide/core.c
index 47a706e..d1cbfe7 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -1129,7 +1129,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
     case WIN_STANDBYNOW1:
     case WIN_STANDBYNOW2:
     case WIN_IDLEIMMEDIATE:
-    case CFA_IDLEIMMEDIATE:
+    case WIN_IDLEIMMEDIATE2:
     case WIN_SETIDLE1:
     case WIN_SETIDLE2:
     case WIN_SLEEPNOW1:
@@ -1168,7 +1168,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
                           */
         ide_set_irq(s->bus);
         break;
-    case WIN_SRST:
+    case WIN_DEVICE_RESET:
         if (s->drive_kind != IDE_CD)
             goto abort_cmd;
         ide_set_signature(s);
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index 7f5ef8d..1117852 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -55,111 +55,120 @@ typedef struct IDEDMAOps IDEDMAOps;
 #define IDE_CMD_RESET           0x04
 #define IDE_CMD_DISABLE_IRQ     0x02
 
-/* ATA/ATAPI Commands pre T13 Spec */
+/* ACS-2 T13/2015-D Table B.2 Command codes */
 #define WIN_NOP				0x00
-/*
- *	0x01->0x02 Reserved
- */
+/* reserved                             0x01..0x02 */
 #define CFA_REQ_EXT_ERROR_CODE		0x03 /* CFA Request Extended Error Code */
-/*
- *      0x04->0x05 Reserved
- */
+/* reserved                             0x04..0x05 */
 #define WIN_DSM                         0x06
-/*
- *      0x07 Reserved
- */
-#define WIN_SRST			0x08 /* ATAPI soft reset command */
+/* reserved                             0x07 */
 #define WIN_DEVICE_RESET		0x08
-/*
- *	0x09->0x0F Reserved
- */
-#define WIN_RECAL			0x10
-#define WIN_RESTORE			WIN_RECAL
-/*
- *	0x10->0x1F Reserved
- */
+/* reserved                             0x09..0x0a */
+/* REQUEST SENSE DATA EXT               0x0B */
+/* reserved                             0x0C..0x0F */
+#define WIN_RECAL                       0x10 /* obsolete since ATA4 */
+/* obsolete since ATA3, retired in ATA4 0x11..0x1F */
 #define WIN_READ			0x20 /* 28-Bit */
-#define WIN_READ_ONCE			0x21 /* 28-Bit without retries */
-#define WIN_READ_LONG			0x22 /* 28-Bit */
-#define WIN_READ_LONG_ONCE		0x23 /* 28-Bit without retries */
+#define WIN_READ_ONCE                   0x21 /* 28-Bit w/o retries, obsolete since ATA5 */
+/* obsolete since ATA4                  0x22..0x23 */
 #define WIN_READ_EXT			0x24 /* 48-Bit */
 #define WIN_READDMA_EXT			0x25 /* 48-Bit */
-#define WIN_READDMA_QUEUED_EXT		0x26 /* 48-Bit */
+#define WIN_READDMA_QUEUED_EXT          0x26 /* 48-Bit, obsolete since ACS2 */
 #define WIN_READ_NATIVE_MAX_EXT		0x27 /* 48-Bit */
-/*
- *	0x28
- */
+/* reserved                             0x28 */
 #define WIN_MULTREAD_EXT		0x29 /* 48-Bit */
-/*
- *	0x2A->0x2F Reserved
- */
+/* READ STREAM DMA EXT                  0x2A */
+/* READ STREAM EXT                      0x2B */
+/* reserved                             0x2C..0x2E */
+/* READ LOG EXT                         0x2F */
 #define WIN_WRITE			0x30 /* 28-Bit */
-#define WIN_WRITE_ONCE			0x31 /* 28-Bit without retries */
-#define WIN_WRITE_LONG			0x32 /* 28-Bit */
-#define WIN_WRITE_LONG_ONCE		0x33 /* 28-Bit without retries */
+#define WIN_WRITE_ONCE                  0x31 /* 28-Bit w/o retries, obsolete since ATA5 */
+/* obsolete since ATA4                  0x32..0x33 */
 #define WIN_WRITE_EXT			0x34 /* 48-Bit */
 #define WIN_WRITEDMA_EXT		0x35 /* 48-Bit */
 #define WIN_WRITEDMA_QUEUED_EXT		0x36 /* 48-Bit */
+#define WIN_SET_MAX_EXT                 0x37 /* 48-Bit, obsolete since ACS2 */
 #define WIN_SET_MAX_EXT			0x37 /* 48-Bit */
 #define CFA_WRITE_SECT_WO_ERASE		0x38 /* CFA Write Sectors without erase */
 #define WIN_MULTWRITE_EXT		0x39 /* 48-Bit */
-/*
- *	0x3A->0x3B Reserved
- */
-#define WIN_WRITE_VERIFY		0x3C /* 28-Bit */
-/*
- *	0x3D->0x3F Reserved
- */
+/* WRITE STREAM DMA EXT                 0x3A */
+/* WRITE STREAM EXT                     0x3B */
+#define WIN_WRITE_VERIFY                0x3C /* 28-Bit, obsolete since ATA4 */
+/* WRITE DMA FUA EXT                    0x3D */
+/* obsolete since ACS2                  0x3E */
+/* WRITE LOG EXT                        0x3F */
 #define WIN_VERIFY			0x40 /* 28-Bit - Read Verify Sectors */
-#define WIN_VERIFY_ONCE			0x41 /* 28-Bit - without retries */
+#define WIN_VERIFY_ONCE                 0x41 /* 28-Bit - w/o retries, obsolete since ATA5 */
 #define WIN_VERIFY_EXT			0x42 /* 48-Bit */
-/*
- *	0x43->0x4F Reserved
- */
-#define WIN_FORMAT			0x50
-/*
- *	0x51->0x5F Reserved
- */
-#define WIN_INIT			0x60
-/*
- *	0x61->0x5F Reserved
- */
-#define WIN_SEEK			0x70 /* 0x70-0x7F Reserved */
+/* reserved                             0x43..0x44 */
+/* WRITE UNCORRECTABLE EXT              0x45 */
+/* reserved                             0x46 */
+/* READ LOG DMA EXT                     0x47 */
+/* reserved                             0x48..0x4F */
+/* obsolete since ATA4                  0x50 */
+/* CONFIGURE STREAM                     0x51 */
+/* reserved                             0x52..0x56 */
+/* WRITE LOG DMA EXT                    0x57 */
+/* reserved                             0x58..0x5A */
+/* TRUSTED NON DATA                     0x5B */
+/* TRUSTED RECEIVE                      0x5C */
+/* TRUSTED RECEIVE DMA                  0x5D */
+/* TRUSTED SEND                         0x5E */
+/* TRUSTED SEND DMA                     0x5F */
+/* READ FPDMA QUEUED                    0x60 */
+/* WRITE FPDMA QUEUED                   0x61 */
+/* reserved                             0x62->0x6F */
+#define WIN_SEEK                        0x70 /* obsolete since ATA7 */
+/* reserved                             0x71-0x7F */
+/* vendor specific                      0x80-0x86 */
 #define CFA_TRANSLATE_SECTOR		0x87 /* CFA Translate Sector */
+/* vendor specific                      0x88-0x8F */
 #define WIN_DIAGNOSE			0x90
-#define WIN_SPECIFY			0x91 /* set drive geometry translation */
+#define WIN_SPECIFY                     0x91 /* set drive geometry translation, obsolete since ATA6 */
 #define WIN_DOWNLOAD_MICROCODE		0x92
-#define WIN_STANDBYNOW2			0x94
-#define CFA_IDLEIMMEDIATE		0x95 /* force drive to become "ready" */
-#define WIN_STANDBY2			0x96
-#define WIN_SETIDLE2			0x97
-#define WIN_CHECKPOWERMODE2		0x98
-#define WIN_SLEEPNOW2			0x99
-/*
- *	0x9A VENDOR
- */
+/* DOWNLOAD MICROCODE DMA               0x93 */
+#define WIN_STANDBYNOW2                 0x94 /* retired in ATA4 */
+#define WIN_IDLEIMMEDIATE2              0x95 /* force drive to become "ready", retired in ATA4 */
+#define WIN_STANDBY2                    0x96 /* retired in ATA4 */
+#define WIN_SETIDLE2                    0x97 /* retired in ATA4 */
+#define WIN_CHECKPOWERMODE2             0x98 /* retired in ATA4 */
+#define WIN_SLEEPNOW2                   0x99 /* retired in ATA4 */
+/* vendor specific                      0x9A */
+/* reserved                             0x9B..0x9F */
 #define WIN_PACKETCMD			0xA0 /* Send a packet command. */
 #define WIN_PIDENTIFY			0xA1 /* identify ATAPI device	*/
-#define WIN_QUEUED_SERVICE		0xA2
+#define WIN_QUEUED_SERVICE              0xA2 /* obsolete since ACS2 */
+/* reserved                             0xA3..0xAF */
 #define WIN_SMART			0xB0 /* self-monitoring and reporting */
+/* Device Configuration Overlay         0xB1 */
+/* reserved                             0xB2..0xB3 */
+/* Sanitize Device                      0xB4 */
+/* reserved                             0xB5 */
+/* NV Cache                             0xB6 */
+/* reserved for CFA                     0xB7..0xBB */
 #define CFA_ACCESS_METADATA_STORAGE	0xB8
+/* reserved                             0xBC..0xBF */
 #define CFA_ERASE_SECTORS       	0xC0 /* microdrives implement as NOP */
+/* vendor specific                      0xC1..0xC3 */
 #define WIN_MULTREAD			0xC4 /* read sectors using multiple mode*/
 #define WIN_MULTWRITE			0xC5 /* write sectors using multiple mode */
 #define WIN_SETMULT			0xC6 /* enable/disable multiple mode */
-#define WIN_READDMA_QUEUED		0xC7 /* read sectors using Queued DMA transfers */
+#define WIN_READDMA_QUEUED              0xC7 /* read sectors using Queued DMA transfers, obsolete since ACS2 */
 #define WIN_READDMA			0xC8 /* read sectors using DMA transfers */
-#define WIN_READDMA_ONCE		0xC9 /* 28-Bit - without retries */
+#define WIN_READDMA_ONCE                0xC9 /* 28-Bit - w/o retries, obsolete since ATA5 */
 #define WIN_WRITEDMA			0xCA /* write sectors using DMA transfers */
-#define WIN_WRITEDMA_ONCE		0xCB /* 28-Bit - without retries */
-#define WIN_WRITEDMA_QUEUED		0xCC /* write sectors using Queued DMA transfers */
+#define WIN_WRITEDMA_ONCE               0xCB /* 28-Bit - w/o retries, obsolete since ATA5 */
+#define WIN_WRITEDMA_QUEUED		0xCC /* write sectors using Queued DMA transfers, obsolete since ACS2 */
 #define CFA_WRITE_MULTI_WO_ERASE	0xCD /* CFA Write multiple without erase */
-#define WIN_GETMEDIASTATUS		0xDA
-#define WIN_ACKMEDIACHANGE		0xDB /* ATA-1, ATA-2 vendor */
-#define WIN_POSTBOOT			0xDC
-#define WIN_PREBOOT			0xDD
-#define WIN_DOORLOCK			0xDE /* lock door on removable drives */
-#define WIN_DOORUNLOCK			0xDF /* unlock door on removable drives */
+/* WRITE MULTIPLE FUA EXT               0xCE */
+/* reserved                             0xCF..0xDO */
+/* CHECK MEDIA CARD TYPE                0xD1 */
+/* reserved for media card pass through 0xD2..0xD4 */
+/* reserved                             0xD5..0xD9 */
+#define WIN_GETMEDIASTATUS              0xDA /* obsolete since ATA8 */
+/* obsolete since ATA3, retired in ATA4 0xDB..0xDD */
+#define WIN_DOORLOCK                    0xDE /* lock door on removable drives, obsolete since ATA8 */
+#define WIN_DOORUNLOCK                  0xDF /* unlock door on removable drives, obsolete since ATA8 */
 #define WIN_STANDBYNOW1			0xE0
 #define WIN_IDLEIMMEDIATE		0xE1 /* force drive to become "ready" */
 #define WIN_STANDBY             	0xE2 /* Set device in Standby Mode */
@@ -169,25 +178,25 @@ typedef struct IDEDMAOps IDEDMAOps;
 #define WIN_SLEEPNOW1			0xE6
 #define WIN_FLUSH_CACHE			0xE7
 #define WIN_WRITE_BUFFER		0xE8 /* force write only 1 sector */
-#define WIN_WRITE_SAME			0xE9 /* read ata-2 to use */
-	/* SET_FEATURES 0x22 or 0xDD */
+/* READ BUFFER DMA                      0xE9 */
 #define WIN_FLUSH_CACHE_EXT		0xEA /* 48-Bit */
+/* WRITE BUFFER DMA                     0xEB */
 #define WIN_IDENTIFY			0xEC /* ask drive to identify itself	*/
-#define WIN_MEDIAEJECT			0xED
-#define WIN_IDENTIFY_DMA		0xEE /* same as WIN_IDENTIFY, but DMA */
+#define WIN_MEDIAEJECT                  0xED /* obsolete since ATA8 */
+/* obsolete since ATA4                  0xEE */
 #define WIN_SETFEATURES			0xEF /* set special drive features */
-#define EXABYTE_ENABLE_NEST		0xF0
-#define IBM_SENSE_CONDITION		0xF0 /* measure disk temperature */
+#define IBM_SENSE_CONDITION             0xF0 /* measure disk temperature, vendor specific */
 #define WIN_SECURITY_SET_PASS		0xF1
 #define WIN_SECURITY_UNLOCK		0xF2
 #define WIN_SECURITY_ERASE_PREPARE	0xF3
 #define WIN_SECURITY_ERASE_UNIT		0xF4
 #define WIN_SECURITY_FREEZE_LOCK	0xF5
-#define CFA_WEAR_LEVEL			0xF5 /* microdrives implement as NOP */
+#define CFA_WEAR_LEVEL                  0xF5 /* microdrives implement as NOP; not specified in T13! */
 #define WIN_SECURITY_DISABLE		0xF6
+/* vendor specific                      0xF7 */
 #define WIN_READ_NATIVE_MAX		0xF8 /* return the native maximum address */
 #define WIN_SET_MAX			0xF9
-#define DISABLE_SEAGATE			0xFB
+/* vendor specific                      0xFA..0xFF */
 
 /* set to 1 set disable mult support */
 #define MAX_MULT_SECTORS 16
commit 145feb176ffe6de1db6d05af064c841d7c16633c
Author: Markus Armbruster <armbru at redhat.com>
Date:   Wed Aug 3 15:07:42 2011 +0200

    block: Split change_cb() into change_media_cb(), resize_cb()
    
    Multiplexing callbacks complicates matters needlessly.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index 00fe345..0aba1bf 100644
--- a/block.c
+++ b/block.c
@@ -44,7 +44,7 @@
 #include <windows.h>
 #endif
 
-static void bdrv_dev_change_cb(BlockDriverState *bs, int reason);
+static void bdrv_dev_change_media_cb(BlockDriverState *bs);
 static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
         int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
         BlockDriverCompletionFunc *cb, void *opaque);
@@ -690,7 +690,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
 
     if (!bdrv_key_required(bs)) {
         bs->media_changed = 1;
-        bdrv_dev_change_cb(bs, CHANGE_MEDIA);
+        bdrv_dev_change_media_cb(bs);
     }
 
     return 0;
@@ -727,7 +727,7 @@ void bdrv_close(BlockDriverState *bs)
         }
 
         bs->media_changed = 1;
-        bdrv_dev_change_cb(bs, CHANGE_MEDIA);
+        bdrv_dev_change_media_cb(bs);
     }
 }
 
@@ -806,10 +806,17 @@ void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops,
     bs->dev_opaque = opaque;
 }
 
-static void bdrv_dev_change_cb(BlockDriverState *bs, int reason)
+static void bdrv_dev_change_media_cb(BlockDriverState *bs)
 {
-    if (bs->dev_ops && bs->dev_ops->change_cb) {
-        bs->dev_ops->change_cb(bs->dev_opaque, reason);
+    if (bs->dev_ops && bs->dev_ops->change_media_cb) {
+        bs->dev_ops->change_media_cb(bs->dev_opaque);
+    }
+}
+
+static void bdrv_dev_resize_cb(BlockDriverState *bs)
+{
+    if (bs->dev_ops && bs->dev_ops->resize_cb) {
+        bs->dev_ops->resize_cb(bs->dev_opaque);
     }
 }
 
@@ -1283,7 +1290,7 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset)
     ret = drv->bdrv_truncate(bs, offset);
     if (ret == 0) {
         ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
-        bdrv_dev_change_cb(bs, CHANGE_SIZE);
+        bdrv_dev_resize_cb(bs);
     }
     return ret;
 }
@@ -1659,7 +1666,7 @@ int bdrv_set_key(BlockDriverState *bs, const char *key)
         bs->valid_key = 1;
         /* call the change callback now, we skipped it on open */
         bs->media_changed = 1;
-        bdrv_dev_change_cb(bs, CHANGE_MEDIA);
+        bdrv_dev_change_media_cb(bs);
     }
     return ret;
 }
diff --git a/block.h b/block.h
index a72cfc9..7e3f587 100644
--- a/block.h
+++ b/block.h
@@ -28,8 +28,18 @@ typedef struct QEMUSnapshotInfo {
     uint64_t vm_clock_nsec; /* VM clock relative to boot */
 } QEMUSnapshotInfo;
 
+/* Callbacks for block device models */
 typedef struct BlockDevOps {
-    void (*change_cb)(void *opaque, int reason);
+    /*
+     * Runs when virtual media changed (monitor commands eject, change)
+     * Beware: doesn't run when a host device's physical media
+     * changes.  Sure would be useful if it did.
+     */
+    void (*change_media_cb)(void *opaque);
+    /*
+     * Runs when the size changed (e.g. monitor command block_resize)
+     */
+    void (*resize_cb)(void *opaque);
 } BlockDevOps;
 
 #define BDRV_O_RDWR        0x0002
diff --git a/block_int.h b/block_int.h
index ab31dc9..19ae75e 100644
--- a/block_int.h
+++ b/block_int.h
@@ -211,9 +211,6 @@ struct BlockDriverState {
     void *private;
 };
 
-#define CHANGE_MEDIA    0x01
-#define CHANGE_SIZE     0x02
-
 struct BlockDriverAIOCB {
     AIOPool *pool;
     BlockDriverState *bs;
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 26a9c5b..47a706e 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -783,15 +783,11 @@ static void ide_cfata_metadata_write(IDEState *s)
 }
 
 /* called when the inserted state of the media has changed */
-static void cdrom_change_cb(void *opaque, int reason)
+static void ide_cd_change_cb(void *opaque)
 {
     IDEState *s = opaque;
     uint64_t nb_sectors;
 
-    if (!(reason & CHANGE_MEDIA)) {
-        return;
-    }
-
     bdrv_get_geometry(s->bs, &nb_sectors);
     s->nb_sectors = nb_sectors;
 
@@ -1743,7 +1739,7 @@ void ide_bus_reset(IDEBus *bus)
 }
 
 static const BlockDevOps ide_cd_block_ops = {
-    .change_cb = cdrom_change_cb,
+    .change_media_cb = ide_cd_change_cb,
 };
 
 int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
diff --git a/hw/sd.c b/hw/sd.c
index 1f00910..45e95f9 100644
--- a/hw/sd.c
+++ b/hw/sd.c
@@ -420,14 +420,10 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv)
     sd->pwd_len = 0;
 }
 
-static void sd_cardchange(void *opaque, int reason)
+static void sd_cardchange(void *opaque)
 {
     SDState *sd = opaque;
 
-    if (!(reason & CHANGE_MEDIA)) {
-        return;
-    }
-
     qemu_set_irq(sd->inserted_cb, bdrv_is_inserted(sd->bdrv));
     if (bdrv_is_inserted(sd->bdrv)) {
         sd_reset(sd, sd->bdrv);
@@ -436,7 +432,7 @@ static void sd_cardchange(void *opaque, int reason)
 }
 
 static const BlockDevOps sd_block_ops = {
-    .change_cb = sd_cardchange,
+    .change_media_cb = sd_cardchange,
 };
 
 /* We do not model the chip select pin, so allow the board to select
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index c10afa9..4df23f4 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -543,17 +543,15 @@ static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id)
     return 0;
 }
 
-static void virtio_blk_change_cb(void *opaque, int reason)
+static void virtio_blk_resize(void *opaque)
 {
     VirtIOBlock *s = opaque;
 
-    if (reason & CHANGE_SIZE) {
-        virtio_notify_config(&s->vdev);
-    }
+    virtio_notify_config(&s->vdev);
 }
 
 static const BlockDevOps virtio_block_ops = {
-    .change_cb = virtio_blk_change_cb,
+    .resize_cb = virtio_blk_resize,
 };
 
 VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf,
commit 0e49de5232f47c9e58adb82c28d4f42be933d891
Author: Markus Armbruster <armbru at redhat.com>
Date:   Wed Aug 3 15:07:41 2011 +0200

    block: Generalize change_cb() to BlockDevOps
    
    So we can more easily add device model callbacks.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index fb9341c..00fe345 100644
--- a/block.c
+++ b/block.c
@@ -44,6 +44,7 @@
 #include <windows.h>
 #endif
 
+static void bdrv_dev_change_cb(BlockDriverState *bs, int reason);
 static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
         int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
         BlockDriverCompletionFunc *cb, void *opaque);
@@ -688,10 +689,8 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
     }
 
     if (!bdrv_key_required(bs)) {
-        /* call the change callback */
         bs->media_changed = 1;
-        if (bs->change_cb)
-            bs->change_cb(bs->change_opaque, CHANGE_MEDIA);
+        bdrv_dev_change_cb(bs, CHANGE_MEDIA);
     }
 
     return 0;
@@ -727,10 +726,8 @@ void bdrv_close(BlockDriverState *bs)
             bdrv_close(bs->file);
         }
 
-        /* call the change callback */
         bs->media_changed = 1;
-        if (bs->change_cb)
-            bs->change_cb(bs->change_opaque, CHANGE_MEDIA);
+        bdrv_dev_change_cb(bs, CHANGE_MEDIA);
     }
 }
 
@@ -792,8 +789,8 @@ void bdrv_detach_dev(BlockDriverState *bs, void *dev)
 {
     assert(bs->dev == dev);
     bs->dev = NULL;
-    bs->change_cb = NULL;
-    bs->change_opaque = NULL;
+    bs->dev_ops = NULL;
+    bs->dev_opaque = NULL;
 }
 
 /* TODO change to return DeviceState * when all users are qdevified */
@@ -802,6 +799,20 @@ void *bdrv_get_attached_dev(BlockDriverState *bs)
     return bs->dev;
 }
 
+void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops,
+                      void *opaque)
+{
+    bs->dev_ops = ops;
+    bs->dev_opaque = opaque;
+}
+
+static void bdrv_dev_change_cb(BlockDriverState *bs, int reason)
+{
+    if (bs->dev_ops && bs->dev_ops->change_cb) {
+        bs->dev_ops->change_cb(bs->dev_opaque, reason);
+    }
+}
+
 /*
  * Run consistency checks on an image
  *
@@ -1272,9 +1283,7 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset)
     ret = drv->bdrv_truncate(bs, offset);
     if (ret == 0) {
         ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
-        if (bs->change_cb) {
-            bs->change_cb(bs->change_opaque, CHANGE_SIZE);
-        }
+        bdrv_dev_change_cb(bs, CHANGE_SIZE);
     }
     return ret;
 }
@@ -1612,15 +1621,6 @@ int bdrv_enable_write_cache(BlockDriverState *bs)
     return bs->enable_write_cache;
 }
 
-/* XXX: no longer used */
-void bdrv_set_change_cb(BlockDriverState *bs,
-                        void (*change_cb)(void *opaque, int reason),
-                        void *opaque)
-{
-    bs->change_cb = change_cb;
-    bs->change_opaque = opaque;
-}
-
 int bdrv_is_encrypted(BlockDriverState *bs)
 {
     if (bs->backing_hd && bs->backing_hd->encrypted)
@@ -1659,8 +1659,7 @@ int bdrv_set_key(BlockDriverState *bs, const char *key)
         bs->valid_key = 1;
         /* call the change callback now, we skipped it on open */
         bs->media_changed = 1;
-        if (bs->change_cb)
-            bs->change_cb(bs->change_opaque, CHANGE_MEDIA);
+        bdrv_dev_change_cb(bs, CHANGE_MEDIA);
     }
     return ret;
 }
diff --git a/block.h b/block.h
index c8eea67..a72cfc9 100644
--- a/block.h
+++ b/block.h
@@ -28,6 +28,10 @@ typedef struct QEMUSnapshotInfo {
     uint64_t vm_clock_nsec; /* VM clock relative to boot */
 } QEMUSnapshotInfo;
 
+typedef struct BlockDevOps {
+    void (*change_cb)(void *opaque, int reason);
+} BlockDevOps;
+
 #define BDRV_O_RDWR        0x0002
 #define BDRV_O_SNAPSHOT    0x0008 /* open the file read only and save writes in a snapshot */
 #define BDRV_O_NOCACHE     0x0020 /* do not use the host page cache */
@@ -78,6 +82,8 @@ int bdrv_attach_dev(BlockDriverState *bs, void *dev);
 void bdrv_attach_dev_nofail(BlockDriverState *bs, void *dev);
 void bdrv_detach_dev(BlockDriverState *bs, void *dev);
 void *bdrv_get_attached_dev(BlockDriverState *bs);
+void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops,
+                      void *opaque);
 int bdrv_read(BlockDriverState *bs, int64_t sector_num,
               uint8_t *buf, int nb_sectors);
 int bdrv_write(BlockDriverState *bs, int64_t sector_num,
@@ -193,9 +199,6 @@ int bdrv_media_changed(BlockDriverState *bs);
 int bdrv_is_locked(BlockDriverState *bs);
 void bdrv_set_locked(BlockDriverState *bs, int locked);
 int bdrv_eject(BlockDriverState *bs, int eject_flag);
-void bdrv_set_change_cb(BlockDriverState *bs,
-                        void (*change_cb)(void *opaque, int reason),
-                        void *opaque);
 void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size);
 BlockDriverState *bdrv_find(const char *name);
 BlockDriverState *bdrv_next(BlockDriverState *bs);
diff --git a/block_int.h b/block_int.h
index adc26f8..ab31dc9 100644
--- a/block_int.h
+++ b/block_int.h
@@ -161,15 +161,14 @@ struct BlockDriverState {
     int encrypted; /* if true, the media is encrypted */
     int valid_key; /* if true, a valid encryption key has been set */
     int sg;        /* if true, the device is a /dev/sg* */
-    /* event callback when inserting/removing */
-    void (*change_cb)(void *opaque, int reason);
-    void *change_opaque;
 
     BlockDriver *drv; /* NULL means no media */
     void *opaque;
 
     void *dev;                  /* attached device model, if any */
     /* TODO change to DeviceState when all users are qdevified */
+    const BlockDevOps *dev_ops;
+    void *dev_opaque;
 
     char filename[1024];
     char backing_file[1024]; /* if non zero, the image is a diff of
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 428f033..26a9c5b 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -1742,6 +1742,10 @@ void ide_bus_reset(IDEBus *bus)
     bus->dma->ops->reset(bus->dma);
 }
 
+static const BlockDevOps ide_cd_block_ops = {
+    .change_cb = cdrom_change_cb,
+};
+
 int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
                    const char *version, const char *serial)
 {
@@ -1776,7 +1780,7 @@ int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
     s->smart_errors = 0;
     s->smart_selftest_count = 0;
     if (kind == IDE_CD) {
-        bdrv_set_change_cb(bs, cdrom_change_cb, s);
+        bdrv_set_dev_ops(bs, &ide_cd_block_ops, s);
         bs->buffer_alignment = 2048;
     } else {
         if (!bdrv_is_inserted(s->bs)) {
diff --git a/hw/sd.c b/hw/sd.c
index ab52634..1f00910 100644
--- a/hw/sd.c
+++ b/hw/sd.c
@@ -435,6 +435,10 @@ static void sd_cardchange(void *opaque, int reason)
     }
 }
 
+static const BlockDevOps sd_block_ops = {
+    .change_cb = sd_cardchange,
+};
+
 /* We do not model the chip select pin, so allow the board to select
    whether card should be in SSI or MMC/SD mode.  It is also up to the
    board to ensure that ssi transfers only occur when the chip select
@@ -450,7 +454,7 @@ SDState *sd_init(BlockDriverState *bs, int is_spi)
     sd_reset(sd, bs);
     if (sd->bdrv) {
         bdrv_attach_dev_nofail(sd->bdrv, sd);
-        bdrv_set_change_cb(sd->bdrv, sd_cardchange, sd);
+        bdrv_set_dev_ops(sd->bdrv, &sd_block_ops, sd);
     }
     return sd;
 }
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index 2a8ccd0..c10afa9 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -552,6 +552,10 @@ static void virtio_blk_change_cb(void *opaque, int reason)
     }
 }
 
+static const BlockDevOps virtio_block_ops = {
+    .change_cb = virtio_blk_change_cb,
+};
+
 VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf,
                               char **serial)
 {
@@ -598,7 +602,7 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf,
     register_savevm(dev, "virtio-blk", virtio_blk_id++, 2,
                     virtio_blk_save, virtio_blk_load, s);
     bdrv_set_removable(s->bs, 0);
-    bdrv_set_change_cb(s->bs, virtio_blk_change_cb, s);
+    bdrv_set_dev_ops(s->bs, &virtio_block_ops, s);
     s->bs->buffer_alignment = conf->logical_block_size;
 
     add_boot_device_path(conf->bootindex, dev, "/disk at 0,0");
commit fa879d62eb51253d00b6920ce1d1d9d261370a49
Author: Markus Armbruster <armbru at redhat.com>
Date:   Wed Aug 3 15:07:40 2011 +0200

    block: Attach non-qdev devices as well
    
    For now, this just protects against programming errors like having the
    same drive back multiple non-qdev devices, or untimely bdrv_delete().
    Later commits will add other interesting uses.
    
    While there, rename BlockDriverState member peer to dev, bdrv_attach()
    to bdrv_attach_dev(), bdrv_detach() to bdrv_detach_dev(), and
    bdrv_get_attached() to bdrv_get_attached_dev().
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block.c b/block.c
index 43742b7..fb9341c 100644
--- a/block.c
+++ b/block.c
@@ -755,7 +755,7 @@ void bdrv_make_anon(BlockDriverState *bs)
 
 void bdrv_delete(BlockDriverState *bs)
 {
-    assert(!bs->peer);
+    assert(!bs->dev);
 
     /* remove from list, if necessary */
     bdrv_make_anon(bs);
@@ -769,26 +769,37 @@ void bdrv_delete(BlockDriverState *bs)
     g_free(bs);
 }
 
-int bdrv_attach(BlockDriverState *bs, DeviceState *qdev)
+int bdrv_attach_dev(BlockDriverState *bs, void *dev)
+/* TODO change to DeviceState *dev when all users are qdevified */
 {
-    if (bs->peer) {
+    if (bs->dev) {
         return -EBUSY;
     }
-    bs->peer = qdev;
+    bs->dev = dev;
     return 0;
 }
 
-void bdrv_detach(BlockDriverState *bs, DeviceState *qdev)
+/* TODO qdevified devices don't use this, remove when devices are qdevified */
+void bdrv_attach_dev_nofail(BlockDriverState *bs, void *dev)
 {
-    assert(bs->peer == qdev);
-    bs->peer = NULL;
+    if (bdrv_attach_dev(bs, dev) < 0) {
+        abort();
+    }
+}
+
+void bdrv_detach_dev(BlockDriverState *bs, void *dev)
+/* TODO change to DeviceState *dev when all users are qdevified */
+{
+    assert(bs->dev == dev);
+    bs->dev = NULL;
     bs->change_cb = NULL;
     bs->change_opaque = NULL;
 }
 
-DeviceState *bdrv_get_attached(BlockDriverState *bs)
+/* TODO change to return DeviceState * when all users are qdevified */
+void *bdrv_get_attached_dev(BlockDriverState *bs)
 {
-    return bs->peer;
+    return bs->dev;
 }
 
 /*
diff --git a/block.h b/block.h
index 3ac0b94..c8eea67 100644
--- a/block.h
+++ b/block.h
@@ -74,9 +74,10 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags);
 int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
               BlockDriver *drv);
 void bdrv_close(BlockDriverState *bs);
-int bdrv_attach(BlockDriverState *bs, DeviceState *qdev);
-void bdrv_detach(BlockDriverState *bs, DeviceState *qdev);
-DeviceState *bdrv_get_attached(BlockDriverState *bs);
+int bdrv_attach_dev(BlockDriverState *bs, void *dev);
+void bdrv_attach_dev_nofail(BlockDriverState *bs, void *dev);
+void bdrv_detach_dev(BlockDriverState *bs, void *dev);
+void *bdrv_get_attached_dev(BlockDriverState *bs);
 int bdrv_read(BlockDriverState *bs, int64_t sector_num,
               uint8_t *buf, int nb_sectors);
 int bdrv_write(BlockDriverState *bs, int64_t sector_num,
diff --git a/block_int.h b/block_int.h
index 8a72b80..adc26f8 100644
--- a/block_int.h
+++ b/block_int.h
@@ -168,7 +168,8 @@ struct BlockDriverState {
     BlockDriver *drv; /* NULL means no media */
     void *opaque;
 
-    DeviceState *peer;
+    void *dev;                  /* attached device model, if any */
+    /* TODO change to DeviceState when all users are qdevified */
 
     char filename[1024];
     char backing_file[1024]; /* if non zero, the image is a diff of
diff --git a/blockdev.c b/blockdev.c
index 2602591..049dda5 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -14,7 +14,6 @@
 #include "qemu-option.h"
 #include "qemu-config.h"
 #include "sysemu.h"
-#include "hw/qdev.h"
 #include "block_int.h"
 
 static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives);
@@ -738,12 +737,12 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
     bdrv_flush(bs);
     bdrv_close(bs);
 
-    /* if we have a device associated with this BlockDriverState (bs->peer)
+    /* if we have a device attached to this BlockDriverState
      * then we need to make the drive anonymous until the device
      * can be removed.  If this is a drive with no device backing
      * then we can just get rid of the block driver state right here.
      */
-    if (bs->peer) {
+    if (bdrv_get_attached_dev(bs)) {
         bdrv_make_anon(bs);
     } else {
         drive_uninit(drive_get_by_blockdev(bs));
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 40abc1e..428f033 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -1890,6 +1890,7 @@ void ide_init2_with_non_qdev_drives(IDEBus *bus, DriveInfo *hd0,
                 error_report("Can't set up IDE drive %s", dinfo->id);
                 exit(1);
             }
+            bdrv_attach_dev_nofail(dinfo->bdrv, &bus->ifs[i]);
         } else {
             ide_reset(&bus->ifs[i]);
         }
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index 8525336..b9cdcd6 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -177,9 +177,9 @@ static int pci_piix3_xen_ide_unplug(DeviceState *dev)
     for (; i < 3; i++) {
         di = drive_get_by_index(IF_IDE, i);
         if (di != NULL && di->bdrv != NULL && !di->bdrv->removable) {
-            DeviceState *ds = bdrv_get_attached(di->bdrv);
+            DeviceState *ds = bdrv_get_attached_dev(di->bdrv);
             if (ds) {
-                bdrv_detach(di->bdrv, ds);
+                bdrv_detach_dev(di->bdrv, ds);
             }
             bdrv_close(di->bdrv);
             pci_ide->bus[di->bus].ifs[di->unit].bs = NULL;
diff --git a/hw/pflash_cfi01.c b/hw/pflash_cfi01.c
index 90e1301..a2d9402 100644
--- a/hw/pflash_cfi01.c
+++ b/hw/pflash_cfi01.c
@@ -620,6 +620,7 @@ pflash_t *pflash_cfi01_register(target_phys_addr_t base, ram_addr_t off,
             g_free(pfl);
             return NULL;
         }
+        bdrv_attach_dev_nofail(pfl->bs, pfl);
     }
 #if 0 /* XXX: there should be a bit to set up read-only,
        *      the same way the hardware does (with WP pin).
diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c
index ac5115e..919cfc4 100644
--- a/hw/pflash_cfi02.c
+++ b/hw/pflash_cfi02.c
@@ -643,6 +643,7 @@ pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
             g_free(pfl);
             return NULL;
         }
+        bdrv_attach_dev_nofail(pfl->bs, pfl);
     }
 #if 0 /* XXX: there should be a bit to set up read-only,
        *      the same way the hardware does (with WP pin).
diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index 0c0c292..7ce95b6 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -312,7 +312,7 @@ static int parse_drive(DeviceState *dev, Property *prop, const char *str)
     bs = bdrv_find(str);
     if (bs == NULL)
         return -ENOENT;
-    if (bdrv_attach(bs, dev) < 0)
+    if (bdrv_attach_dev(bs, dev) < 0)
         return -EEXIST;
     *ptr = bs;
     return 0;
@@ -323,7 +323,7 @@ static void free_drive(DeviceState *dev, Property *prop)
     BlockDriverState **ptr = qdev_get_prop_ptr(dev, prop);
 
     if (*ptr) {
-        bdrv_detach(*ptr, dev);
+        bdrv_detach_dev(*ptr, dev);
         blockdev_auto_del(*ptr);
     }
 }
@@ -678,7 +678,7 @@ int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *va
 {
     int res;
 
-    res = bdrv_attach(value, dev);
+    res = bdrv_attach_dev(value, dev);
     if (res < 0) {
         error_report("Can't attach drive %s to %s.%s: %s",
                      bdrv_get_device_name(value),
diff --git a/hw/sd.c b/hw/sd.c
index bb8c2ff..ab52634 100644
--- a/hw/sd.c
+++ b/hw/sd.c
@@ -449,6 +449,7 @@ SDState *sd_init(BlockDriverState *bs, int is_spi)
     sd->enable = 1;
     sd_reset(sd, bs);
     if (sd->bdrv) {
+        bdrv_attach_dev_nofail(sd->bdrv, sd);
         bdrv_set_change_cb(sd->bdrv, sd_cardchange, sd);
     }
     return sd;
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index 4072efd..e92434c 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -518,7 +518,7 @@ static int usb_msd_initfn(USBDevice *dev)
      *
      * The hack is probably a bad idea.
      */
-    bdrv_detach(bs, &s->dev.qdev);
+    bdrv_detach_dev(bs, &s->dev.qdev);
     s->conf.bs = NULL;
 
     if (!s->serial) {
diff --git a/hw/xen_disk.c b/hw/xen_disk.c
index bd5c669..da531a6 100644
--- a/hw/xen_disk.c
+++ b/hw/xen_disk.c
@@ -697,6 +697,7 @@ static int blk_init(struct XenDevice *xendev)
         xen_be_printf(&blkdev->xendev, 2, "get configured bdrv (cmdline setup)\n");
         blkdev->bs = blkdev->dinfo->bdrv;
     }
+    bdrv_attach_dev_nofail(blkdev->bs, blkdev);
     blkdev->file_blk  = BLOCK_SIZE;
     blkdev->file_size = bdrv_getlength(blkdev->bs);
     if (blkdev->file_size < 0) {
commit 648fb0ea5e9d7f32c80ec23c3ece4321403dfecd
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Thu Sep 1 16:16:10 2011 +0200

    async: Allow nested qemu_bh_poll calls
    
    qemu may segfault when a BH handler first deletes a BH and then (possibly
    indirectly) calls a nested qemu_bh_poll(). This is because the inner instance
    frees the BH and deletes it from the list that the outer one processes.
    
    This patch deletes BHs only in the outermost qemu_bh_poll instance.
    
    Commit 7887f620 already tried to achieve the same, but it assumed that the BH
    handler would only delete its own BH. With a nested qemu_bh_poll(), this isn't
    guaranteed, so that commit wasn't enough. Hope this one fixes it for real.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/async.c b/async.c
index 9d4e960..ca13962 100644
--- a/async.c
+++ b/async.c
@@ -55,6 +55,9 @@ int qemu_bh_poll(void)
 {
     QEMUBH *bh, **bhp, *next;
     int ret;
+    static int nesting = 0;
+
+    nesting++;
 
     ret = 0;
     for (bh = first_bh; bh; bh = next) {
@@ -68,15 +71,20 @@ int qemu_bh_poll(void)
         }
     }
 
+    nesting--;
+
     /* remove deleted bhs */
-    bhp = &first_bh;
-    while (*bhp) {
-        bh = *bhp;
-        if (bh->deleted) {
-            *bhp = bh->next;
-            g_free(bh);
-        } else
-            bhp = &bh->next;
+    if (!nesting) {
+        bhp = &first_bh;
+        while (*bhp) {
+            bh = *bhp;
+            if (bh->deleted) {
+                *bhp = bh->next;
+                g_free(bh);
+            } else {
+                bhp = &bh->next;
+            }
+        }
     }
 
     return ret;
commit 0fa9131a44943cc14c931a23eee040da4cc0c454
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Thu Sep 1 15:02:13 2011 +0200

    qcow2: Fix error cases to run depedent requests
    
    Requests depending on a failed request would end up waiting forever. This fixes
    the error path to continue dependent requests even when the request has failed.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/qcow2.c b/block/qcow2.c
index f26f7b6..8aed310 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -593,13 +593,12 @@ static int qcow2_co_writev(BlockDriverState *bs,
         }
 
         ret = qcow2_alloc_cluster_link_l2(bs, &l2meta);
-
-        run_dependent_requests(s, &l2meta);
-
         if (ret < 0) {
             goto fail;
         }
 
+        run_dependent_requests(s, &l2meta);
+
         remaining_sectors -= cur_nr_sectors;
         sector_num += cur_nr_sectors;
         bytes_done += cur_nr_sectors * 512;
@@ -607,6 +606,8 @@ static int qcow2_co_writev(BlockDriverState *bs,
     ret = 0;
 
 fail:
+    run_dependent_requests(s, &l2meta);
+
     qemu_co_mutex_unlock(&s->lock);
 
     qemu_iovec_destroy(&hd_qiov);
commit 8e217d5384a38bdb4727c4e22d7ed64c351361f7
Author: Kevin Wolf <kwolf at redhat.com>
Date:   Thu Sep 1 15:00:42 2011 +0200

    qcow2: Properly initialise QcowL2Meta
    
    Dependency list pointers filled with random garbage from the stack aren't a
    good idea.
    
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/qcow2.c b/block/qcow2.c
index b725d68..f26f7b6 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -526,13 +526,14 @@ static int qcow2_co_writev(BlockDriverState *bs,
     int n_end;
     int ret;
     int cur_nr_sectors; /* number of sectors in current iteration */
-    QCowL2Meta l2meta;
     uint64_t cluster_offset;
     QEMUIOVector hd_qiov;
     uint64_t bytes_done = 0;
     uint8_t *cluster_data = NULL;
+    QCowL2Meta l2meta = {
+        .nb_clusters = 0,
+    };
 
-    l2meta.nb_clusters = 0;
     qemu_co_queue_init(&l2meta.dependent_requests);
 
     qemu_iovec_init(&hd_qiov, qiov->niov);
commit c30e624d5d04efdb581c841f9bf8b06302b96575
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Tue Aug 30 09:46:11 2011 +0200

    linux aio: some comments
    
    Add some notes about Linux AIO explaining why we don't use AIO in
    some situations.
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Signed-off-by: Kevin Wolf <kwolf at redhat.com>

diff --git a/block/raw-posix.c b/block/raw-posix.c
index c5c9944..bcf50b2 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -236,6 +236,10 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
     }
 
 #ifdef CONFIG_LINUX_AIO
+    /*
+     * Currently Linux do AIO only for files opened with O_DIRECT
+     * specified so check NOCACHE flag too
+     */
     if ((bdrv_flags & (BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO)) ==
                       (BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO)) {
 
diff --git a/linux-aio.c b/linux-aio.c
index 5fd3932..5265a02 100644
--- a/linux-aio.c
+++ b/linux-aio.c
@@ -181,6 +181,7 @@ BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
     case QEMU_AIO_READ:
         io_prep_preadv(iocbs, fd, qiov->iov, qiov->niov, offset);
 	break;
+    /* Currently Linux kernel does not support other operations */
     default:
         fprintf(stderr, "%s: invalid AIO request type 0x%x.\n",
                         __func__, type);
commit c50a6def965d2e5144557af447825c9875f48a6f
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 21:42:57 2011 +0300

    milkymist: convert to memory API
    
    Reviewed-by: Richard Henderson  <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/milkymist.c b/hw/milkymist.c
index a44b80c..bca0a58 100644
--- a/hw/milkymist.c
+++ b/hw/milkymist.c
@@ -29,6 +29,7 @@
 #include "blockdev.h"
 #include "milkymist-hw.h"
 #include "lm32.h"
+#include "exec-memory.h"
 
 #define BIOS_FILENAME    "mmone-bios.bin"
 #define BIOS_OFFSET      0x00860000
@@ -81,7 +82,8 @@ milkymist_init(ram_addr_t ram_size_not_used,
     CPUState *env;
     int kernel_size;
     DriveInfo *dinfo;
-    ram_addr_t phys_sdram;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *phys_sdram = g_new(MemoryRegion, 1);
     qemu_irq irq[32], *cpu_irq;
     int i;
     char *bios_filename;
@@ -108,9 +110,8 @@ milkymist_init(ram_addr_t ram_size_not_used,
 
     cpu_lm32_set_phys_msb_ignore(env, 1);
 
-    phys_sdram = qemu_ram_alloc(NULL, "milkymist.sdram", sdram_size);
-    cpu_register_physical_memory(sdram_base, sdram_size,
-            phys_sdram | IO_MEM_RAM);
+    memory_region_init_ram(phys_sdram, NULL, "milkymist.sdram", sdram_size);
+    memory_region_add_subregion(address_space_mem, sdram_base, phys_sdram);
 
     dinfo = drive_get(IF_PFLASH, 0, 0);
     /* Numonyx JS28F256J3F105 */
commit 5105ed3b1931a8f61904b2c79af4dba364474dd2
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 21:40:35 2011 +0300

    milkymist-softusb: convert to memory API
    
    Reviewed-by: Richard Henderson  <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/milkymist-softusb.c b/hw/milkymist-softusb.c
index fe4eedb..ef4d9ee 100644
--- a/hw/milkymist-softusb.c
+++ b/hw/milkymist-softusb.c
@@ -49,6 +49,9 @@ struct MilkymistSoftUsbState {
     HIDState hid_kbd;
     HIDState hid_mouse;
 
+    MemoryRegion regs_region;
+    MemoryRegion pmem;
+    MemoryRegion dmem;
     qemu_irq irq;
 
     /* device properties */
@@ -68,7 +71,8 @@ struct MilkymistSoftUsbState {
 };
 typedef struct MilkymistSoftUsbState MilkymistSoftUsbState;
 
-static uint32_t softusb_read(void *opaque, target_phys_addr_t addr)
+static uint64_t softusb_read(void *opaque, target_phys_addr_t addr,
+                             unsigned size)
 {
     MilkymistSoftUsbState *s = opaque;
     uint32_t r = 0;
@@ -91,7 +95,8 @@ static uint32_t softusb_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void
-softusb_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+softusb_write(void *opaque, target_phys_addr_t addr, uint64_t value,
+              unsigned size)
 {
     MilkymistSoftUsbState *s = opaque;
 
@@ -110,16 +115,14 @@ softusb_write(void *opaque, target_phys_addr_t addr, uint32_t value)
     }
 }
 
-static CPUReadMemoryFunc * const softusb_read_fn[] = {
-    NULL,
-    NULL,
-    &softusb_read,
-};
-
-static CPUWriteMemoryFunc * const softusb_write_fn[] = {
-    NULL,
-    NULL,
-    &softusb_write,
+static const MemoryRegionOps softusb_mmio_ops = {
+    .read = softusb_read,
+    .write = softusb_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
 };
 
 static inline void softusb_read_dmem(MilkymistSoftUsbState *s,
@@ -256,23 +259,20 @@ static void milkymist_softusb_reset(DeviceState *d)
 static int milkymist_softusb_init(SysBusDevice *dev)
 {
     MilkymistSoftUsbState *s = FROM_SYSBUS(typeof(*s), dev);
-    int softusb_regs;
-    ram_addr_t pmem_ram;
-    ram_addr_t dmem_ram;
 
     sysbus_init_irq(dev, &s->irq);
 
-    softusb_regs = cpu_register_io_memory(softusb_read_fn, softusb_write_fn, s,
-            DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, R_MAX * 4, softusb_regs);
+    memory_region_init_io(&s->regs_region, &softusb_mmio_ops, s,
+                          "milkymist-softusb", R_MAX * 4);
+    sysbus_init_mmio_region(dev, &s->regs_region);
 
     /* register pmem and dmem */
-    pmem_ram = qemu_ram_alloc(NULL, "milkymist_softusb.pmem", s->pmem_size);
-    cpu_register_physical_memory(s->pmem_base, s->pmem_size,
-            pmem_ram | IO_MEM_RAM);
-    dmem_ram = qemu_ram_alloc(NULL, "milkymist_softusb.dmem", s->dmem_size);
-    cpu_register_physical_memory(s->dmem_base, s->dmem_size,
-            dmem_ram | IO_MEM_RAM);
+    memory_region_init_ram(&s->pmem, NULL, "milkymist_softusb.pmem",
+                           s->pmem_size);
+    sysbus_add_memory(dev, s->pmem_base, &s->pmem);
+    memory_region_init_ram(&s->dmem, NULL, "milkymist_softusb.dmem",
+                           s->dmem_size);
+    sysbus_add_memory(dev, s->dmem_base, &s->dmem);
 
     hid_init(&s->hid_kbd, HID_KEYBOARD, softusb_kbd_hid_datain);
     hid_init(&s->hid_mouse, HID_MOUSE, softusb_mouse_hid_datain);
commit 8a53d56fdc3eae18f38d864659cef205c37c8a42
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 21:32:25 2011 +0300

    milkymist-minimac2: convert to memory API
    
    Reviewed-by: Richard Henderson  <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/milkymist-minimac2.c b/hw/milkymist-minimac2.c
index cd36026..fb48e37 100644
--- a/hw/milkymist-minimac2.c
+++ b/hw/milkymist-minimac2.c
@@ -97,6 +97,8 @@ struct MilkymistMinimac2State {
     NICConf conf;
     char *phy_model;
     target_phys_addr_t buffers_base;
+    MemoryRegion buffers;
+    MemoryRegion regs_region;
 
     qemu_irq rx_irq;
     qemu_irq tx_irq;
@@ -320,8 +322,8 @@ static ssize_t minimac2_rx(VLANClientState *nc, const uint8_t *buf, size_t size)
     return size;
 }
 
-static uint32_t
-minimac2_read(void *opaque, target_phys_addr_t addr)
+static uint64_t
+minimac2_read(void *opaque, target_phys_addr_t addr, unsigned size)
 {
     MilkymistMinimac2State *s = opaque;
     uint32_t r = 0;
@@ -350,7 +352,8 @@ minimac2_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void
-minimac2_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+minimac2_write(void *opaque, target_phys_addr_t addr, uint64_t value,
+               unsigned size)
 {
     MilkymistMinimac2State *s = opaque;
 
@@ -395,16 +398,14 @@ minimac2_write(void *opaque, target_phys_addr_t addr, uint32_t value)
     }
 }
 
-static CPUReadMemoryFunc * const minimac2_read_fn[] = {
-    NULL,
-    NULL,
-    &minimac2_read,
-};
-
-static CPUWriteMemoryFunc * const minimac2_write_fn[] = {
-    NULL,
-    NULL,
-    &minimac2_write,
+static const MemoryRegionOps minimac2_ops = {
+    .read = minimac2_read,
+    .write = minimac2_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 static int minimac2_can_rx(VLANClientState *nc)
@@ -457,25 +458,23 @@ static NetClientInfo net_milkymist_minimac2_info = {
 static int milkymist_minimac2_init(SysBusDevice *dev)
 {
     MilkymistMinimac2State *s = FROM_SYSBUS(typeof(*s), dev);
-    int regs;
-    ram_addr_t buffers;
     size_t buffers_size = TARGET_PAGE_ALIGN(3 * MINIMAC2_BUFFER_SIZE);
 
     sysbus_init_irq(dev, &s->rx_irq);
     sysbus_init_irq(dev, &s->tx_irq);
 
-    regs = cpu_register_io_memory(minimac2_read_fn, minimac2_write_fn, s,
-            DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, R_MAX * 4, regs);
+    memory_region_init_io(&s->regs_region, &minimac2_ops, s,
+                          "minimac2-mmio", R_MAX * 4);
+    sysbus_init_mmio_region(dev, &s->regs_region);
 
     /* register buffers memory */
-    buffers = qemu_ram_alloc(NULL, "milkymist_minimac2.buffers", buffers_size);
-    s->rx0_buf = qemu_get_ram_ptr(buffers);
+    memory_region_init_ram(&s->buffers, NULL, "milkymist_minimac2.buffers",
+                           buffers_size);
+    s->rx0_buf = memory_region_get_ram_ptr(&s->buffers);
     s->rx1_buf = s->rx0_buf + MINIMAC2_BUFFER_SIZE;
     s->tx_buf = s->rx1_buf + MINIMAC2_BUFFER_SIZE;
 
-    cpu_register_physical_memory(s->buffers_base, buffers_size,
-            buffers | IO_MEM_RAM);
+    sysbus_add_memory(dev, s->buffers_base, &s->buffers);
 
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
     s->nic = qemu_new_nic(&net_milkymist_minimac2_info, &s->conf,
commit c378b364ee2fb3690fd6e3cbf07fb1a666eabe3a
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 21:21:47 2011 +0300

    mcf5208: convert to memory API
    
    Reviewed-by: Richard Henderson  <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/mcf5208.c b/hw/mcf5208.c
index 8fe507f..1c2c0c4 100644
--- a/hw/mcf5208.c
+++ b/hw/mcf5208.c
@@ -13,6 +13,7 @@
 #include "boards.h"
 #include "loader.h"
 #include "elf.h"
+#include "exec-memory.h"
 
 #define SYS_FREQ 66000000
 
@@ -27,6 +28,7 @@
 #define PCSR_PRE_MASK   0x0f00
 
 typedef struct {
+    MemoryRegion iomem;
     qemu_irq irq;
     ptimer_state *timer;
     uint16_t pcsr;
@@ -43,7 +45,7 @@ static void m5208_timer_update(m5208_timer_state *s)
 }
 
 static void m5208_timer_write(void *opaque, target_phys_addr_t offset,
-                              uint32_t value)
+                              uint64_t value, unsigned size)
 {
     m5208_timer_state *s = (m5208_timer_state *)opaque;
     int prescale;
@@ -104,7 +106,8 @@ static void m5208_timer_trigger(void *opaque)
     m5208_timer_update(s);
 }
 
-static uint32_t m5208_timer_read(void *opaque, target_phys_addr_t addr)
+static uint64_t m5208_timer_read(void *opaque, target_phys_addr_t addr,
+                                 unsigned size)
 {
     m5208_timer_state *s = (m5208_timer_state *)opaque;
     switch (addr) {
@@ -120,19 +123,14 @@ static uint32_t m5208_timer_read(void *opaque, target_phys_addr_t addr)
     }
 }
 
-static CPUReadMemoryFunc * const m5208_timer_readfn[] = {
-   m5208_timer_read,
-   m5208_timer_read,
-   m5208_timer_read
+static const MemoryRegionOps m5208_timer_ops = {
+    .read = m5208_timer_read,
+    .write = m5208_timer_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const m5208_timer_writefn[] = {
-   m5208_timer_write,
-   m5208_timer_write,
-   m5208_timer_write
-};
-
-static uint32_t m5208_sys_read(void *opaque, target_phys_addr_t addr)
+static uint64_t m5208_sys_read(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
 {
     switch (addr) {
     case 0x110: /* SDCS0 */
@@ -154,45 +152,36 @@ static uint32_t m5208_sys_read(void *opaque, target_phys_addr_t addr)
 }
 
 static void m5208_sys_write(void *opaque, target_phys_addr_t addr,
-                            uint32_t value)
+                            uint64_t value, unsigned size)
 {
     hw_error("m5208_sys_write: Bad offset 0x%x\n", (int)addr);
 }
 
-static CPUReadMemoryFunc * const m5208_sys_readfn[] = {
-   m5208_sys_read,
-   m5208_sys_read,
-   m5208_sys_read
-};
-
-static CPUWriteMemoryFunc * const m5208_sys_writefn[] = {
-   m5208_sys_write,
-   m5208_sys_write,
-   m5208_sys_write
+static const MemoryRegionOps m5208_sys_ops = {
+    .read = m5208_sys_read,
+    .write = m5208_sys_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static void mcf5208_sys_init(qemu_irq *pic)
+static void mcf5208_sys_init(MemoryRegion *address_space, qemu_irq *pic)
 {
-    int iomemtype;
+    MemoryRegion *iomem = g_new(MemoryRegion, 1);
     m5208_timer_state *s;
     QEMUBH *bh;
     int i;
 
-    iomemtype = cpu_register_io_memory(m5208_sys_readfn,
-                                       m5208_sys_writefn, NULL,
-                                       DEVICE_NATIVE_ENDIAN);
     /* SDRAMC.  */
-    cpu_register_physical_memory(0xfc0a8000, 0x00004000, iomemtype);
+    memory_region_init_io(iomem, &m5208_sys_ops, NULL, "m5208-sys", 0x00004000);
+    memory_region_add_subregion(address_space, 0xfc0a8000, iomem);
     /* Timers.  */
     for (i = 0; i < 2; i++) {
         s = (m5208_timer_state *)g_malloc0(sizeof(m5208_timer_state));
         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,
-                                           DEVICE_NATIVE_ENDIAN);
-        cpu_register_physical_memory(0xfc080000 + 0x4000 * i, 0x00004000,
-                                     iomemtype);
+        memory_region_init_io(&s->iomem, &m5208_timer_ops, s,
+                              "m5208-timer", 0x00004000);
+        memory_region_add_subregion(address_space, 0xfc080000 + 0x4000 * i,
+                                    &s->iomem);
         s->irq = pic[4 + i];
     }
 }
@@ -207,6 +196,9 @@ static void mcf5208evb_init(ram_addr_t ram_size,
     uint64_t elf_entry;
     target_phys_addr_t entry;
     qemu_irq *pic;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *sram = g_new(MemoryRegion, 1);
 
     if (!cpu_model)
         cpu_model = "m5208";
@@ -221,12 +213,12 @@ static void mcf5208evb_init(ram_addr_t ram_size,
     /* TODO: Configure BARs.  */
 
     /* DRAM at 0x40000000 */
-    cpu_register_physical_memory(0x40000000, ram_size,
-        qemu_ram_alloc(NULL, "mcf5208.ram", ram_size) | IO_MEM_RAM);
+    memory_region_init_ram(ram, NULL, "mcf5208.ram", ram_size);
+    memory_region_add_subregion(address_space_mem, 0x40000000, ram);
 
     /* Internal SRAM.  */
-    cpu_register_physical_memory(0x80000000, 16384,
-        qemu_ram_alloc(NULL, "mcf5208.sram", 16384) | IO_MEM_RAM);
+    memory_region_init_ram(sram, NULL, "mcf5208.sram", 16384);
+    memory_region_add_subregion(address_space_mem, 0x80000000, sram);
 
     /* Internal peripherals.  */
     pic = mcf_intc_init(0xfc048000, env);
@@ -235,7 +227,7 @@ static void mcf5208evb_init(ram_addr_t ram_size,
     mcf_uart_mm_init(0xfc064000, pic[27], serial_hds[1]);
     mcf_uart_mm_init(0xfc068000, pic[28], serial_hds[2]);
 
-    mcf5208_sys_init(pic);
+    mcf5208_sys_init(address_space_mem, pic);
 
     if (nb_nics > 1) {
         fprintf(stderr, "Too many NICs\n");
commit 02e5c167570800e833e36340d87e21db55eb4e87
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 21:08:45 2011 +0300

    mainstone: convert to memory API
    
    Reviewed-by: Richard Henderson  <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/mainstone.c b/hw/mainstone.c
index c0524d7..336f31e 100644
--- a/hw/mainstone.c
+++ b/hw/mainstone.c
@@ -17,6 +17,7 @@
 #include "flash.h"
 #include "blockdev.h"
 #include "sysbus.h"
+#include "exec-memory.h"
 
 /* Device addresses */
 #define MST_FPGA_PHYS	0x08000000
@@ -90,7 +91,8 @@ static struct arm_boot_info mainstone_binfo = {
     .ram_size = 0x04000000,
 };
 
-static void mainstone_common_init(ram_addr_t ram_size,
+static void mainstone_common_init(MemoryRegion *address_space_mem,
+                ram_addr_t ram_size,
                 const char *kernel_filename,
                 const char *kernel_cmdline, const char *initrd_filename,
                 const char *cpu_model, enum mainstone_model_e model, int arm_id)
@@ -102,15 +104,16 @@ static void mainstone_common_init(ram_addr_t ram_size,
     DriveInfo *dinfo;
     int i;
     int be;
+    MemoryRegion *rom = g_new(MemoryRegion, 1);
 
     if (!cpu_model)
         cpu_model = "pxa270-c5";
 
     /* Setup CPU & memory */
     cpu = pxa270_init(mainstone_binfo.ram_size, cpu_model);
-    cpu_register_physical_memory(0, MAINSTONE_ROM,
-                    qemu_ram_alloc(NULL, "mainstone.rom",
-                                   MAINSTONE_ROM) | IO_MEM_ROM);
+    memory_region_init_ram(rom, NULL, "mainstone.rom", MAINSTONE_ROM);
+    memory_region_set_readonly(rom, true);
+    memory_region_add_subregion(address_space_mem, 0, rom);
 
 #ifdef TARGET_WORDS_BIGENDIAN
     be = 1;
@@ -169,7 +172,7 @@ static void mainstone_init(ram_addr_t ram_size,
                 const char *kernel_filename, const char *kernel_cmdline,
                 const char *initrd_filename, const char *cpu_model)
 {
-    mainstone_common_init(ram_size, kernel_filename,
+    mainstone_common_init(get_system_memory(), ram_size, kernel_filename,
                 kernel_cmdline, initrd_filename, cpu_model, mainstone, 0x196);
 }
 
commit 88fa8031bde51ad6b4bf5578dd7c19c484921ebe
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 21:05:07 2011 +0300

    lm32_boards: convert to memory API
    
    Reviewed-by: Richard Henderson  <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/lm32_boards.c b/hw/lm32_boards.c
index e4acac1..97e1c00 100644
--- a/hw/lm32_boards.c
+++ b/hw/lm32_boards.c
@@ -28,6 +28,7 @@
 #include "elf.h"
 #include "lm32_hwsetup.h"
 #include "lm32.h"
+#include "exec-memory.h"
 
 typedef struct {
     CPUState *env;
@@ -76,7 +77,8 @@ static void lm32_evr_init(ram_addr_t ram_size_not_used,
 {
     CPUState *env;
     DriveInfo *dinfo;
-    ram_addr_t phys_ram;
+    MemoryRegion *address_space_mem =  get_system_memory();
+    MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
     qemu_irq *cpu_irq, irq[32];
     ResetInfo *reset_info;
     int i;
@@ -104,8 +106,8 @@ static void lm32_evr_init(ram_addr_t ram_size_not_used,
 
     reset_info->flash_base = flash_base;
 
-    phys_ram = qemu_ram_alloc(NULL, "lm32_evr.sdram", ram_size);
-    cpu_register_physical_memory(ram_base, ram_size, phys_ram | IO_MEM_RAM);
+    memory_region_init_ram(phys_ram, NULL, "lm32_evr.sdram", ram_size);
+    memory_region_add_subregion(address_space_mem, ram_base, phys_ram);
 
     dinfo = drive_get(IF_PFLASH, 0, 0);
     /* Spansion S29NS128P */
@@ -162,7 +164,8 @@ static void lm32_uclinux_init(ram_addr_t ram_size_not_used,
 {
     CPUState *env;
     DriveInfo *dinfo;
-    ram_addr_t phys_ram;
+    MemoryRegion *address_space_mem =  get_system_memory();
+    MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
     qemu_irq *cpu_irq, irq[32];
     HWSetup *hw;
     ResetInfo *reset_info;
@@ -197,8 +200,8 @@ static void lm32_uclinux_init(ram_addr_t ram_size_not_used,
 
     reset_info->flash_base = flash_base;
 
-    phys_ram = qemu_ram_alloc(NULL, "lm32_uclinux.sdram", ram_size);
-    cpu_register_physical_memory(ram_base, ram_size, phys_ram | IO_MEM_RAM);
+    memory_region_init_ram(phys_ram, NULL, "lm32_uclinux.sdram", ram_size);
+    memory_region_add_subregion(address_space_mem, ram_base, phys_ram);
 
     dinfo = drive_get(IF_PFLASH, 0, 0);
     /* Spansion S29NS128P */
commit cbdea0ca89d1b61f11f2fa4f044054bde55bbc3b
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 20:44:23 2011 +0300

    dummy_m68k: convert to memory API
    
    Reviewed-by: Richard Henderson  <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/dummy_m68k.c b/hw/dummy_m68k.c
index eed9e38..30146b9 100644
--- a/hw/dummy_m68k.c
+++ b/hw/dummy_m68k.c
@@ -10,6 +10,7 @@
 #include "boards.h"
 #include "loader.h"
 #include "elf.h"
+#include "exec-memory.h"
 
 #define KERNEL_LOAD_ADDR 0x10000
 
@@ -21,6 +22,8 @@ static void dummy_m68k_init(ram_addr_t ram_size,
                      const char *initrd_filename, const char *cpu_model)
 {
     CPUState *env;
+    MemoryRegion *address_space_mem =  get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
     int kernel_size;
     uint64_t elf_entry;
     target_phys_addr_t entry;
@@ -37,8 +40,8 @@ static void dummy_m68k_init(ram_addr_t ram_size,
     env->vbr = 0;
 
     /* RAM at address zero */
-    cpu_register_physical_memory(0, ram_size,
-        qemu_ram_alloc(NULL, "dummy_m68k.ram", ram_size) | IO_MEM_RAM);
+    memory_region_init_ram(ram, NULL, "dummy_m68k.ram", ram_size);
+    memory_region_add_subregion(address_space_mem, 0, ram);
 
     /* Load kernel.  */
     if (kernel_filename) {
commit cfe5f011042456ad6ebd815f5ce4177befedd79a
Author: Avi Kivity <avi at redhat.com>
Date:   Thu Aug 4 15:55:30 2011 +0300

    pflash_cfi01/pflash_cfi02: convert to memory API
    
    cfi02 is annoying in that is ignores some address bits; we probably
    want explicit support in the memory API for that.
    
    In order to get the correct opaque into the MemoryRegion object, the
    allocation scheme is changed so that the flash emulation code allocates
    memory, instead of the caller.  This clears a FIXME in the flash code.
    
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/collie.c b/hw/collie.c
index 156404d..a10cc1b 100644
--- a/hw/collie.c
+++ b/hw/collie.c
@@ -26,7 +26,6 @@ static void collie_init(ram_addr_t ram_size,
 {
     StrongARMState *s;
     DriveInfo *dinfo;
-    ram_addr_t phys_flash;
 
     if (!cpu_model) {
         cpu_model = "sa1110";
@@ -34,15 +33,13 @@ static void collie_init(ram_addr_t ram_size,
 
     s = sa1110_init(collie_binfo.ram_size, cpu_model);
 
-    phys_flash = qemu_ram_alloc(NULL, "collie.fl1", 0x02000000);
     dinfo = drive_get(IF_PFLASH, 0, 0);
-    pflash_cfi01_register(SA_CS0, phys_flash,
+    pflash_cfi01_register(SA_CS0, NULL, "collie.fl1", 0x02000000,
                     dinfo ? dinfo->bdrv : NULL, (64 * 1024),
                     512, 4, 0x00, 0x00, 0x00, 0x00, 0);
 
-    phys_flash = qemu_ram_alloc(NULL, "collie.fl2", 0x02000000);
     dinfo = drive_get(IF_PFLASH, 0, 1);
-    pflash_cfi01_register(SA_CS1, phys_flash,
+    pflash_cfi01_register(SA_CS1, NULL, "collie.fl2", 0x02000000,
                     dinfo ? dinfo->bdrv : NULL, (64 * 1024),
                     512, 4, 0x00, 0x00, 0x00, 0x00, 0);
 
diff --git a/hw/flash.h b/hw/flash.h
index 270be5e..9c9e526 100644
--- a/hw/flash.h
+++ b/hw/flash.h
@@ -1,15 +1,22 @@
 /* NOR flash devices */
+
+#include "memory.h"
+
 typedef struct pflash_t pflash_t;
 
 /* pflash_cfi01.c */
-pflash_t *pflash_cfi01_register(target_phys_addr_t base, ram_addr_t off,
+pflash_t *pflash_cfi01_register(target_phys_addr_t base,
+                                DeviceState *qdev, const char *name,
+                                target_phys_addr_t size,
                                 BlockDriverState *bs,
                                 uint32_t sector_len, int nb_blocs, int width,
                                 uint16_t id0, uint16_t id1,
                                 uint16_t id2, uint16_t id3, int be);
 
 /* pflash_cfi02.c */
-pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
+pflash_t *pflash_cfi02_register(target_phys_addr_t base,
+                                DeviceState *qdev, const char *name,
+                                target_phys_addr_t size,
                                 BlockDriverState *bs, uint32_t sector_len,
                                 int nb_blocs, int nb_mappings, int width,
                                 uint16_t id0, uint16_t id1,
@@ -17,6 +24,8 @@ pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
                                 uint16_t unlock_addr0, uint16_t unlock_addr1,
                                 int be);
 
+MemoryRegion *pflash_cfi01_get_memory(pflash_t *fl);
+
 /* nand.c */
 DeviceState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id);
 void nand_setpins(DeviceState *dev, uint8_t cle, uint8_t ale,
diff --git a/hw/gumstix.c b/hw/gumstix.c
index 853f7e1..b8b76f4 100644
--- a/hw/gumstix.c
+++ b/hw/gumstix.c
@@ -67,8 +67,7 @@ static void connex_init(ram_addr_t ram_size,
 #else
     be = 0;
 #endif
-    if (!pflash_cfi01_register(0x00000000, qemu_ram_alloc(NULL, "connext.rom",
-                                                          connex_rom),
+    if (!pflash_cfi01_register(0x00000000, NULL, "connext.rom", connex_rom,
                                dinfo->bdrv, sector_len, connex_rom / sector_len,
                                2, 0, 0, 0, 0, be)) {
         fprintf(stderr, "qemu: Error registering flash memory.\n");
@@ -106,8 +105,7 @@ static void verdex_init(ram_addr_t ram_size,
 #else
     be = 0;
 #endif
-    if (!pflash_cfi01_register(0x00000000, qemu_ram_alloc(NULL, "verdex.rom",
-                                                          verdex_rom),
+    if (!pflash_cfi01_register(0x00000000, NULL, "verdex.rom", verdex_rom,
                                dinfo->bdrv, sector_len, verdex_rom / sector_len,
                                2, 0, 0, 0, 0, be)) {
         fprintf(stderr, "qemu: Error registering flash memory.\n");
diff --git a/hw/lm32_boards.c b/hw/lm32_boards.c
index d18aad7..e4acac1 100644
--- a/hw/lm32_boards.c
+++ b/hw/lm32_boards.c
@@ -77,7 +77,6 @@ static void lm32_evr_init(ram_addr_t ram_size_not_used,
     CPUState *env;
     DriveInfo *dinfo;
     ram_addr_t phys_ram;
-    ram_addr_t phys_flash;
     qemu_irq *cpu_irq, irq[32];
     ResetInfo *reset_info;
     int i;
@@ -108,10 +107,9 @@ static void lm32_evr_init(ram_addr_t ram_size_not_used,
     phys_ram = qemu_ram_alloc(NULL, "lm32_evr.sdram", ram_size);
     cpu_register_physical_memory(ram_base, ram_size, phys_ram | IO_MEM_RAM);
 
-    phys_flash = qemu_ram_alloc(NULL, "lm32_evr.flash", flash_size);
     dinfo = drive_get(IF_PFLASH, 0, 0);
     /* Spansion S29NS128P */
-    pflash_cfi02_register(flash_base, phys_flash,
+    pflash_cfi02_register(flash_base, NULL, "lm32_evr.flash", flash_size,
                           dinfo ? dinfo->bdrv : NULL, flash_sector_size,
                           flash_size / flash_sector_size, 1, 2,
                           0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1);
@@ -165,7 +163,6 @@ static void lm32_uclinux_init(ram_addr_t ram_size_not_used,
     CPUState *env;
     DriveInfo *dinfo;
     ram_addr_t phys_ram;
-    ram_addr_t phys_flash;
     qemu_irq *cpu_irq, irq[32];
     HWSetup *hw;
     ResetInfo *reset_info;
@@ -203,10 +200,9 @@ static void lm32_uclinux_init(ram_addr_t ram_size_not_used,
     phys_ram = qemu_ram_alloc(NULL, "lm32_uclinux.sdram", ram_size);
     cpu_register_physical_memory(ram_base, ram_size, phys_ram | IO_MEM_RAM);
 
-    phys_flash = qemu_ram_alloc(NULL, "lm32_uclinux.flash", flash_size);
     dinfo = drive_get(IF_PFLASH, 0, 0);
     /* Spansion S29NS128P */
-    pflash_cfi02_register(flash_base, phys_flash,
+    pflash_cfi02_register(flash_base, NULL, "lm32_uclinux.flash", flash_size,
                           dinfo ? dinfo->bdrv : NULL, flash_sector_size,
                           flash_size / flash_sector_size, 1, 2,
                           0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1);
diff --git a/hw/mainstone.c b/hw/mainstone.c
index 4792f0e..c0524d7 100644
--- a/hw/mainstone.c
+++ b/hw/mainstone.c
@@ -126,10 +126,9 @@ static void mainstone_common_init(ram_addr_t ram_size,
             exit(1);
         }
 
-        if (!pflash_cfi01_register(mainstone_flash_base[i],
-                                   qemu_ram_alloc(NULL, i ? "mainstone.flash1" :
-                                                  "mainstone.flash0",
-                                                  MAINSTONE_FLASH),
+        if (!pflash_cfi01_register(mainstone_flash_base[i], NULL,
+                                   i ? "mainstone.flash1" : "mainstone.flash0",
+                                   MAINSTONE_FLASH,
                                    dinfo->bdrv, sector_len,
                                    MAINSTONE_FLASH / sector_len, 4, 0, 0, 0, 0,
                                    be)) {
diff --git a/hw/milkymist.c b/hw/milkymist.c
index 93288c8..a44b80c 100644
--- a/hw/milkymist.c
+++ b/hw/milkymist.c
@@ -82,7 +82,6 @@ milkymist_init(ram_addr_t ram_size_not_used,
     int kernel_size;
     DriveInfo *dinfo;
     ram_addr_t phys_sdram;
-    ram_addr_t phys_flash;
     qemu_irq irq[32], *cpu_irq;
     int i;
     char *bios_filename;
@@ -113,10 +112,9 @@ milkymist_init(ram_addr_t ram_size_not_used,
     cpu_register_physical_memory(sdram_base, sdram_size,
             phys_sdram | IO_MEM_RAM);
 
-    phys_flash = qemu_ram_alloc(NULL, "milkymist.flash", flash_size);
     dinfo = drive_get(IF_PFLASH, 0, 0);
     /* Numonyx JS28F256J3F105 */
-    pflash_cfi01_register(flash_base, phys_flash,
+    pflash_cfi01_register(flash_base, NULL, "milkymist.flash", flash_size,
                           dinfo ? dinfo->bdrv : NULL, flash_sector_size,
                           flash_size / flash_sector_size, 2,
                           0x00, 0x89, 0x00, 0x1d, 1);
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index 86a8ba0..31d443e 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -46,6 +46,7 @@
 #include "elf.h"
 #include "mc146818rtc.h"
 #include "blockdev.h"
+#include "exec-memory.h"
 
 //#define DEBUG_BOARD_INIT
 
@@ -761,8 +762,10 @@ void mips_malta_init (ram_addr_t ram_size,
                       const char *initrd_filename, const char *cpu_model)
 {
     char *filename;
+    pflash_t *fl;
     ram_addr_t ram_offset;
-    ram_addr_t bios_offset;
+    MemoryRegion *system_memory = get_system_memory();
+    MemoryRegion *bios, *bios_alias = g_new(MemoryRegion, 1);
     target_long bios_size;
     int64_t kernel_entry;
     PCIBus *pci_bus;
@@ -811,17 +814,9 @@ void mips_malta_init (ram_addr_t ram_size,
         exit(1);
     }
     ram_offset = qemu_ram_alloc(NULL, "mips_malta.ram", ram_size);
-    bios_offset = qemu_ram_alloc(NULL, "mips_malta.bios", BIOS_SIZE);
-
 
     cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
 
-    /* Map the bios at two physical locations, as on the real board. */
-    cpu_register_physical_memory(0x1e000000LL,
-                                 BIOS_SIZE, bios_offset | IO_MEM_ROM);
-    cpu_register_physical_memory(0x1fc00000LL,
-                                 BIOS_SIZE, bios_offset | IO_MEM_ROM);
-
 #ifdef TARGET_WORDS_BIGENDIAN
     be = 1;
 #else
@@ -833,12 +828,19 @@ void mips_malta_init (ram_addr_t ram_size,
     /* Load firmware in flash / BIOS unless we boot directly into a kernel. */
     if (kernel_filename) {
         /* Write a small bootloader to the flash location. */
+        bios = g_new(MemoryRegion, 1);
+        memory_region_init_ram(bios, NULL, "mips_malta.bios", BIOS_SIZE);
+        memory_region_set_readonly(bios, true);
+        memory_region_init_alias(bios_alias, "bios.1fc", bios, 0, BIOS_SIZE);
+        /* Map the bios at two physical locations, as on the real board. */
+        memory_region_add_subregion(system_memory, 0x1e000000LL, bios);
+        memory_region_add_subregion(system_memory, 0x1fc00000LL, bios_alias);
         loaderparams.ram_size = ram_size;
         loaderparams.kernel_filename = kernel_filename;
         loaderparams.kernel_cmdline = kernel_cmdline;
         loaderparams.initrd_filename = initrd_filename;
         kernel_entry = load_kernel();
-        write_bootloader(env, qemu_get_ram_ptr(bios_offset), kernel_entry);
+        write_bootloader(env, memory_region_get_ram_ptr(bios), kernel_entry);
     } else {
         dinfo = drive_get(IF_PFLASH, 0, fl_idx);
         if (dinfo) {
@@ -847,15 +849,31 @@ void mips_malta_init (ram_addr_t ram_size,
             fl_sectors = bios_size >> 16;
 #ifdef DEBUG_BOARD_INIT
             printf("Register parallel flash %d size " TARGET_FMT_lx " at "
-                   "offset %08lx addr %08llx '%s' %x\n",
-                   fl_idx, bios_size, bios_offset, 0x1e000000LL,
+                   "addr %08llx '%s' %x\n",
+                   fl_idx, bios_size, 0x1e000000LL,
                    bdrv_get_device_name(dinfo->bdrv), fl_sectors);
 #endif
-            pflash_cfi01_register(0x1e000000LL, bios_offset,
-                                  dinfo->bdrv, 65536, fl_sectors,
-                                  4, 0x0000, 0x0000, 0x0000, 0x0000, be);
-            fl_idx++;
+            fl = pflash_cfi01_register(0x1e000000LL,
+                                       NULL, "mips_malta.bios", BIOS_SIZE,
+                                       dinfo->bdrv, 65536, fl_sectors,
+                                       4, 0x0000, 0x0000, 0x0000, 0x0000, be);
+            bios = pflash_cfi01_get_memory(fl);
+            /* Map the bios at two physical locations, as on the real board. */
+            memory_region_init_alias(bios_alias, "bios.1fc",
+                                     bios, 0, BIOS_SIZE);
+            memory_region_add_subregion(system_memory, 0x1fc00000LL,
+                                        bios_alias);
+           fl_idx++;
         } else {
+            bios = g_new(MemoryRegion, 1);
+            memory_region_init_ram(bios, NULL, "mips_malta.bios", BIOS_SIZE);
+            memory_region_set_readonly(bios, true);
+            memory_region_init_alias(bios_alias, "bios.1fc",
+                                     bios, 0, BIOS_SIZE);
+            /* Map the bios at two physical locations, as on the real board. */
+            memory_region_add_subregion(system_memory, 0x1e000000LL, bios);
+            memory_region_add_subregion(system_memory, 0x1fc00000LL,
+                                        bios_alias);
             /* Load a BIOS image. */
             if (bios_name == NULL)
                 bios_name = BIOS_FILENAME;
@@ -878,7 +896,7 @@ void mips_malta_init (ram_addr_t ram_size,
            a neat trick which allows bi-endian firmware. */
 #ifndef TARGET_WORDS_BIGENDIAN
         {
-            uint32_t *addr = qemu_get_ram_ptr(bios_offset);;
+            uint32_t *addr = memory_region_get_ram_ptr(bios);
             uint32_t *end = addr + bios_size;
             while (addr < end) {
                 bswap32s(addr);
@@ -890,7 +908,7 @@ void mips_malta_init (ram_addr_t ram_size,
     /* Board ID = 0x420 (Malta Board with CoreLV)
        XXX: theoretically 0x1e000010 should map to flash and 0x1fc00010 should
        map to the board ID. */
-    stl_p(qemu_get_ram_ptr(bios_offset) + 0x10, 0x00000420);
+    stl_p(memory_region_get_ram_ptr(bios) + 0x10, 0x00000420);
 
     /* Init internal devices */
     cpu_mips_irq_init_cpu(env);
diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c
index 9d90568..5d002c5 100644
--- a/hw/mips_r4k.c
+++ b/hw/mips_r4k.c
@@ -23,6 +23,7 @@
 #include "elf.h"
 #include "mc146818rtc.h"
 #include "blockdev.h"
+#include "exec-memory.h"
 
 #define MAX_IDE_BUS 2
 
@@ -163,7 +164,7 @@ void mips_r4k_init (ram_addr_t ram_size,
 {
     char *filename;
     ram_addr_t ram_offset;
-    ram_addr_t bios_offset;
+    MemoryRegion *bios;
     int bios_size;
     CPUState *env;
     ResetData *reset_info;
@@ -227,15 +228,15 @@ void mips_r4k_init (ram_addr_t ram_size,
     be = 0;
 #endif
     if ((bios_size > 0) && (bios_size <= BIOS_SIZE)) {
-        bios_offset = qemu_ram_alloc(NULL, "mips_r4k.bios", BIOS_SIZE);
-	cpu_register_physical_memory(0x1fc00000, BIOS_SIZE,
-                                     bios_offset | IO_MEM_ROM);
+        bios = g_new(MemoryRegion, 1);
+        memory_region_init_ram(bios, NULL, "mips_r4k.bios", BIOS_SIZE);
+        memory_region_set_readonly(bios, true);
+        memory_region_add_subregion(get_system_memory(), 0x1fc00000, bios);
 
         load_image_targphys(filename, 0x1fc00000, BIOS_SIZE);
     } else if ((dinfo = drive_get(IF_PFLASH, 0, 0)) != NULL) {
         uint32_t mips_rom = 0x00400000;
-        bios_offset = qemu_ram_alloc(NULL, "mips_r4k.bios", mips_rom);
-        if (!pflash_cfi01_register(0x1fc00000, bios_offset,
+        if (!pflash_cfi01_register(0x1fc00000, NULL, "mips_r4k.bios", mips_rom,
                                    dinfo->bdrv, sector_len,
                                    mips_rom / sector_len,
                                    4, 0, 0, 0, 0, be)) {
diff --git a/hw/musicpal.c b/hw/musicpal.c
index 63dd391..ade5a91 100644
--- a/hw/musicpal.c
+++ b/hw/musicpal.c
@@ -1565,16 +1565,16 @@ static void musicpal_init(ram_addr_t ram_size,
          * image is smaller than 32 MB.
          */
 #ifdef TARGET_WORDS_BIGENDIAN
-        pflash_cfi02_register(0-MP_FLASH_SIZE_MAX, qemu_ram_alloc(NULL,
-                              "musicpal.flash", flash_size),
+        pflash_cfi02_register(0-MP_FLASH_SIZE_MAX, NULL,
+                              "musicpal.flash", flash_size,
                               dinfo->bdrv, 0x10000,
                               (flash_size + 0xffff) >> 16,
                               MP_FLASH_SIZE_MAX / flash_size,
                               2, 0x00BF, 0x236D, 0x0000, 0x0000,
                               0x5555, 0x2AAA, 1);
 #else
-        pflash_cfi02_register(0-MP_FLASH_SIZE_MAX, qemu_ram_alloc(NULL,
-                              "musicpal.flash", flash_size),
+        pflash_cfi02_register(0-MP_FLASH_SIZE_MAX, NULL,
+                              "musicpal.flash", flash_size,
                               dinfo->bdrv, 0x10000,
                               (flash_size + 0xffff) >> 16,
                               MP_FLASH_SIZE_MAX / flash_size,
diff --git a/hw/omap_sx1.c b/hw/omap_sx1.c
index a7b687b..15cfbb5 100644
--- a/hw/omap_sx1.c
+++ b/hw/omap_sx1.c
@@ -161,8 +161,8 @@ static void sx1_init(ram_addr_t ram_size,
 #endif
 
     if ((dinfo = drive_get(IF_PFLASH, 0, fl_idx)) != NULL) {
-        if (!pflash_cfi01_register(OMAP_CS0_BASE, qemu_ram_alloc(NULL,
-                                   "omap_sx1.flash0-1", flash_size),
+        if (!pflash_cfi01_register(OMAP_CS0_BASE, NULL,
+                                   "omap_sx1.flash0-1", flash_size,
                                    dinfo->bdrv, sector_size,
                                    flash_size / sector_size,
                                    4, 0, 0, 0, 0, be)) {
@@ -182,8 +182,8 @@ static void sx1_init(ram_addr_t ram_size,
         cpu_register_physical_memory(OMAP_CS1_BASE + flash1_size,
                         OMAP_CS1_SIZE - flash1_size, io);
 
-        if (!pflash_cfi01_register(OMAP_CS1_BASE, qemu_ram_alloc(NULL,
-                                   "omap_sx1.flash1-1", flash1_size),
+        if (!pflash_cfi01_register(OMAP_CS1_BASE, NULL,
+                                   "omap_sx1.flash1-1", flash1_size,
                                    dinfo->bdrv, sector_size,
                                    flash1_size / sector_size,
                                    4, 0, 0, 0, 0, be)) {
diff --git a/hw/petalogix_ml605_mmu.c b/hw/petalogix_ml605_mmu.c
index e3ca310..38db521 100644
--- a/hw/petalogix_ml605_mmu.c
+++ b/hw/petalogix_ml605_mmu.c
@@ -149,7 +149,6 @@ petalogix_ml605_init(ram_addr_t ram_size,
     target_phys_addr_t ddr_base = MEMORY_BASEADDR;
     ram_addr_t phys_lmb_bram;
     ram_addr_t phys_ram;
-    ram_addr_t phys_flash;
     qemu_irq irq[32], *cpu_irq;
 
     /* init CPUs */
@@ -169,11 +168,11 @@ petalogix_ml605_init(ram_addr_t ram_size,
     phys_ram = qemu_ram_alloc(NULL, "petalogix_ml605.ram", ram_size);
     cpu_register_physical_memory(ddr_base, ram_size, phys_ram | IO_MEM_RAM);
 
-    phys_flash = qemu_ram_alloc(NULL, "petalogix_ml605.flash", FLASH_SIZE);
     dinfo = drive_get(IF_PFLASH, 0, 0);
     /* 5th parameter 2 means bank-width
      * 10th paremeter 0 means little-endian */
-    pflash_cfi01_register(FLASH_BASEADDR, phys_flash,
+    pflash_cfi01_register(FLASH_BASEADDR,
+                          NULL, "petalogix_ml605.flash", FLASH_SIZE,
                           dinfo ? dinfo->bdrv : NULL, (64 * 1024),
                           FLASH_SIZE >> 16,
                           2, 0x89, 0x18, 0x0000, 0x0, 0);
diff --git a/hw/petalogix_s3adsp1800_mmu.c b/hw/petalogix_s3adsp1800_mmu.c
index a43fb4c..66fb96d 100644
--- a/hw/petalogix_s3adsp1800_mmu.c
+++ b/hw/petalogix_s3adsp1800_mmu.c
@@ -127,7 +127,6 @@ petalogix_s3adsp1800_init(ram_addr_t ram_size,
     target_phys_addr_t ddr_base = 0x90000000;
     ram_addr_t phys_lmb_bram;
     ram_addr_t phys_ram;
-    ram_addr_t phys_flash;
     qemu_irq irq[32], *cpu_irq;
 
     /* init CPUs */
@@ -148,9 +147,9 @@ petalogix_s3adsp1800_init(ram_addr_t ram_size,
     phys_ram = qemu_ram_alloc(NULL, "petalogix_s3adsp1800.ram", ram_size);
     cpu_register_physical_memory(ddr_base, ram_size, phys_ram | IO_MEM_RAM);
 
-    phys_flash = qemu_ram_alloc(NULL, "petalogix_s3adsp1800.flash", FLASH_SIZE);
     dinfo = drive_get(IF_PFLASH, 0, 0);
-    pflash_cfi01_register(0xa0000000, phys_flash,
+    pflash_cfi01_register(0xa0000000,
+                          NULL, "petalogix_s3adsp1800.flash", FLASH_SIZE,
                           dinfo ? dinfo->bdrv : NULL, (64 * 1024),
                           FLASH_SIZE >> 16,
                           1, 0x89, 0x18, 0x0000, 0x0, 1);
diff --git a/hw/pflash_cfi01.c b/hw/pflash_cfi01.c
index 90e1301..ce48fdf 100644
--- a/hw/pflash_cfi01.c
+++ b/hw/pflash_cfi01.c
@@ -40,6 +40,7 @@
 #include "flash.h"
 #include "block.h"
 #include "qemu-timer.h"
+#include "exec-memory.h"
 
 #define PFLASH_BUG(fmt, ...) \
 do { \
@@ -74,8 +75,7 @@ struct pflash_t {
     target_phys_addr_t counter;
     unsigned int writeblock_size;
     QEMUTimer *timer;
-    ram_addr_t off;
-    int fl_mem;
+    MemoryRegion mem;
     void *storage;
 };
 
@@ -89,8 +89,7 @@ static void pflash_timer (void *opaque)
     if (pfl->bypass) {
         pfl->wcycle = 2;
     } else {
-        cpu_register_physical_memory(pfl->base, pfl->total_len,
-                        pfl->off | IO_MEM_ROMD | pfl->fl_mem);
+        memory_region_rom_device_set_readable(&pfl->mem, true);
         pfl->wcycle = 0;
     }
     pfl->cmd = 0;
@@ -263,7 +262,7 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset,
 
     if (!pfl->wcycle) {
         /* Set the device in I/O access mode */
-        cpu_register_physical_memory(pfl->base, pfl->total_len, pfl->fl_mem);
+        memory_region_rom_device_set_readable(&pfl->mem, false);
     }
 
     switch (pfl->wcycle) {
@@ -422,8 +421,7 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset,
            __func__, offset, pfl->wcycle, pfl->cmd, value);
 
  reset_flash:
-    cpu_register_physical_memory(pfl->base, pfl->total_len,
-                    pfl->off | IO_MEM_ROMD | pfl->fl_mem);
+    memory_region_rom_device_set_readable(&pfl->mem, true);
 
     pfl->bypass = 0;
     pfl->wcycle = 0;
@@ -514,28 +512,20 @@ static void pflash_writel_le(void *opaque, target_phys_addr_t addr,
     pflash_write(pfl, addr, value, 4, 0);
 }
 
-static CPUWriteMemoryFunc * const pflash_write_ops_be[] = {
-    &pflash_writeb_be,
-    &pflash_writew_be,
-    &pflash_writel_be,
+static const MemoryRegionOps pflash_cfi01_ops_be = {
+    .old_mmio = {
+        .read = { pflash_readb_be, pflash_readw_be, pflash_readl_be, },
+        .write = { pflash_writeb_be, pflash_writew_be, pflash_writel_be, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUReadMemoryFunc * const pflash_read_ops_be[] = {
-    &pflash_readb_be,
-    &pflash_readw_be,
-    &pflash_readl_be,
-};
-
-static CPUWriteMemoryFunc * const pflash_write_ops_le[] = {
-    &pflash_writeb_le,
-    &pflash_writew_le,
-    &pflash_writel_le,
-};
-
-static CPUReadMemoryFunc * const pflash_read_ops_le[] = {
-    &pflash_readb_le,
-    &pflash_readw_le,
-    &pflash_readl_le,
+static const MemoryRegionOps pflash_cfi01_ops_le = {
+    .old_mmio = {
+        .read = { pflash_readb_le, pflash_readw_le, pflash_readl_le, },
+        .write = { pflash_writeb_le, pflash_writew_le, pflash_writel_le, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 /* Count trailing zeroes of a 32 bits quantity */
@@ -574,12 +564,13 @@ static int ctz32 (uint32_t n)
     return ret;
 }
 
-pflash_t *pflash_cfi01_register(target_phys_addr_t base, ram_addr_t off,
+pflash_t *pflash_cfi01_register(target_phys_addr_t base,
+                                DeviceState *qdev, const char *name,
+                                target_phys_addr_t size,
                                 BlockDriverState *bs, uint32_t sector_len,
                                 int nb_blocs, int width,
                                 uint16_t id0, uint16_t id1,
-                                uint16_t id2, uint16_t id3,
-                                int be)
+                                uint16_t id2, uint16_t id3, int be)
 {
     pflash_t *pfl;
     target_phys_addr_t total_len;
@@ -596,27 +587,19 @@ pflash_t *pflash_cfi01_register(target_phys_addr_t base, ram_addr_t off,
 
     pfl = g_malloc0(sizeof(pflash_t));
 
-    /* FIXME: Allocate ram ourselves.  */
-    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,
-                                             DEVICE_NATIVE_ENDIAN);
-    } else {
-        pfl->fl_mem = cpu_register_io_memory(pflash_read_ops_le,
-                                             pflash_write_ops_le, pfl,
-                                             DEVICE_NATIVE_ENDIAN);
-    }
-    pfl->off = off;
-    cpu_register_physical_memory(base, total_len,
-                    off | pfl->fl_mem | IO_MEM_ROMD);
+    memory_region_init_rom_device(
+        &pfl->mem, be ? &pflash_cfi01_ops_be : &pflash_cfi01_ops_le, pfl,
+        qdev, name, size);
+    pfl->storage = memory_region_get_ram_ptr(&pfl->mem);
+    memory_region_add_subregion(get_system_memory(), base, &pfl->mem);
 
     pfl->bs = bs;
     if (pfl->bs) {
         /* read the initial flash content */
         ret = bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9);
         if (ret < 0) {
-            cpu_unregister_io_memory(pfl->fl_mem);
+            memory_region_del_subregion(get_system_memory(), &pfl->mem);
+            memory_region_destroy(&pfl->mem);
             g_free(pfl);
             return NULL;
         }
@@ -724,3 +707,8 @@ pflash_t *pflash_cfi01_register(target_phys_addr_t base, ram_addr_t off,
 
     return pfl;
 }
+
+MemoryRegion *pflash_cfi01_get_memory(pflash_t *fl)
+{
+    return &fl->mem;
+}
diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c
index ac5115e..4dbec87 100644
--- a/hw/pflash_cfi02.c
+++ b/hw/pflash_cfi02.c
@@ -39,6 +39,7 @@
 #include "flash.h"
 #include "qemu-timer.h"
 #include "block.h"
+#include "exec-memory.h"
 
 //#define PFLASH_DEBUG
 #ifdef PFLASH_DEBUG
@@ -69,25 +70,38 @@ struct pflash_t {
     uint8_t cfi_len;
     uint8_t cfi_table[0x52];
     QEMUTimer *timer;
-    ram_addr_t off;
-    int fl_mem;
+    /* The device replicates the flash memory across its memory space.  Emulate
+     * that by having a container (.mem) filled with an array of aliases
+     * (.mem_mappings) pointing to the flash memory (.orig_mem).
+     */
+    MemoryRegion mem;
+    MemoryRegion *mem_mappings;    /* array; one per mapping */
+    MemoryRegion orig_mem;
     int rom_mode;
     int read_counter; /* used for lazy switch-back to rom mode */
     void *storage;
 };
 
-static void pflash_register_memory(pflash_t *pfl, int rom_mode)
+/*
+ * Set up replicated mappings of the same region.
+ */
+static void pflash_setup_mappings(pflash_t *pfl)
 {
-    unsigned long phys_offset = pfl->fl_mem;
-    int i;
-
-    if (rom_mode)
-        phys_offset |= pfl->off | IO_MEM_ROMD;
-    pfl->rom_mode = rom_mode;
+    unsigned i;
+    target_phys_addr_t size = memory_region_size(&pfl->orig_mem);
+
+    memory_region_init(&pfl->mem, "pflash", pfl->mappings * size);
+    pfl->mem_mappings = g_new(MemoryRegion, pfl->mappings);
+    for (i = 0; i < pfl->mappings; ++i) {
+        memory_region_init_alias(&pfl->mem_mappings[i], "pflash-alias",
+                                 &pfl->orig_mem, 0, size);
+        memory_region_add_subregion(&pfl->mem, i * size, &pfl->mem_mappings[i]);
+    }
+}
 
-    for (i = 0; i < pfl->mappings; i++)
-        cpu_register_physical_memory(pfl->base + i * pfl->chip_len,
-                                     pfl->chip_len, phys_offset);
+static void pflash_register_memory(pflash_t *pfl, int rom_mode)
+{
+    memory_region_rom_device_set_readable(&pfl->orig_mem, rom_mode);
 }
 
 static void pflash_timer (void *opaque)
@@ -538,28 +552,20 @@ static void pflash_writel_le(void *opaque, target_phys_addr_t addr,
     pflash_write(pfl, addr, value, 4, 0);
 }
 
-static CPUWriteMemoryFunc * const pflash_write_ops_be[] = {
-    &pflash_writeb_be,
-    &pflash_writew_be,
-    &pflash_writel_be,
-};
-
-static CPUReadMemoryFunc * const pflash_read_ops_be[] = {
-    &pflash_readb_be,
-    &pflash_readw_be,
-    &pflash_readl_be,
+static const MemoryRegionOps pflash_cfi02_ops_be = {
+    .old_mmio = {
+        .read = { pflash_readb_be, pflash_readw_be, pflash_readl_be, },
+        .write = { pflash_writeb_be, pflash_writew_be, pflash_writel_be, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const pflash_write_ops_le[] = {
-    &pflash_writeb_le,
-    &pflash_writew_le,
-    &pflash_writel_le,
-};
-
-static CPUReadMemoryFunc * const pflash_read_ops_le[] = {
-    &pflash_readb_le,
-    &pflash_readw_le,
-    &pflash_readl_le,
+static const MemoryRegionOps pflash_cfi02_ops_le = {
+    .old_mmio = {
+        .read = { pflash_readb_le, pflash_readw_le, pflash_readl_le, },
+        .write = { pflash_writeb_le, pflash_writew_le, pflash_writel_le, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 /* Count trailing zeroes of a 32 bits quantity */
@@ -598,7 +604,9 @@ static int ctz32 (uint32_t n)
     return ret;
 }
 
-pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
+pflash_t *pflash_cfi02_register(target_phys_addr_t base,
+                                DeviceState *qdev, const char *name,
+                                target_phys_addr_t size,
                                 BlockDriverState *bs, uint32_t sector_len,
                                 int nb_blocs, int nb_mappings, int width,
                                 uint16_t id0, uint16_t id1,
@@ -618,32 +626,25 @@ pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
         return NULL;
 #endif
     pfl = g_malloc0(sizeof(pflash_t));
-    /* FIXME: Allocate ram ourselves.  */
-    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, DEVICE_NATIVE_ENDIAN);
-    } else {
-        pfl->fl_mem = cpu_register_io_memory(pflash_read_ops_le,
-                                             pflash_write_ops_le,
-                                             pfl, DEVICE_NATIVE_ENDIAN);
-    }
-    pfl->off = off;
+    memory_region_init_rom_device(
+        &pfl->orig_mem, be ? &pflash_cfi02_ops_be : &pflash_cfi02_ops_le, pfl,
+        qdev, name, size);
+    pfl->storage = memory_region_get_ram_ptr(&pfl->orig_mem);
     pfl->base = base;
     pfl->chip_len = chip_len;
     pfl->mappings = nb_mappings;
-    pflash_register_memory(pfl, 1);
     pfl->bs = bs;
     if (pfl->bs) {
         /* read the initial flash content */
         ret = bdrv_read(pfl->bs, 0, pfl->storage, chip_len >> 9);
         if (ret < 0) {
-            cpu_unregister_io_memory(pfl->fl_mem);
             g_free(pfl);
             return NULL;
         }
     }
+    pflash_setup_mappings(pfl);
+    pfl->rom_mode = 1;
+    memory_region_add_subregion(get_system_memory(), pfl->base, &pfl->mem);
 #if 0 /* XXX: there should be a bit to set up read-only,
        *      the same way the hardware does (with WP pin).
        */
diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c
index dec165e..e6c8ac6 100644
--- a/hw/ppc405_boards.c
+++ b/hw/ppc405_boards.c
@@ -32,6 +32,7 @@
 #include "qemu-log.h"
 #include "loader.h"
 #include "blockdev.h"
+#include "exec-memory.h"
 
 #define BIOS_FILENAME "ppc405_rom.bin"
 #define BIOS_SIZE (2048 * 1024)
@@ -181,7 +182,8 @@ static void ref405ep_init (ram_addr_t ram_size,
     ppc4xx_bd_info_t bd;
     CPUPPCState *env;
     qemu_irq *pic;
-    ram_addr_t sram_offset, bios_offset, bdloc;
+    MemoryRegion *bios;
+    ram_addr_t sram_offset, bdloc;
     MemoryRegion *ram_memories = g_malloc(2 * sizeof(*ram_memories));
     target_phys_addr_t ram_bases[2], ram_sizes[2];
     target_ulong sram_size;
@@ -224,15 +226,15 @@ static void ref405ep_init (ram_addr_t ram_size,
     dinfo = drive_get(IF_PFLASH, 0, fl_idx);
     if (dinfo) {
         bios_size = bdrv_getlength(dinfo->bdrv);
-        bios_offset = qemu_ram_alloc(NULL, "ef405ep.bios", bios_size);
         fl_sectors = (bios_size + 65535) >> 16;
 #ifdef DEBUG_BOARD_INIT
         printf("Register parallel flash %d size %lx"
-               " at offset %08lx addr %lx '%s' %d\n",
-               fl_idx, bios_size, bios_offset, -bios_size,
+               " at addr %lx '%s' %d\n",
+               fl_idx, bios_size, -bios_size,
                bdrv_get_device_name(dinfo->bdrv), fl_sectors);
 #endif
-        pflash_cfi02_register((uint32_t)(-bios_size), bios_offset,
+        pflash_cfi02_register((uint32_t)(-bios_size),
+                              NULL, "ef405ep.bios", bios_size,
                               dinfo->bdrv, 65536, fl_sectors, 1,
                               2, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA,
                               1);
@@ -243,12 +245,13 @@ static void ref405ep_init (ram_addr_t ram_size,
 #ifdef DEBUG_BOARD_INIT
         printf("Load BIOS from file\n");
 #endif
-        bios_offset = qemu_ram_alloc(NULL, "ef405ep.bios", BIOS_SIZE);
+        bios = g_new(MemoryRegion, 1);
+        memory_region_init_ram(bios, NULL, "ef405ep.bios", BIOS_SIZE);
         if (bios_name == NULL)
             bios_name = BIOS_FILENAME;
         filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
         if (filename) {
-            bios_size = load_image(filename, qemu_get_ram_ptr(bios_offset));
+            bios_size = load_image(filename, memory_region_get_ram_ptr(bios));
             g_free(filename);
         } else {
             bios_size = -1;
@@ -259,8 +262,9 @@ static void ref405ep_init (ram_addr_t ram_size,
             exit(1);
         }
         bios_size = (bios_size + 0xfff) & ~0xfff;
-        cpu_register_physical_memory((uint32_t)(-bios_size),
-                                     bios_size, bios_offset | IO_MEM_ROM);
+        memory_region_set_readonly(bios, true);
+        memory_region_add_subregion(get_system_memory(),
+                                    (uint32_t)(-bios_size), bios);
     }
     /* Register FPGA */
 #ifdef DEBUG_BOARD_INIT
@@ -507,7 +511,7 @@ static void taihu_405ep_init(ram_addr_t ram_size,
 {
     char *filename;
     qemu_irq *pic;
-    ram_addr_t bios_offset;
+    MemoryRegion *bios;
     MemoryRegion *ram_memories = g_malloc(2 * sizeof(*ram_memories));
     target_phys_addr_t ram_bases[2], ram_sizes[2];
     long bios_size;
@@ -544,14 +548,14 @@ static void taihu_405ep_init(ram_addr_t ram_size,
         /* XXX: should check that size is 2MB */
         //        bios_size = 2 * 1024 * 1024;
         fl_sectors = (bios_size + 65535) >> 16;
-        bios_offset = qemu_ram_alloc(NULL, "taihu_405ep.bios", bios_size);
 #ifdef DEBUG_BOARD_INIT
         printf("Register parallel flash %d size %lx"
-               " at offset %08lx addr %lx '%s' %d\n",
-               fl_idx, bios_size, bios_offset, -bios_size,
+               " at addr %lx '%s' %d\n",
+               fl_idx, bios_size, -bios_size,
                bdrv_get_device_name(dinfo->bdrv), fl_sectors);
 #endif
-        pflash_cfi02_register((uint32_t)(-bios_size), bios_offset,
+        pflash_cfi02_register((uint32_t)(-bios_size),
+                              NULL, "taihu_405ep.bios", bios_size,
                               dinfo->bdrv, 65536, fl_sectors, 1,
                               4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA,
                               1);
@@ -564,10 +568,11 @@ static void taihu_405ep_init(ram_addr_t ram_size,
 #endif
         if (bios_name == NULL)
             bios_name = BIOS_FILENAME;
-        bios_offset = qemu_ram_alloc(NULL, "taihu_405ep.bios", BIOS_SIZE);
+        bios = g_new(MemoryRegion, 1);
+        memory_region_init_ram(bios, NULL, "taihu_405ep.bios", BIOS_SIZE);
         filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
         if (filename) {
-            bios_size = load_image(filename, qemu_get_ram_ptr(bios_offset));
+            bios_size = load_image(filename, memory_region_get_ram_ptr(bios));
             g_free(filename);
         } else {
             bios_size = -1;
@@ -578,8 +583,9 @@ static void taihu_405ep_init(ram_addr_t ram_size,
             exit(1);
         }
         bios_size = (bios_size + 0xfff) & ~0xfff;
-        cpu_register_physical_memory((uint32_t)(-bios_size),
-                                     bios_size, bios_offset | IO_MEM_ROM);
+        memory_region_set_readonly(bios, true);
+        memory_region_add_subregion(get_system_memory(), (uint32_t)(-bios_size),
+                                    bios);
     }
     /* Register Linux flash */
     dinfo = drive_get(IF_PFLASH, 0, fl_idx);
@@ -590,12 +596,11 @@ static void taihu_405ep_init(ram_addr_t ram_size,
         fl_sectors = (bios_size + 65535) >> 16;
 #ifdef DEBUG_BOARD_INIT
         printf("Register parallel flash %d size %lx"
-               " at offset %08lx  addr " TARGET_FMT_lx " '%s'\n",
-               fl_idx, bios_size, bios_offset, (target_ulong)0xfc000000,
+               " at addr " TARGET_FMT_lx " '%s'\n",
+               fl_idx, bios_size, (target_ulong)0xfc000000,
                bdrv_get_device_name(dinfo->bdrv));
 #endif
-        bios_offset = qemu_ram_alloc(NULL, "taihu_405ep.flash", bios_size);
-        pflash_cfi02_register(0xfc000000, bios_offset,
+        pflash_cfi02_register(0xfc000000, NULL, "taihu_405ep.flash", bios_size,
                               dinfo->bdrv, 65536, fl_sectors, 1,
                               4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA,
                               1);
diff --git a/hw/r2d.c b/hw/r2d.c
index 771f3d0..b8b0df3 100644
--- a/hw/r2d.c
+++ b/hw/r2d.c
@@ -267,7 +267,7 @@ static void r2d_init(ram_addr_t ram_size,
 
     /* onboard flash memory */
     dinfo = drive_get(IF_PFLASH, 0, 0);
-    pflash_cfi02_register(0x0, qemu_ram_alloc(NULL, "r2d.flash", FLASH_SIZE),
+    pflash_cfi02_register(0x0, NULL, "r2d.flash", FLASH_SIZE,
                           dinfo ? dinfo->bdrv : NULL, (16 * 1024),
                           FLASH_SIZE >> 16,
                           1, 4, 0x0000, 0x0000, 0x0000, 0x0000,
diff --git a/hw/virtex_ml507.c b/hw/virtex_ml507.c
index 333050c..7459b0b 100644
--- a/hw/virtex_ml507.c
+++ b/hw/virtex_ml507.c
@@ -196,7 +196,6 @@ static void virtex_init(ram_addr_t ram_size,
     target_phys_addr_t ram_base = 0;
     DriveInfo *dinfo;
     ram_addr_t phys_ram;
-    ram_addr_t phys_flash;
     qemu_irq irq[32], *cpu_irq;
     clk_setup_t clk_setup[7];
     int kernel_size;
@@ -215,9 +214,8 @@ static void virtex_init(ram_addr_t ram_size,
     phys_ram = qemu_ram_alloc(NULL, "ram", ram_size);
     cpu_register_physical_memory(ram_base, ram_size, phys_ram | IO_MEM_RAM);
 
-    phys_flash = qemu_ram_alloc(NULL, "virtex.flash", FLASH_SIZE);
     dinfo = drive_get(IF_PFLASH, 0, 0);
-    pflash_cfi01_register(0xfc000000, phys_flash,
+    pflash_cfi01_register(0xfc000000, NULL, "virtex.flash", FLASH_SIZE,
                           dinfo ? dinfo->bdrv : NULL, (64 * 1024),
                           FLASH_SIZE >> 16,
                           1, 0x89, 0x18, 0x0000, 0x0, 1);
diff --git a/hw/z2.c b/hw/z2.c
index f93a1bf..b6ae608 100644
--- a/hw/z2.c
+++ b/hw/z2.c
@@ -305,7 +305,7 @@ static void z2_init(ram_addr_t ram_size,
     }
 
     if (!pflash_cfi01_register(Z2_FLASH_BASE,
-                               qemu_ram_alloc(NULL, "z2.flash0", Z2_FLASH_SIZE),
+                               NULL, "z2.flash0", Z2_FLASH_SIZE,
                                dinfo->bdrv, sector_len,
                                Z2_FLASH_SIZE / sector_len, 4, 0, 0, 0, 0,
                                be)) {
commit ccbecf6237db9eed57923b961d48a75c77c7aebd
Author: Avi Kivity <avi at redhat.com>
Date:   Wed Aug 3 18:55:00 2011 +0300

    Makefile.hw: allow hw/ files to include glib headers
    
    Reviewed-by: Richard Henderson  <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/Makefile.hw b/Makefile.hw
index 659e441..63eb7e4 100644
--- a/Makefile.hw
+++ b/Makefile.hw
@@ -10,6 +10,7 @@ include $(SRC_PATH)/rules.mak
 $(call set-vpath, $(SRC_PATH):$(SRC_PATH)/hw)
 
 QEMU_CFLAGS+=-I..
+QEMU_CFLAGS += $(GLIB_CFLAGS)
 
 include $(SRC_PATH)/Makefile.objs
 
commit 72124c01c614ab114134a42c1d8147fc7adeeb8c
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 1 11:04:39 2011 +0300

    piix_pci: wrap memory update in a transaction
    
    The code will remap all PAMs, even if just one is updated, resulting
    in reduced performance.  Wrap in a transaction to detect that those
    other PAMs have not changed.
    
    Reviewed-by: Richard Henderson  <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index f892994..8f6ea42 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -142,6 +142,7 @@ static void i440fx_update_memory_mappings(PCII440FXState *d)
     int i, r;
     uint32_t smram;
 
+    memory_region_transaction_begin();
     update_pam(d, 0xf0000, 0x100000, (d->dev.config[I440FX_PAM] >> 4) & 3,
                &d->pam_regions[0]);
     for(i = 0; i < 12; i++) {
@@ -162,6 +163,7 @@ static void i440fx_update_memory_mappings(PCII440FXState *d)
             d->smram_enabled = false;
         }
     }
+    memory_region_transaction_commit();
 }
 
 static void i440fx_set_smm(int val, void *arg)
commit 64c048f4a86d92078970ca5d817fd6411430b6a0
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 1 11:03:42 2011 +0300

    cirrus: wrap memory update in a transaction
    
    This prevents spurious unmapping and remapping of the vga windows,
    which reduces performance.
    
    Reviewed-by: Richard Henderson  <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index 4d0ef0d..ec7ea82 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -2424,6 +2424,7 @@ static void cirrus_update_memory_access(CirrusVGAState *s)
 {
     unsigned mode;
 
+    memory_region_transaction_begin();
     if ((s->vga.sr[0x17] & 0x44) == 0x44) {
         goto generic_io;
     } else if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
@@ -2443,6 +2444,7 @@ static void cirrus_update_memory_access(CirrusVGAState *s)
             unmap_linear_vram(s);
         }
     }
+    memory_region_transaction_commit();
 }
 
 
commit a4911d642532f8ca1c1353e47de0ec0d5b19ef86
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Jul 25 15:07:22 2011 +0300

    leon3: convert to memory API
    
    Reviewed-by: Richard Henderson  <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/leon3.c b/hw/leon3.c
index a62a941..607ec85 100644
--- a/hw/leon3.c
+++ b/hw/leon3.c
@@ -29,6 +29,7 @@
 #include "loader.h"
 #include "elf.h"
 #include "trace.h"
+#include "exec-memory.h"
 
 #include "grlib.h"
 
@@ -100,7 +101,9 @@ static void leon3_generic_hw_init(ram_addr_t  ram_size,
                                   const char *cpu_model)
 {
     CPUState   *env;
-    ram_addr_t  ram_offset, prom_offset;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *prom = g_new(MemoryRegion, 1);
     int         ret;
     char       *filename;
     qemu_irq   *cpu_irqs = NULL;
@@ -139,14 +142,14 @@ static void leon3_generic_hw_init(ram_addr_t  ram_size,
         exit(1);
     }
 
-    ram_offset = qemu_ram_alloc(NULL, "leon3.ram", ram_size);
-    cpu_register_physical_memory(0x40000000, ram_size, ram_offset | IO_MEM_RAM);
+    memory_region_init_ram(ram, NULL, "leon3.ram", ram_size);
+    memory_region_add_subregion(address_space_mem, 0x40000000, ram);
 
     /* Allocate BIOS */
     prom_size = 8 * 1024 * 1024; /* 8Mb */
-    prom_offset = qemu_ram_alloc(NULL, "Leon3.bios", prom_size);
-    cpu_register_physical_memory(0x00000000, prom_size,
-                                 prom_offset | IO_MEM_ROM);
+    memory_region_init_ram(prom, NULL, "Leon3.bios", prom_size);
+    memory_region_set_readonly(prom, true);
+    memory_region_add_subregion(address_space_mem, 0x00000000, prom);
 
     /* Load boot prom */
     if (bios_name == NULL) {
commit 211adf4d51c2540915bf1d970fcb2a425e37cbd5
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Jul 25 15:03:19 2011 +0300

    integratorcp: convert to memory API (RAM/flash only)
    
    Reviewed-by: Richard Henderson  <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/integratorcp.c b/hw/integratorcp.c
index 2814108..3c8982e 100644
--- a/hw/integratorcp.c
+++ b/hw/integratorcp.c
@@ -13,11 +13,13 @@
 #include "boards.h"
 #include "arm-misc.h"
 #include "net.h"
+#include "exec-memory.h"
 
 typedef struct {
     SysBusDevice busdev;
     uint32_t memsz;
-    uint32_t flash_offset;
+    MemoryRegion flash;
+    bool flash_mapped;
     uint32_t cm_osc;
     uint32_t cm_ctrl;
     uint32_t cm_lock;
@@ -108,9 +110,15 @@ static uint32_t integratorcm_read(void *opaque, target_phys_addr_t offset)
 static void integratorcm_do_remap(integratorcm_state *s, int flash)
 {
     if (flash) {
-        cpu_register_physical_memory(0, 0x100000, IO_MEM_RAM);
+        if (s->flash_mapped) {
+            sysbus_del_memory(&s->busdev, &s->flash);
+            s->flash_mapped = false;
+        }
     } else {
-        cpu_register_physical_memory(0, 0x100000, s->flash_offset | IO_MEM_RAM);
+        if (!s->flash_mapped) {
+            sysbus_add_memory_overlap(&s->busdev, 0, &s->flash, 1);
+            s->flash_mapped = true;
+        }
     }
     //??? tlb_flush (cpu_single_env, 1);
 }
@@ -252,7 +260,8 @@ static int integratorcm_init(SysBusDevice *dev)
     }
     memcpy(integrator_spd + 73, "QEMU-MEMORY", 11);
     s->cm_init = 0x00000112;
-    s->flash_offset = qemu_ram_alloc(NULL, "integrator.flash", 0x100000);
+    memory_region_init_ram(&s->flash, NULL, "integrator.flash", 0x100000);
+    s->flash_mapped = false;
 
     iomemtype = cpu_register_io_memory(integratorcm_readfn,
                                        integratorcm_writefn, s,
@@ -456,7 +465,9 @@ static void integratorcp_init(ram_addr_t ram_size,
                      const char *initrd_filename, const char *cpu_model)
 {
     CPUState *env;
-    ram_addr_t ram_offset;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
     qemu_irq pic[32];
     qemu_irq *cpu_pic;
     DeviceState *dev;
@@ -469,13 +480,14 @@ static void integratorcp_init(ram_addr_t ram_size,
         fprintf(stderr, "Unable to find CPU definition\n");
         exit(1);
     }
-    ram_offset = qemu_ram_alloc(NULL, "integrator.ram", ram_size);
+    memory_region_init_ram(ram, NULL, "integrator.ram", ram_size);
     /* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash.  */
     /* ??? RAM should repeat to fill physical memory space.  */
     /* SDRAM at address zero*/
-    cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
+    memory_region_add_subregion(address_space_mem, 0, ram);
     /* And again at address 0x80000000 */
-    cpu_register_physical_memory(0x80000000, ram_size, ram_offset | IO_MEM_RAM);
+    memory_region_init_alias(ram_alias, "ram.alias", ram, 0, ram_size);
+    memory_region_add_subregion(address_space_mem, 0x80000000, ram_alias);
 
     dev = qdev_create(NULL, "integrator_core");
     qdev_prop_set_uint32(dev, "memsz", ram_size >> 20);
commit d40b2af8baca0a400ff7a3f75199f083ff0babff
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Jul 25 15:02:17 2011 +0300

    sysbus: add sysbus_add_memory_overlap()
    
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/sysbus.c b/hw/sysbus.c
index 02b4e49..4fab5a4 100644
--- a/hw/sysbus.c
+++ b/hw/sysbus.c
@@ -268,6 +268,13 @@ void sysbus_add_memory(SysBusDevice *dev, target_phys_addr_t addr,
     memory_region_add_subregion(get_system_memory(), addr, mem);
 }
 
+void sysbus_add_memory_overlap(SysBusDevice *dev, target_phys_addr_t addr,
+                               MemoryRegion *mem, unsigned priority)
+{
+    memory_region_add_subregion_overlap(get_system_memory(), addr, mem,
+                                        priority);
+}
+
 void sysbus_del_memory(SysBusDevice *dev, MemoryRegion *mem)
 {
     memory_region_del_subregion(get_system_memory(), mem);
diff --git a/hw/sysbus.h b/hw/sysbus.h
index e14055f..6c36537 100644
--- a/hw/sysbus.h
+++ b/hw/sysbus.h
@@ -60,6 +60,8 @@ void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq);
 void sysbus_mmio_map(SysBusDevice *dev, int n, target_phys_addr_t addr);
 void sysbus_add_memory(SysBusDevice *dev, target_phys_addr_t addr,
                        MemoryRegion *mem);
+void sysbus_add_memory_overlap(SysBusDevice *dev, target_phys_addr_t addr,
+                               MemoryRegion *mem, unsigned priority);
 void sysbus_del_memory(SysBusDevice *dev, MemoryRegion *mem);
 void sysbus_add_io(SysBusDevice *dev, target_phys_addr_t addr,
                    MemoryRegion *mem);
commit b0e3d5ac2fdcb45650d728ed6895e1241cf625af
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Jul 25 14:32:34 2011 +0300

    axis_dev88: convert to memory API (RAM only)
    
    Reviewed-by: Richard Henderson  <rth at twiddle.net>
    Acked-by: Edgar E. Iglesias <edgar.iglesias at gmail.com>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/axis_dev88.c b/hw/axis_dev88.c
index 06200e2..73eb39d 100644
--- a/hw/axis_dev88.c
+++ b/hw/axis_dev88.c
@@ -31,6 +31,7 @@
 #include "elf.h"
 #include "cris-boot.h"
 #include "blockdev.h"
+#include "exec-memory.h"
 
 #define D(x)
 #define DNAND(x)
@@ -259,8 +260,9 @@ void axisdev88_init (ram_addr_t ram_size,
     int i;
     int nand_regs;
     int gpio_regs;
-    ram_addr_t phys_ram;
-    ram_addr_t phys_intmem;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
+    MemoryRegion *phys_intmem = g_new(MemoryRegion, 1);
 
     /* init CPUs */
     if (cpu_model == NULL) {
@@ -269,15 +271,13 @@ void axisdev88_init (ram_addr_t ram_size,
     env = cpu_init(cpu_model);
 
     /* allocate RAM */
-    phys_ram = qemu_ram_alloc(NULL, "axisdev88.ram", ram_size);
-    cpu_register_physical_memory(0x40000000, ram_size, phys_ram | IO_MEM_RAM);
+    memory_region_init_ram(phys_ram, NULL, "axisdev88.ram", ram_size);
+    memory_region_add_subregion(address_space_mem, 0x40000000, phys_ram);
 
     /* The ETRAX-FS has 128Kb on chip ram, the docs refer to it as the 
        internal memory.  */
-    phys_intmem = qemu_ram_alloc(NULL, "axisdev88.chipram", INTMEM_SIZE);
-    cpu_register_physical_memory(0x38000000, INTMEM_SIZE,
-                                 phys_intmem | IO_MEM_RAM);
-
+    memory_region_init_ram(phys_intmem, NULL, "axisdev88.chipram", INTMEM_SIZE);
+    memory_region_add_subregion(address_space_mem, 0x38000000, phys_intmem);
 
       /* Attach a NAND flash to CS1.  */
     nand = drive_get(IF_MTD, 0, 0);
commit 7d6f78cfacf702d902951924cb437ef2460b36ce
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Jul 25 14:27:01 2011 +0300

    armv7m: convert to memory API
    
    Reviewed-by: Richard Henderson  <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/arm-misc.h b/hw/arm-misc.h
index f8a7472..af403a1 100644
--- a/hw/arm-misc.h
+++ b/hw/arm-misc.h
@@ -11,13 +11,16 @@
 #ifndef ARM_MISC_H
 #define ARM_MISC_H 1
 
+#include "memory.h"
+
 /* The CPU is also modeled as an interrupt controller.  */
 #define ARM_PIC_CPU_IRQ 0
 #define ARM_PIC_CPU_FIQ 1
 qemu_irq *arm_pic_init_cpu(CPUState *env);
 
 /* armv7m.c */
-qemu_irq *armv7m_init(int flash_size, int sram_size,
+qemu_irq *armv7m_init(MemoryRegion *address_space_mem,
+                      int flash_size, int sram_size,
                       const char *kernel_filename, const char *cpu_model);
 
 /* arm_boot.c */
diff --git a/hw/armv7m.c b/hw/armv7m.c
index a932f16..28d41b8 100644
--- a/hw/armv7m.c
+++ b/hw/armv7m.c
@@ -156,7 +156,8 @@ static void armv7m_reset(void *opaque)
    flash_size and sram_size are in kb.
    Returns the NVIC array.  */
 
-qemu_irq *armv7m_init(int flash_size, int sram_size,
+qemu_irq *armv7m_init(MemoryRegion *address_space_mem,
+                      int flash_size, int sram_size,
                       const char *kernel_filename, const char *cpu_model)
 {
     CPUState *env;
@@ -169,6 +170,9 @@ qemu_irq *armv7m_init(int flash_size, int sram_size,
     uint64_t lowaddr;
     int i;
     int big_endian;
+    MemoryRegion *sram = g_new(MemoryRegion, 1);
+    MemoryRegion *flash = g_new(MemoryRegion, 1);
+    MemoryRegion *hack = g_new(MemoryRegion, 1);
 
     flash_size *= 1024;
     sram_size *= 1024;
@@ -194,12 +198,11 @@ qemu_irq *armv7m_init(int flash_size, int sram_size,
 #endif
 
     /* Flash programming is done via the SCU, so pretend it is ROM.  */
-    cpu_register_physical_memory(0, flash_size,
-                                 qemu_ram_alloc(NULL, "armv7m.flash",
-                                                flash_size) | IO_MEM_ROM);
-    cpu_register_physical_memory(0x20000000, sram_size,
-                                 qemu_ram_alloc(NULL, "armv7m.sram",
-                                                sram_size) | IO_MEM_RAM);
+    memory_region_init_ram(flash, NULL, "armv7m.flash", flash_size);
+    memory_region_set_readonly(flash, true);
+    memory_region_add_subregion(address_space_mem, 0, flash);
+    memory_region_init_ram(sram, NULL, "armv7m.sram", sram_size);
+    memory_region_add_subregion(address_space_mem, 0x20000000, sram);
     armv7m_bitband_init();
 
     nvic = qdev_create(NULL, "armv7m_nvic");
@@ -232,9 +235,8 @@ qemu_irq *armv7m_init(int flash_size, int sram_size,
     /* Hack to map an additional page of ram at the top of the address
        space.  This stops qemu complaining about executing code outside RAM
        when returning from an exception.  */
-    cpu_register_physical_memory(0xfffff000, 0x1000,
-                                 qemu_ram_alloc(NULL, "armv7m.hack", 
-                                                0x1000) | IO_MEM_RAM);
+    memory_region_init_ram(hack, NULL, "armv7m.hack", 0x1000);
+    memory_region_add_subregion(address_space_mem, 0xfffff000, hack);
 
     qemu_register_reset(armv7m_reset, env);
     return pic;
diff --git a/hw/stellaris.c b/hw/stellaris.c
index 9b0db7f..2bf1c23 100644
--- a/hw/stellaris.c
+++ b/hw/stellaris.c
@@ -15,6 +15,7 @@
 #include "i2c.h"
 #include "net.h"
 #include "boards.h"
+#include "exec-memory.h"
 
 #define GPIO_A 0
 #define GPIO_B 1
@@ -1260,6 +1261,7 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model,
         0x40024000, 0x40025000, 0x40026000};
     static const int gpio_irq[7] = {0, 1, 2, 3, 4, 30, 31};
 
+    MemoryRegion *address_space_mem = get_system_memory();
     qemu_irq *pic;
     DeviceState *gpio_dev[7];
     qemu_irq gpio_in[7][8];
@@ -1274,7 +1276,8 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model,
 
     flash_size = ((board->dc0 & 0xffff) + 1) << 1;
     sram_size = (board->dc0 >> 18) + 1;
-    pic = armv7m_init(flash_size, sram_size, kernel_filename, cpu_model);
+    pic = armv7m_init(address_space_mem,
+                      flash_size, sram_size, kernel_filename, cpu_model);
 
     if (board->dc1 & (1 << 16)) {
         dev = sysbus_create_varargs("stellaris-adc", 0x40038000,
commit 72e4d2554d16af85b7cdf7dfff8143c40ef245f1
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Jul 25 14:14:31 2011 +0300

    an5206: convert to memory API
    
    Reviewed-by: Richard Henderson  <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/an5206.c b/hw/an5206.c
index 04ca420..481ae60 100644
--- a/hw/an5206.c
+++ b/hw/an5206.c
@@ -12,6 +12,7 @@
 #include "boards.h"
 #include "loader.h"
 #include "elf.h"
+#include "exec-memory.h"
 
 #define KERNEL_LOAD_ADDR 0x10000
 #define AN5206_MBAR_ADDR 0x10000000
@@ -37,6 +38,9 @@ static void an5206_init(ram_addr_t ram_size,
     int kernel_size;
     uint64_t elf_entry;
     target_phys_addr_t entry;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *sram = g_new(MemoryRegion, 1);
 
     if (!cpu_model)
         cpu_model = "m5206";
@@ -52,12 +56,12 @@ static void an5206_init(ram_addr_t ram_size,
     env->rambar0 = AN5206_RAMBAR_ADDR | 1;
 
     /* DRAM at address zero */
-    cpu_register_physical_memory(0, ram_size,
-        qemu_ram_alloc(NULL, "an5206.ram", ram_size) | IO_MEM_RAM);
+    memory_region_init_ram(ram, NULL, "an5206.ram", ram_size);
+    memory_region_add_subregion(address_space_mem, 0, ram);
 
     /* Internal SRAM.  */
-    cpu_register_physical_memory(AN5206_RAMBAR_ADDR, 512,
-        qemu_ram_alloc(NULL, "an5206.sram", 512) | IO_MEM_RAM);
+    memory_region_init_ram(sram, NULL, "an5206.sram", 512);
+    memory_region_add_subregion(address_space_mem, AN5206_RAMBAR_ADDR, sram);
 
     mcf5206_init(AN5206_MBAR_ADDR, env);
 
commit fcdf7729beb53f20ab1bbcc96517f03c83cfa274
Author: Avi Kivity <avi at redhat.com>
Date:   Sun Jul 24 19:27:24 2011 +0300

    ReadWriteHandler: remove
    
    No longer used.
    
    Reviewed-by: Richard Henderson  <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/Makefile.target b/Makefile.target
index 0787758..8822442 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -191,7 +191,6 @@ obj-$(CONFIG_VIRTIO) += virtio.o virtio-blk.o virtio-balloon.o virtio-net.o virt
 obj-y += vhost_net.o
 obj-$(CONFIG_VHOST_NET) += vhost.o
 obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/virtio-9p-device.o
-obj-y += rwhandler.o
 obj-$(CONFIG_KVM) += kvm.o kvm-all.o
 obj-$(CONFIG_NO_KVM) += kvm-stub.o
 obj-y += memory.o
diff --git a/rwhandler.c b/rwhandler.c
deleted file mode 100644
index bb2238f..0000000
--- a/rwhandler.c
+++ /dev/null
@@ -1,87 +0,0 @@
-#include "rwhandler.h"
-#include "ioport.h"
-#include "cpu-all.h"
-
-#define RWHANDLER_WRITE(name, len, type) \
-static void name(void *opaque, type addr, uint32_t value) \
-{\
-    struct ReadWriteHandler *handler = opaque;\
-    handler->write(handler, addr, value, len);\
-}
-
-#define RWHANDLER_READ(name, len, type) \
-static uint32_t name(void *opaque, type addr) \
-{ \
-    struct ReadWriteHandler *handler = opaque; \
-    return handler->read(handler, addr, len); \
-}
-
-RWHANDLER_WRITE(cpu_io_memory_simple_writeb, 1, target_phys_addr_t);
-RWHANDLER_READ(cpu_io_memory_simple_readb, 1, target_phys_addr_t);
-RWHANDLER_WRITE(cpu_io_memory_simple_writew, 2, target_phys_addr_t);
-RWHANDLER_READ(cpu_io_memory_simple_readw, 2, target_phys_addr_t);
-RWHANDLER_WRITE(cpu_io_memory_simple_writel, 4, target_phys_addr_t);
-RWHANDLER_READ(cpu_io_memory_simple_readl, 4, target_phys_addr_t);
-
-static CPUWriteMemoryFunc * const cpu_io_memory_simple_write[] = {
-    &cpu_io_memory_simple_writeb,
-    &cpu_io_memory_simple_writew,
-    &cpu_io_memory_simple_writel,
-};
-
-static CPUReadMemoryFunc * const cpu_io_memory_simple_read[] = {
-    &cpu_io_memory_simple_readb,
-    &cpu_io_memory_simple_readw,
-    &cpu_io_memory_simple_readl,
-};
-
-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, endian);
-}
-
-RWHANDLER_WRITE(ioport_simple_writeb, 1, uint32_t);
-RWHANDLER_READ(ioport_simple_readb, 1, uint32_t);
-RWHANDLER_WRITE(ioport_simple_writew, 2, uint32_t);
-RWHANDLER_READ(ioport_simple_readw, 2, uint32_t);
-RWHANDLER_WRITE(ioport_simple_writel, 4, uint32_t);
-RWHANDLER_READ(ioport_simple_readl, 4, uint32_t);
-
-int register_ioport_simple(ReadWriteHandler* handler,
-                           pio_addr_t start, int length, int size)
-{
-    IOPortWriteFunc *write;
-    IOPortReadFunc *read;
-    int r;
-    switch (size) {
-    case 1:
-        write = ioport_simple_writeb;
-        read = ioport_simple_readb;
-        break;
-    case 2:
-        write = ioport_simple_writew;
-        read = ioport_simple_readw;
-        break;
-    default:
-        write = ioport_simple_writel;
-        read = ioport_simple_readl;
-    }
-    if (handler->write) {
-        r = register_ioport_write(start, length, size, write, handler);
-        if (r < 0) {
-            return r;
-        }
-    }
-    if (handler->read) {
-        r = register_ioport_read(start, length, size, read, handler);
-        if (r < 0) {
-            return r;
-        }
-    }
-    return 0;
-}
diff --git a/rwhandler.h b/rwhandler.h
deleted file mode 100644
index b2a5790..0000000
--- a/rwhandler.h
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef READ_WRITE_HANDLER_H
-#define READ_WRITE_HANDLER_H
-
-#include "qemu-common.h"
-#include "ioport.h"
-
-typedef struct ReadWriteHandler ReadWriteHandler;
-
-/* len is guaranteed to be one of 1, 2 or 4, addr is guaranteed to fit in an
- * appropriate type (io/memory/etc). They do not need to be range checked. */
-typedef void WriteHandlerFunc(ReadWriteHandler *, pcibus_t addr,
-                              uint32_t value, int len);
-typedef uint32_t ReadHandlerFunc(ReadWriteHandler *, pcibus_t addr, int len);
-
-struct ReadWriteHandler {
-    WriteHandlerFunc *write;
-    ReadHandlerFunc *read;
-};
-
-/* 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 endian);
-/* io port handler: can supply only read or write handlers. */
-int register_ioport_simple(ReadWriteHandler *,
-                           pio_addr_t start, int length, int size);
-
-#endif
commit d0ed8076cbdc26138a7e33fed5e45a35d019a103
Author: Avi Kivity <avi at redhat.com>
Date:   Sun Jul 24 17:47:18 2011 +0300

    pci_host: convert conf index and data ports to memory API
    
    Reviewed-by: Richard Henderson  <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/dec_pci.c b/hw/dec_pci.c
index a35f382..1aec066 100644
--- a/hw/dec_pci.c
+++ b/hw/dec_pci.c
@@ -80,16 +80,15 @@ PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn)
 static int pci_dec_21154_init_device(SysBusDevice *dev)
 {
     DECState *s;
-    int pci_mem_config, pci_mem_data;
 
     s = FROM_SYSBUS(DECState, dev);
 
-    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);
+    memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
+                          &s->host_state, "pci-conf-idx", 0x1000);
+    memory_region_init_io(&s->host_state.data_mem, &pci_host_data_le_ops,
+                          &s->host_state, "pci-data-idx", 0x1000);
+    sysbus_init_mmio_region(dev, &s->host_state.conf_mem);
+    sysbus_init_mmio_region(dev, &s->host_state.data_mem);
     return 0;
 }
 
diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c
index 9a823e1..9d3ff7d 100644
--- a/hw/grackle_pci.c
+++ b/hw/grackle_pci.c
@@ -92,16 +92,15 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic,
 static int pci_grackle_init_device(SysBusDevice *dev)
 {
     GrackleState *s;
-    int pci_mem_config, pci_mem_data;
 
     s = FROM_SYSBUS(GrackleState, dev);
 
-    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);
+    memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
+                          &s->host_state, "pci-conf-idx", 0x1000);
+    memory_region_init_io(&s->host_state.data_mem, &pci_host_data_le_ops,
+                          &s->host_state, "pci-data-idx", 0x1000);
+    sysbus_init_mmio_region(dev, &s->host_state.conf_mem);
+    sysbus_init_mmio_region(dev, &s->host_state.data_mem);
 
     qemu_register_reset(pci_grackle_reset, &s->host_state);
     return 0;
diff --git a/hw/pci_host.c b/hw/pci_host.c
index 2e8a29f..44c6c20 100644
--- a/hw/pci_host.c
+++ b/hw/pci_host.c
@@ -94,82 +94,72 @@ uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len)
     return val;
 }
 
-static void pci_host_config_write(ReadWriteHandler *handler,
-                                  pcibus_t addr, uint32_t val, int len)
+static void pci_host_config_write(void *opaque, target_phys_addr_t addr,
+                                  uint64_t val, unsigned len)
 {
-    PCIHostState *s = container_of(handler, PCIHostState, conf_handler);
+    PCIHostState *s = opaque;
 
-    PCI_DPRINTF("%s addr %" FMT_PCIBUS " %d val %"PRIx32"\n",
+    PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx64"\n",
                 __func__, addr, len, val);
     s->config_reg = val;
 }
 
-static uint32_t pci_host_config_read(ReadWriteHandler *handler,
-                                     pcibus_t addr, int len)
+static uint64_t pci_host_config_read(void *opaque, target_phys_addr_t addr,
+                                     unsigned len)
 {
-    PCIHostState *s = container_of(handler, PCIHostState, conf_handler);
+    PCIHostState *s = opaque;
     uint32_t val = s->config_reg;
 
-    PCI_DPRINTF("%s addr %" FMT_PCIBUS " len %d val %"PRIx32"\n",
+    PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx32"\n",
                 __func__, addr, len, val);
     return val;
 }
 
-static void pci_host_data_write(ReadWriteHandler *handler,
-                                pcibus_t addr, uint32_t val, int len)
+static void pci_host_data_write(void *opaque, target_phys_addr_t addr,
+                                uint64_t val, unsigned len)
 {
-    PCIHostState *s = container_of(handler, PCIHostState, data_handler);
-    PCI_DPRINTF("write addr %" FMT_PCIBUS " len %d val %x\n",
-                addr, len, val);
+    PCIHostState *s = opaque;
+    PCI_DPRINTF("write addr " TARGET_FMT_plx " len %d val %x\n",
+                addr, len, (unsigned)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(ReadWriteHandler *handler,
-                                   pcibus_t addr, int len)
+static uint64_t pci_host_data_read(void *opaque,
+                                   target_phys_addr_t addr, unsigned len)
 {
-    PCIHostState *s = container_of(handler, PCIHostState, data_handler);
+    PCIHostState *s = opaque;
     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",
+    PCI_DPRINTF("read addr " TARGET_FMT_plx " 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;
-    s->conf_handler.read = pci_host_config_read;
-    s->data_handler.write = pci_host_data_write;
-    s->data_handler.read = pci_host_data_read;
-}
+const MemoryRegionOps pci_host_conf_le_ops = {
+    .read = pci_host_config_read,
+    .write = pci_host_config_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
 
-int pci_host_conf_register_mmio(PCIHostState *s, int endian)
-{
-    pci_host_init(s);
-    return cpu_register_io_memory_simple(&s->conf_handler, endian);
-}
+const MemoryRegionOps pci_host_conf_be_ops = {
+    .read = pci_host_config_read,
+    .write = pci_host_config_write,
+    .endianness = DEVICE_BIG_ENDIAN,
+};
 
-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);
-}
+const MemoryRegionOps pci_host_data_le_ops = {
+    .read = pci_host_data_read,
+    .write = pci_host_data_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+const MemoryRegionOps pci_host_data_be_ops = {
+    .read = pci_host_data_read,
+    .write = pci_host_data_write,
+    .endianness = DEVICE_BIG_ENDIAN,
+};
 
-int pci_host_data_register_mmio(PCIHostState *s, int endian)
-{
-    pci_host_init(s);
-    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_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/pci_host.h b/hw/pci_host.h
index 7f55114..0211086 100644
--- a/hw/pci_host.h
+++ b/hw/pci_host.h
@@ -29,12 +29,11 @@
 #define PCI_HOST_H
 
 #include "sysbus.h"
-#include "rwhandler.h"
 
 struct PCIHostState {
     SysBusDevice busdev;
-    ReadWriteHandler conf_handler;
-    ReadWriteHandler data_handler;
+    MemoryRegion conf_mem;
+    MemoryRegion data_mem;
     MemoryRegion *address_space;
     uint32_t config_reg;
     PCIBus *bus;
@@ -49,12 +48,9 @@ uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr,
 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 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);
-void pci_host_data_register_ioport(pio_addr_t ioport, PCIHostState *s);
+extern const MemoryRegionOps pci_host_conf_le_ops;
+extern const MemoryRegionOps pci_host_conf_be_ops;
+extern const MemoryRegionOps pci_host_data_le_ops;
+extern const MemoryRegionOps pci_host_data_be_ops;
 
 #endif /* PCI_HOST_H */
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index c563c6e..f892994 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -235,9 +235,16 @@ static int i440fx_pcihost_initfn(SysBusDevice *dev)
 {
     I440FXState *s = FROM_SYSBUS(I440FXState, dev);
 
-    pci_host_conf_register_ioport(0xcf8, s);
+    memory_region_init_io(&s->conf_mem, &pci_host_conf_le_ops, s,
+                          "pci-conf-idx", 4);
+    sysbus_add_io(dev, 0xcf8, &s->conf_mem);
+    sysbus_init_ioports(&s->busdev, 0xcf8, 4);
+
+    memory_region_init_io(&s->data_mem, &pci_host_data_le_ops, s,
+                          "pci-conf-data", 4);
+    sysbus_add_io(dev, 0xcfc, &s->data_mem);
+    sysbus_init_ioports(&s->busdev, 0xcfc, 4);
 
-    pci_host_data_register_ioport(0xcfc, s);
     return 0;
 }
 
diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c
index 52e2663..339b38e 100644
--- a/hw/ppc4xx_pci.c
+++ b/hw/ppc4xx_pci.c
@@ -368,10 +368,12 @@ PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4],
     cpu_register_physical_memory(config_space + PCIC0_CFGADDR, 4, index);
 
     /* CFGDATA */
-    index = pci_host_data_register_mmio(&controller->pci_state, 1);
-    if (index < 0)
-        goto free;
-    cpu_register_physical_memory(config_space + PCIC0_CFGDATA, 4, index);
+    memory_region_init_io(&controller->pci_state.data_mem,
+                          &pci_host_data_be_ops,
+                          &controller->pci_state, "pci-conf-data", 4);
+    memory_region_add_subregion(get_system_memory(),
+                                config_space + PCIC0_CFGDATA,
+                                &controller->pci_state.data_mem);
 
     /* Internal registers */
     index = cpu_register_io_memory(pci_reg_read, pci_reg_write, controller,
diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c
index 4390aeb..2db365d 100644
--- a/hw/ppce500_pci.c
+++ b/hw/ppce500_pci.c
@@ -79,8 +79,6 @@ struct PPCE500PCIState {
     uint32_t gasket_time;
     qemu_irq irq[4];
     /* mmio maps */
-    int cfgaddr;
-    int cfgdata;
     int reg;
 };
 
@@ -268,18 +266,18 @@ static void e500_pci_map(SysBusDevice *dev, target_phys_addr_t base)
     PCIHostState *h = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev));
     PPCE500PCIState *s = DO_UPCAST(PPCE500PCIState, pci_state, h);
 
-    cpu_register_physical_memory(base + PCIE500_CFGADDR, 4, s->cfgaddr);
-    cpu_register_physical_memory(base + PCIE500_CFGDATA, 4, s->cfgdata);
+    sysbus_add_memory(dev, base + PCIE500_CFGADDR, &h->conf_mem);
+    sysbus_add_memory(dev, base + PCIE500_CFGDATA, &h->data_mem);
     cpu_register_physical_memory(base + PCIE500_REG_BASE, PCIE500_REG_SIZE,
                                  s->reg);
 }
 
 static void e500_pci_unmap(SysBusDevice *dev, target_phys_addr_t base)
 {
-    cpu_register_physical_memory(base + PCIE500_CFGADDR, 4,
-                                 IO_MEM_UNASSIGNED);
-    cpu_register_physical_memory(base + PCIE500_CFGDATA, 4,
-                                 IO_MEM_UNASSIGNED);
+    PCIHostState *h = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev));
+
+    sysbus_del_memory(dev, &h->conf_mem);
+    sysbus_del_memory(dev, &h->data_mem);
     cpu_register_physical_memory(base + PCIE500_REG_BASE, PCIE500_REG_SIZE,
                                  IO_MEM_UNASSIGNED);
 }
@@ -309,9 +307,10 @@ static int e500_pcihost_initfn(SysBusDevice *dev)
 
     pci_create_simple(b, 0, "e500-host-bridge");
 
-    s->cfgaddr = pci_host_conf_register_mmio(&s->pci_state, DEVICE_BIG_ENDIAN);
-    s->cfgdata = pci_host_data_register_mmio(&s->pci_state,
-                                             DEVICE_LITTLE_ENDIAN);
+    memory_region_init_io(&h->conf_mem, &pci_host_conf_be_ops, h,
+                          "pci-conf-idx", 4);
+    memory_region_init_io(&h->data_mem, &pci_host_data_le_ops, h,
+                          "pci-conf-data", 4);
     s->reg = cpu_register_io_memory(e500_pci_reg_read, e500_pci_reg_write, s,
                                     DEVICE_BIG_ENDIAN);
     sysbus_init_mmio_cb2(dev, e500_pci_map, e500_pci_unmap);
diff --git a/hw/prep_pci.c b/hw/prep_pci.c
index c36232a..55e4e25 100644
--- a/hw/prep_pci.c
+++ b/hw/prep_pci.c
@@ -125,9 +125,15 @@ PCIBus *pci_prep_init(qemu_irq *pic,
                               address_space_io,
                               0, 4);
 
-    pci_host_conf_register_ioport(0xcf8, s);
-
-    pci_host_data_register_ioport(0xcfc, s);
+    memory_region_init_io(&s->conf_mem, &pci_host_conf_be_ops, s,
+                          "pci-conf-idx", 1);
+    memory_region_add_subregion(address_space_io, 0xcf8, &s->conf_mem);
+    sysbus_init_ioports(&s->busdev, 0xcf8, 1);
+
+    memory_region_init_io(&s->conf_mem, &pci_host_data_be_ops, s,
+                          "pci-conf-data", 1);
+    memory_region_add_subregion(address_space_io, 0xcfc, &s->data_mem);
+    sysbus_init_ioports(&s->busdev, 0xcfc, 1);
 
     PPC_io_memory = cpu_register_io_memory(PPC_PCIIO_read,
                                            PPC_PCIIO_write, s,
diff --git a/hw/unin_pci.c b/hw/unin_pci.c
index f896f8c..600cd1e 100644
--- a/hw/unin_pci.c
+++ b/hw/unin_pci.c
@@ -41,7 +41,6 @@ static const int unin_irq_line[] = { 0x1b, 0x1c, 0x1d, 0x1e };
 typedef struct UNINState {
     SysBusDevice busdev;
     PCIHostState host_state;
-    ReadWriteHandler data_handler;
 } UNINState;
 
 static int pci_unin_map_irq(PCIDevice *pci_dev, int irq_num)
@@ -100,67 +99,70 @@ static uint32_t unin_get_config_reg(uint32_t reg, uint32_t addr)
     return retval;
 }
 
-static void unin_data_write(ReadWriteHandler *handler,
-                            pcibus_t addr, uint32_t val, int len)
+static void unin_data_write(void *opaque, target_phys_addr_t addr,
+                            uint64_t val, unsigned len)
 {
-    UNINState *s = container_of(handler, UNINState, data_handler);
-    UNIN_DPRINTF("write addr %" FMT_PCIBUS " len %d val %x\n", addr, len, val);
+    UNINState *s = opaque;
+    UNIN_DPRINTF("write addr %" TARGET_FMT_plx " len %d val %"PRIx64"\n",
+                 addr, len, val);
     pci_data_write(s->host_state.bus,
                    unin_get_config_reg(s->host_state.config_reg, addr),
                    val, len);
 }
 
-static uint32_t unin_data_read(ReadWriteHandler *handler,
-                               pcibus_t addr, int len)
+static uint64_t unin_data_read(void *opaque, target_phys_addr_t addr,
+                               unsigned len)
 {
-    UNINState *s = container_of(handler, UNINState, data_handler);
+    UNINState *s = opaque;
     uint32_t val;
 
     val = pci_data_read(s->host_state.bus,
                         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);
+    UNIN_DPRINTF("read addr %" TARGET_FMT_plx " len %d val %x\n",
+                 addr, len, val);
     return val;
 }
 
+static const MemoryRegionOps unin_data_ops = {
+    .read = unin_data_read,
+    .write = unin_data_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
 static int pci_unin_main_init_device(SysBusDevice *dev)
 {
     UNINState *s;
-    int pci_mem_config, pci_mem_data;
 
     /* Use values found on a real PowerMac */
     /* Uninorth main bus */
     s = FROM_SYSBUS(UNINState, dev);
 
-    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,
-                                                 DEVICE_LITTLE_ENDIAN);
-    sysbus_init_mmio(dev, 0x1000, pci_mem_config);
-    sysbus_init_mmio(dev, 0x1000, pci_mem_data);
+    memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
+                          &s->host_state, "pci-conf-idx", 0x1000);
+    memory_region_init_io(&s->host_state.data_mem, &unin_data_ops, s,
+                          "pci-conf-data", 0x1000);
+    sysbus_init_mmio_region(dev, &s->host_state.conf_mem);
+    sysbus_init_mmio_region(dev, &s->host_state.data_mem);
 
     qemu_register_reset(pci_unin_reset, &s->host_state);
     return 0;
 }
 
+
 static int pci_u3_agp_init_device(SysBusDevice *dev)
 {
     UNINState *s;
-    int pci_mem_config, pci_mem_data;
 
     /* Uninorth U3 AGP bus */
     s = FROM_SYSBUS(UNINState, dev);
 
-    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,
-                                                 DEVICE_LITTLE_ENDIAN);
-    sysbus_init_mmio(dev, 0x1000, pci_mem_config);
-    sysbus_init_mmio(dev, 0x1000, pci_mem_data);
+    memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
+                          &s->host_state, "pci-conf-idx", 0x1000);
+    memory_region_init_io(&s->host_state.data_mem, &unin_data_ops, s,
+                          "pci-conf-data", 0x1000);
+    sysbus_init_mmio_region(dev, &s->host_state.conf_mem);
+    sysbus_init_mmio_region(dev, &s->host_state.data_mem);
 
     qemu_register_reset(pci_unin_reset, &s->host_state);
 
@@ -170,34 +172,32 @@ static int pci_u3_agp_init_device(SysBusDevice *dev)
 static int pci_unin_agp_init_device(SysBusDevice *dev)
 {
     UNINState *s;
-    int pci_mem_config, pci_mem_data;
 
     /* Uninorth AGP bus */
     s = FROM_SYSBUS(UNINState, dev);
 
-    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);
+    memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
+                          &s->host_state, "pci-conf-idx", 0x1000);
+    memory_region_init_io(&s->host_state.data_mem, &pci_host_data_le_ops,
+                          &s->host_state, "pci-conf-data", 0x1000);
+    sysbus_init_mmio_region(dev, &s->host_state.conf_mem);
+    sysbus_init_mmio_region(dev, &s->host_state.data_mem);
     return 0;
 }
 
 static int pci_unin_internal_init_device(SysBusDevice *dev)
 {
     UNINState *s;
-    int pci_mem_config, pci_mem_data;
 
     /* Uninorth internal bus */
     s = FROM_SYSBUS(UNINState, dev);
 
-    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);
+    memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
+                          &s->host_state, "pci-conf-idx", 0x1000);
+    memory_region_init_io(&s->host_state.data_mem, &pci_host_data_le_ops,
+                          &s->host_state, "pci-conf-data", 0x1000);
+    sysbus_init_mmio_region(dev, &s->host_state.conf_mem);
+    sysbus_init_mmio_region(dev, &s->host_state.data_mem);
     return 0;
 }
 
commit 2b985d9c29efdd0a8394ad6b2edd2ba1acdb3536
Author: Avi Kivity <avi at redhat.com>
Date:   Sun Jul 24 17:12:11 2011 +0300

    sysbus: add helpers to add and delete memory regions to the system bus
    
    Reviewed-by: Richard Henderson  <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/sysbus.c b/hw/sysbus.c
index c365d39..02b4e49 100644
--- a/hw/sysbus.c
+++ b/hw/sysbus.c
@@ -261,3 +261,25 @@ static char *sysbus_get_fw_dev_path(DeviceState *dev)
 
     return strdup(path);
 }
+
+void sysbus_add_memory(SysBusDevice *dev, target_phys_addr_t addr,
+                       MemoryRegion *mem)
+{
+    memory_region_add_subregion(get_system_memory(), addr, mem);
+}
+
+void sysbus_del_memory(SysBusDevice *dev, MemoryRegion *mem)
+{
+    memory_region_del_subregion(get_system_memory(), mem);
+}
+
+void sysbus_add_io(SysBusDevice *dev, target_phys_addr_t addr,
+                       MemoryRegion *mem)
+{
+    memory_region_add_subregion(get_system_io(), addr, mem);
+}
+
+void sysbus_del_io(SysBusDevice *dev, MemoryRegion *mem)
+{
+    memory_region_del_subregion(get_system_io(), mem);
+}
diff --git a/hw/sysbus.h b/hw/sysbus.h
index aa3d383..e14055f 100644
--- a/hw/sysbus.h
+++ b/hw/sysbus.h
@@ -58,6 +58,12 @@ 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);
 void sysbus_mmio_map(SysBusDevice *dev, int n, target_phys_addr_t addr);
+void sysbus_add_memory(SysBusDevice *dev, target_phys_addr_t addr,
+                       MemoryRegion *mem);
+void sysbus_del_memory(SysBusDevice *dev, MemoryRegion *mem);
+void sysbus_add_io(SysBusDevice *dev, target_phys_addr_t addr,
+                   MemoryRegion *mem);
+void sysbus_del_io(SysBusDevice *dev, MemoryRegion *mem);
 
 /* Legacy helper function for creating devices.  */
 DeviceState *sysbus_create_varargs(const char *name,
commit f070e1e227e0d4dd468b48b39a1581ca78ff419e
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Jul 18 11:58:50 2011 +0300

    stellaris_enet: convert to memory API
    
    Reviewed-by: Richard Henderson  <rth at twiddle.net>
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c
index f9bd3da..d5613ff 100644
--- a/hw/stellaris_enet.c
+++ b/hw/stellaris_enet.c
@@ -69,7 +69,7 @@ typedef struct {
     NICState *nic;
     NICConf conf;
     qemu_irq irq;
-    int mmio_index;
+    MemoryRegion mmio;
 } stellaris_enet_state;
 
 static void stellaris_enet_update(stellaris_enet_state *s)
@@ -130,7 +130,8 @@ static int stellaris_enet_can_receive(VLANClientState *nc)
     return (s->np < 31);
 }
 
-static uint32_t stellaris_enet_read(void *opaque, target_phys_addr_t offset)
+static uint64_t stellaris_enet_read(void *opaque, target_phys_addr_t offset,
+                                    unsigned size)
 {
     stellaris_enet_state *s = (stellaris_enet_state *)opaque;
     uint32_t val;
@@ -198,7 +199,7 @@ static uint32_t stellaris_enet_read(void *opaque, target_phys_addr_t offset)
 }
 
 static void stellaris_enet_write(void *opaque, target_phys_addr_t offset,
-                        uint32_t value)
+                                 uint64_t value, unsigned size)
 {
     stellaris_enet_state *s = (stellaris_enet_state *)opaque;
 
@@ -303,17 +304,12 @@ static void stellaris_enet_write(void *opaque, target_phys_addr_t offset,
     }
 }
 
-static CPUReadMemoryFunc * const stellaris_enet_readfn[] = {
-   stellaris_enet_read,
-   stellaris_enet_read,
-   stellaris_enet_read
+static const MemoryRegionOps stellaris_enet_ops = {
+    .read = stellaris_enet_read,
+    .write = stellaris_enet_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const stellaris_enet_writefn[] = {
-   stellaris_enet_write,
-   stellaris_enet_write,
-   stellaris_enet_write
-};
 static void stellaris_enet_reset(stellaris_enet_state *s)
 {
     s->mdv = 0x80;
@@ -391,7 +387,7 @@ static void stellaris_enet_cleanup(VLANClientState *nc)
 
     unregister_savevm(&s->busdev.qdev, "stellaris_enet", s);
 
-    cpu_unregister_io_memory(s->mmio_index);
+    memory_region_destroy(&s->mmio);
 
     g_free(s);
 }
@@ -408,10 +404,9 @@ 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,
-                                           DEVICE_NATIVE_ENDIAN);
-    sysbus_init_mmio(dev, 0x1000, s->mmio_index);
+    memory_region_init_io(&s->mmio, &stellaris_enet_ops, s, "stellaris_enet",
+                          0x1000);
+    sysbus_init_mmio_region(dev, &s->mmio);
     sysbus_init_irq(dev, &s->irq);
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
 
commit 13faf2a71f88d90c1c51e3cc76eebc9c6e120437
Author: Avi Kivity <avi at redhat.com>
Date:   Mon Aug 8 21:46:13 2011 +0300

    mips_fulong2e: convert to memory API
    
    Signed-off-by: Avi Kivity <avi at redhat.com>

diff --git a/hw/mips_fulong2e.c b/hw/mips_fulong2e.c
index ec8c88e..abe3056 100644
--- a/hw/mips_fulong2e.c
+++ b/hw/mips_fulong2e.c
@@ -38,6 +38,7 @@
 #include "vt82c686.h"
 #include "mc146818rtc.h"
 #include "blockdev.h"
+#include "exec-memory.h"
 
 #define DEBUG_FULONG2E_INIT
 
@@ -256,7 +257,9 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device,
                         const char *initrd_filename, const char *cpu_model)
 {
     char *filename;
-    unsigned long ram_offset, bios_offset;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *bios = g_new(MemoryRegion, 1);
     long bios_size;
     int64_t kernel_entry;
     qemu_irq *i8259;
@@ -288,12 +291,12 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device,
     bios_size = 1024 * 1024;
 
     /* allocate RAM */
-    ram_offset = qemu_ram_alloc(NULL, "fulong2e.ram", ram_size);
-    bios_offset = qemu_ram_alloc(NULL, "fulong2e.bios", bios_size);
+    memory_region_init_ram(ram, NULL, "fulong2e.ram", ram_size);
+    memory_region_init_ram(bios, NULL, "fulong2e.bios", bios_size);
+    memory_region_set_readonly(bios, true);
 
-    cpu_register_physical_memory(0, ram_size, ram_offset);
-    cpu_register_physical_memory(0x1fc00000LL,
-					   bios_size, bios_offset | IO_MEM_ROM);
+    memory_region_add_subregion(address_space_mem, 0, ram);
+    memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
 
     /* We do not support flash operation, just loading pmon.bin as raw BIOS.
      * Please use -L to set the BIOS path and -bios to set bios name. */
@@ -304,7 +307,7 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device,
         loaderparams.kernel_cmdline = kernel_cmdline;
         loaderparams.initrd_filename = initrd_filename;
         kernel_entry = load_kernel (env);
-        write_bootloader(env, qemu_get_ram_ptr(bios_offset), kernel_entry);
+        write_bootloader(env, memory_region_get_ram_ptr(bios), kernel_entry);
     } else {
         if (bios_name == NULL) {
                 bios_name = FULONG_BIOSNAME;
commit 9f4facbce9dc4037b23baa77950381fc2f92e2d3
Author: Brad Smith <brad at comstyle.com>
Date:   Fri Sep 2 10:53:26 2011 +0100

    libcacard: use INSTALL_DATA for data
    
    Signed-off-by: Brad Smith <brad at comstyle.com>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/libcacard/Makefile b/libcacard/Makefile
index bf052bc..81d9eb5 100644
--- a/libcacard/Makefile
+++ b/libcacard/Makefile
@@ -56,7 +56,7 @@ install-libcacard: libcacard.pc libcacard.la vscclient
 	$(INSTALL_DIR) "$(DESTDIR)$(libcacard_includedir)"
 	$(INSTALL_DIR) "$(DESTDIR)$(bindir)"
 	$(LIBTOOL) --mode=install $(INSTALL_PROG) vscclient "$(DESTDIR)$(bindir)"
-	$(LIBTOOL) --mode=install $(INSTALL_PROG) libcacard.la "$(DESTDIR)$(libdir)"
+	$(LIBTOOL) --mode=install $(INSTALL_DATA) libcacard.la "$(DESTDIR)$(libdir)"
 	$(LIBTOOL) --mode=install $(INSTALL_DATA) libcacard.pc "$(DESTDIR)$(libdir)/pkgconfig"
 	for inc in *.h; do \
 		$(LIBTOOL) --mode=install $(INSTALL_DATA) $(libcacard_srcpath)/$$inc "$(DESTDIR)$(libcacard_includedir)"; \
commit c6bfc164e8f929e1e6a79f7b5a3cf096b22ef5f3
Author: Boris Figovsky <boris.figovsky at ravellosystems.com>
Date:   Tue Aug 30 10:00:55 2011 +0300

    x86: fix daa opcode for al register values higher than 0xf9
    
    The second if statement should consider the original al register value,
    and not the new one.
    
    Signed-off-by: Boris Figovsky <boris.figovksy at ravellosystems.com>
    Reviewed-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c
index 1bbc3b5..1fc248f 100644
--- a/target-i386/op_helper.c
+++ b/target-i386/op_helper.c
@@ -1970,20 +1970,20 @@ void helper_aas(void)
 
 void helper_daa(void)
 {
-    int al, af, cf;
+    int old_al, al, af, cf;
     int eflags;
 
     eflags = helper_cc_compute_all(CC_OP);
     cf = eflags & CC_C;
     af = eflags & CC_A;
-    al = EAX & 0xff;
+    old_al = al = EAX & 0xff;
 
     eflags = 0;
     if (((al & 0x0f) > 9 ) || af) {
         al = (al + 6) & 0xff;
         eflags |= CC_A;
     }
-    if ((al > 0x9f) || cf) {
+    if ((old_al > 0x99) || cf) {
         al = (al + 0x60) & 0xff;
         eflags |= CC_C;
     }
commit 6f9faa91f5fb3a866f5bf592207c9498a017740d
Author: Stefan Weil <weil at mail.berlios.de>
Date:   Wed Jul 20 20:56:35 2011 +0200

    sh4: Fix potential crash in debug code
    
    cppcheck reports this error:
    
    qemu/hw/sh_intc.c:390: error: Possible null pointer dereference:
     s - otherwise it is redundant to check if s is null at line 385
    
    If s were NULL, the printf() statement would crash.
    Setting braces fixes this bug.
    
    Signed-off-by: Stefan Weil <weil at mail.berlios.de>
    Reviewed-by: Andreas Färber <andreas.faerber at web.de>
    Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>

diff --git a/hw/sh_intc.c b/hw/sh_intc.c
index ecb46e5..e07424f 100644
--- a/hw/sh_intc.c
+++ b/hw/sh_intc.c
@@ -382,13 +382,14 @@ void sh_intc_register_sources(struct intc_desc *desc,
 
 	sh_intc_register_source(desc, vect->enum_id, groups, nr_groups);
 	s = sh_intc_source(desc, vect->enum_id);
-	if (s)
-	    s->vect = vect->vect;
+        if (s) {
+            s->vect = vect->vect;
 
 #ifdef DEBUG_INTC_SOURCES
-	printf("sh_intc: registered source %d -> 0x%04x (%d/%d)\n",
-	       vect->enum_id, s->vect, s->enable_count, s->enable_max);
+            printf("sh_intc: registered source %d -> 0x%04x (%d/%d)\n",
+                   vect->enum_id, s->vect, s->enable_count, s->enable_max);
 #endif
+        }
     }
 
     if (groups) {
commit b9cb88b0565c9a292f79a1c7bd387b8e9978e2a6
Author: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Date:   Tue Aug 2 11:36:24 2011 +0530

    hw/9pfs: mark directories also as un-reclaimable on unlink
    
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>

diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index 16f7d4e..94b7090 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -235,6 +235,27 @@ static size_t v9fs_string_size(V9fsString *str)
     return str->size;
 }
 
+/*
+ * returns 0 if fid got re-opened, 1 if not, < 0 on error */
+static int v9fs_reopen_fid(V9fsState *s, V9fsFidState *f)
+{
+    int err = 1;
+    if (f->fid_type == P9_FID_FILE) {
+        if (f->fs.fd == -1) {
+            do {
+                err = v9fs_co_open(s, f, f->open_flags);
+            } while (err == -EINTR);
+        }
+    } else if (f->fid_type == P9_FID_DIR) {
+        if (f->fs.dir == NULL) {
+            do {
+                err = v9fs_co_opendir(s, f);
+            } while (err == -EINTR);
+        }
+    }
+    return err;
+}
+
 static V9fsFidState *get_fid(V9fsState *s, int32_t fid)
 {
     int err;
@@ -249,34 +270,17 @@ static V9fsFidState *get_fid(V9fsState *s, int32_t fid)
              * in open later.
              */
             f->ref++;
-
             /*
              * check whether we need to reopen the
              * file. We might have closed the fd
              * while trying to free up some file
              * descriptors.
              */
-            if (f->fid_type == P9_FID_FILE) {
-                if (f->fs.fd == -1) {
-                    do {
-                        err = v9fs_co_open(s, f, f->open_flags);
-                    } while (err == -EINTR);
-                    if (err < 0) {
-                        f->ref--;
-                        return NULL;
-                    }
-                }
-            } else if (f->fid_type == P9_FID_DIR) {
-                if (f->fs.dir == NULL) {
-                    do {
-                        err = v9fs_co_opendir(s, f);
-                    } while (err == -EINTR);
-                    if (err < 0) {
-                        f->ref--;
-                        return NULL;
-                    }
-                }
-             }
+            err = v9fs_reopen_fid(s, f);
+            if (err < 0) {
+                f->ref--;
+                return NULL;
+            }
             /*
              * Mark the fid as referenced so that the LRU
              * reclaim won't close the file descriptor
@@ -490,19 +494,18 @@ static int v9fs_mark_fids_unreclaim(V9fsState *s, V9fsString *str)
         if (!strcmp(fidp->path.data, str->data)) {
             /* Mark the fid non reclaimable. */
             fidp->flags |= FID_NON_RECLAIMABLE;
-            /* reopen the file if already closed */
-            if (fidp->fs.fd == -1) {
-                do {
-                    err = v9fs_co_open(s, fidp, fidp->open_flags);
-                } while (err == -EINTR);
-                if (err < 0) {
-                    return -1;
-                }
-                /*
-                 * Go back to head of fid list because
-                 * the list could have got updated when
-                 * switched to the worker thread
-                 */
+
+            /* reopen the file/dir if already closed */
+            err = v9fs_reopen_fid(s, fidp);
+            if (err < 0) {
+                return -1;
+            }
+            /*
+             * Go back to head of fid list because
+             * the list could have got updated when
+             * switched to the worker thread
+             */
+            if (err == 0) {
                 fidp = &head_fid;
             }
         }
commit 95f65511c36fe4e2b319de4551f8a5657a63b67f
Author: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Date:   Wed May 18 17:08:34 2011 +0530

    hw/9pfs: Add directory reclaim support
    
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>

diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c
index 86adc87..f17f927 100644
--- a/hw/9pfs/codir.c
+++ b/hw/9pfs/codir.c
@@ -97,6 +97,12 @@ int v9fs_co_opendir(V9fsState *s, V9fsFidState *fidp)
                 err = 0;
             }
         });
+    if (!err) {
+        total_open_fd++;
+        if (total_open_fd > open_fd_hw) {
+            v9fs_reclaim_fd(s);
+        }
+    }
     return err;
 }
 
@@ -111,5 +117,8 @@ int v9fs_co_closedir(V9fsState *s, DIR *dir)
                 err = -errno;
             }
         });
+    if (!err) {
+        total_open_fd--;
+    }
     return err;
 }
diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index 6529216..16f7d4e 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -266,7 +266,17 @@ static V9fsFidState *get_fid(V9fsState *s, int32_t fid)
                         return NULL;
                     }
                 }
-            }
+            } else if (f->fid_type == P9_FID_DIR) {
+                if (f->fs.dir == NULL) {
+                    do {
+                        err = v9fs_co_opendir(s, f);
+                    } while (err == -EINTR);
+                    if (err < 0) {
+                        f->ref--;
+                        return NULL;
+                    }
+                }
+             }
             /*
              * Mark the fid as referenced so that the LRU
              * reclaim won't close the file descriptor
@@ -348,7 +358,9 @@ static int free_fid(V9fsState *s, V9fsFidState *fidp)
             retval = v9fs_co_close(s, fidp->fs.fd);
         }
     } else if (fidp->fid_type == P9_FID_DIR) {
-        retval = v9fs_co_closedir(s, fidp->fs.dir);
+        if (fidp->fs.dir != NULL) {
+            retval = v9fs_co_closedir(s, fidp->fs.dir);
+        }
     } else if (fidp->fid_type == P9_FID_XATTR) {
         retval = v9fs_xattr_fid_clunk(s, fidp);
     }
@@ -429,6 +441,19 @@ void v9fs_reclaim_fd(V9fsState *s)
                 f->fs.fd = -1;
                 reclaim_count++;
             }
+        } else if (f->fid_type == P9_FID_DIR) {
+            if (f->fs.dir != NULL) {
+                /*
+                 * Up the reference count so that
+                 * a clunk request won't free this fid
+                 */
+                f->ref++;
+                f->rclm_lst = reclaim_list;
+                reclaim_list = f;
+                f->fs_reclaim.dir = f->fs.dir;
+                f->fs.dir = NULL;
+                reclaim_count++;
+            }
         }
         if (reclaim_count >= open_fd_rc) {
             break;
@@ -443,6 +468,8 @@ void v9fs_reclaim_fd(V9fsState *s)
         reclaim_list = f->rclm_lst;
         if (f->fid_type == P9_FID_FILE) {
             v9fs_co_close(s, f->fs_reclaim.fd);
+        } else if (f->fid_type == P9_FID_DIR) {
+            v9fs_co_closedir(s, f->fs_reclaim.dir);
         }
         f->rclm_lst = NULL;
         /*
commit 9b54ffaab2e7cd09e7da47a9dc9b8f746ebcfe1b
Author: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Date:   Wed May 18 16:59:54 2011 +0530

    hw/9pfs: Use v9fs_do_close instead of close
    
    we should use the local abstraction instead of
    directly calling close.
    
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>

diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index 4ba2590..6529216 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -1592,7 +1592,7 @@ static void v9fs_lcreate(void *opaque)
     if (err < 0) {
         fidp->fid_type = P9_FID_NONE;
         if (fidp->fs.fd > 0) {
-            close(fidp->fs.fd);
+            v9fs_co_close(pdu->s, fidp->fs.fd);
         }
         goto out;
     }
@@ -2160,7 +2160,7 @@ static void v9fs_create(void *opaque)
     if (err < 0) {
         fidp->fid_type = P9_FID_NONE;
         if (fidp->fs.fd) {
-            close(fidp->fs.fd);
+            v9fs_co_close(pdu->s, fidp->fs.fd);
         }
         goto out;
     }
commit 9e5b2247eaf56f057402d99285cc76b0d3e8827f
Author: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Date:   Sun May 22 15:33:57 2011 +0530

    hw/9pfs: init fid list properly
    
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>

diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index 44b9ace..97f2da5 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -130,6 +130,7 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
     s->config_size = sizeof(struct virtio_9p_config) +
                         s->tag_len;
     s->vdev.get_config = virtio_9p_get_config;
+    s->fid_list = NULL;
 
     if (v9fs_init_worker_threads() < 0) {
         fprintf(stderr, "worker thread initialization failed\n");
commit 7a46274529c2a1866e4344b4385739db674d6a35
Author: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Date:   Wed May 18 15:40:57 2011 +0530

    hw/9pfs: Add file descriptor reclaim support
    
    [M. Mohan Kumar <mohan at in.ibm.com> removed some unused variables]
    
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>

diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c
index 3a257b9..86adc87 100644
--- a/hw/9pfs/codir.c
+++ b/hw/9pfs/codir.c
@@ -100,12 +100,10 @@ int v9fs_co_opendir(V9fsState *s, V9fsFidState *fidp)
     return err;
 }
 
-int v9fs_co_closedir(V9fsState *s, V9fsFidState *fidp)
+int v9fs_co_closedir(V9fsState *s, DIR *dir)
 {
     int err;
-    DIR *dir;
 
-    dir = fidp->fs.dir;
     v9fs_co_run_in_worker(
         {
             err = s->ops->closedir(&s->ctx, dir);
diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c
index e388146..0caf1e3 100644
--- a/hw/9pfs/cofile.c
+++ b/hw/9pfs/cofile.c
@@ -58,6 +58,12 @@ int v9fs_co_open(V9fsState *s, V9fsFidState *fidp, int flags)
                 err = 0;
             }
         });
+    if (!err) {
+        total_open_fd++;
+        if (total_open_fd > open_fd_hw) {
+            v9fs_reclaim_fd(s);
+        }
+    }
     return err;
 }
 
@@ -79,15 +85,19 @@ int v9fs_co_open2(V9fsState *s, V9fsFidState *fidp, char *fullname, gid_t gid,
                 err = -errno;
             }
         });
+    if (!err) {
+        total_open_fd++;
+        if (total_open_fd > open_fd_hw) {
+            v9fs_reclaim_fd(s);
+        }
+    }
     return err;
 }
 
-int v9fs_co_close(V9fsState *s, V9fsFidState *fidp)
+int v9fs_co_close(V9fsState *s, int fd)
 {
-    int fd;
     int err;
 
-    fd = fidp->fs.fd;
     v9fs_co_run_in_worker(
         {
             err = s->ops->close(&s->ctx, fd);
@@ -95,6 +105,9 @@ int v9fs_co_close(V9fsState *s, V9fsFidState *fidp)
                 err = -errno;
             }
         });
+    if (!err) {
+        total_open_fd--;
+    }
     return err;
 }
 
diff --git a/hw/9pfs/virtio-9p-coth.h b/hw/9pfs/virtio-9p-coth.h
index 48defb7..b7be9b5 100644
--- a/hw/9pfs/virtio-9p-coth.h
+++ b/hw/9pfs/virtio-9p-coth.h
@@ -83,8 +83,8 @@ extern int v9fs_co_open2(V9fsState *, V9fsFidState *, char *, gid_t, int, int);
 extern int v9fs_co_lsetxattr(V9fsState *, V9fsString *, V9fsString *,
                              void *, size_t, int);
 extern int v9fs_co_lremovexattr(V9fsState *, V9fsString *, V9fsString *);
-extern int v9fs_co_closedir(V9fsState *, V9fsFidState *);
-extern int v9fs_co_close(V9fsState *, V9fsFidState *);
+extern int v9fs_co_closedir(V9fsState *, DIR *);
+extern int v9fs_co_close(V9fsState *, int);
 extern int v9fs_co_fsync(V9fsState *, V9fsFidState *, int);
 extern int v9fs_co_symlink(V9fsState *, V9fsFidState *, const char *,
                            const char *, gid_t);
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index 9466002..44b9ace 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -171,6 +171,7 @@ static PCIDeviceInfo virtio_9p_info = {
 static void virtio_9p_register_devices(void)
 {
     pci_qdev_register(&virtio_9p_info);
+    virtio_9p_set_fd_limit();
 }
 
 device_init(virtio_9p_register_devices)
diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index 555f456..4ba2590 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -22,6 +22,9 @@
 #include "virtio-9p-coth.h"
 
 int debug_9p_pdu;
+int open_fd_hw;
+int total_open_fd;
+static int open_fd_rc;
 
 enum {
     Oread   = 0x00,
@@ -234,12 +237,41 @@ static size_t v9fs_string_size(V9fsString *str)
 
 static V9fsFidState *get_fid(V9fsState *s, int32_t fid)
 {
+    int err;
     V9fsFidState *f;
 
     for (f = s->fid_list; f; f = f->next) {
         BUG_ON(f->clunked);
         if (f->fid == fid) {
+            /*
+             * Update the fid ref upfront so that
+             * we don't get reclaimed when we yield
+             * in open later.
+             */
             f->ref++;
+
+            /*
+             * check whether we need to reopen the
+             * file. We might have closed the fd
+             * while trying to free up some file
+             * descriptors.
+             */
+            if (f->fid_type == P9_FID_FILE) {
+                if (f->fs.fd == -1) {
+                    do {
+                        err = v9fs_co_open(s, f, f->open_flags);
+                    } while (err == -EINTR);
+                    if (err < 0) {
+                        f->ref--;
+                        return NULL;
+                    }
+                }
+            }
+            /*
+             * Mark the fid as referenced so that the LRU
+             * reclaim won't close the file descriptor
+             */
+            f->flags |= FID_REFERENCED;
             return f;
         }
     }
@@ -261,6 +293,11 @@ static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
     f->fid = fid;
     f->fid_type = P9_FID_NONE;
     f->ref = 1;
+    /*
+     * Mark the fid as referenced so that the LRU
+     * reclaim won't close the file descriptor
+     */
+    f->flags |= FID_REFERENCED;
     f->next = s->fid_list;
     s->fid_list = f;
 
@@ -306,9 +343,12 @@ static int free_fid(V9fsState *s, V9fsFidState *fidp)
     int retval = 0;
 
     if (fidp->fid_type == P9_FID_FILE) {
-        retval = v9fs_co_close(s, fidp);
+        /* If we reclaimed the fd no need to close */
+        if (fidp->fs.fd != -1) {
+            retval = v9fs_co_close(s, fidp->fs.fd);
+        }
     } else if (fidp->fid_type == P9_FID_DIR) {
-        retval = v9fs_co_closedir(s, fidp);
+        retval = v9fs_co_closedir(s, fidp->fs.dir);
     } else if (fidp->fid_type == P9_FID_XATTR) {
         retval = v9fs_xattr_fid_clunk(s, fidp);
     }
@@ -321,6 +361,9 @@ static void put_fid(V9fsState *s, V9fsFidState *fidp)
 {
     BUG_ON(!fidp->ref);
     fidp->ref--;
+    /*
+     * Don't free the fid if it is in reclaim list
+     */
     if (!fidp->ref && fidp->clunked) {
         free_fid(s, fidp);
     }
@@ -345,6 +388,101 @@ static int clunk_fid(V9fsState *s, int32_t fid)
     return 0;
 }
 
+void v9fs_reclaim_fd(V9fsState *s)
+{
+    int reclaim_count = 0;
+    V9fsFidState *f, *reclaim_list = NULL;
+
+    for (f = s->fid_list; f; f = f->next) {
+        /*
+         * Unlink fids cannot be reclaimed. Check
+         * for them and skip them. Also skip fids
+         * currently being operated on.
+         */
+        if (f->ref || f->flags & FID_NON_RECLAIMABLE) {
+            continue;
+        }
+        /*
+         * if it is a recently referenced fid
+         * we leave the fid untouched and clear the
+         * reference bit. We come back to it later
+         * in the next iteration. (a simple LRU without
+         * moving list elements around)
+         */
+        if (f->flags & FID_REFERENCED) {
+            f->flags &= ~FID_REFERENCED;
+            continue;
+        }
+        /*
+         * Add fids to reclaim list.
+         */
+        if (f->fid_type == P9_FID_FILE) {
+            if (f->fs.fd != -1) {
+                /*
+                 * Up the reference count so that
+                 * a clunk request won't free this fid
+                 */
+                f->ref++;
+                f->rclm_lst = reclaim_list;
+                reclaim_list = f;
+                f->fs_reclaim.fd = f->fs.fd;
+                f->fs.fd = -1;
+                reclaim_count++;
+            }
+        }
+        if (reclaim_count >= open_fd_rc) {
+            break;
+        }
+    }
+    /*
+     * Now close the fid in reclaim list. Free them if they
+     * are already clunked.
+     */
+    while (reclaim_list) {
+        f = reclaim_list;
+        reclaim_list = f->rclm_lst;
+        if (f->fid_type == P9_FID_FILE) {
+            v9fs_co_close(s, f->fs_reclaim.fd);
+        }
+        f->rclm_lst = NULL;
+        /*
+         * Now drop the fid reference, free it
+         * if clunked.
+         */
+        put_fid(s, f);
+    }
+}
+
+static int v9fs_mark_fids_unreclaim(V9fsState *s, V9fsString *str)
+{
+    int err;
+    V9fsFidState *fidp, head_fid;
+
+    head_fid.next = s->fid_list;
+    for (fidp = s->fid_list; fidp; fidp = fidp->next) {
+        if (!strcmp(fidp->path.data, str->data)) {
+            /* Mark the fid non reclaimable. */
+            fidp->flags |= FID_NON_RECLAIMABLE;
+            /* reopen the file if already closed */
+            if (fidp->fs.fd == -1) {
+                do {
+                    err = v9fs_co_open(s, fidp, fidp->open_flags);
+                } while (err == -EINTR);
+                if (err < 0) {
+                    return -1;
+                }
+                /*
+                 * Go back to head of fid list because
+                 * the list could have got updated when
+                 * switched to the worker thread
+                 */
+                fidp = &head_fid;
+            }
+        }
+    }
+    return 0;
+}
+
 #define P9_QID_TYPE_DIR         0x80
 #define P9_QID_TYPE_SYMLINK     0x02
 
@@ -1389,6 +1527,14 @@ static void v9fs_open(void *opaque)
             goto out;
         }
         fidp->fid_type = P9_FID_FILE;
+        fidp->open_flags = flags;
+        if (flags & O_EXCL) {
+            /*
+             * We let the host file system do O_EXCL check
+             * We should not reclaim such fd
+             */
+            fidp->flags |= FID_NON_RECLAIMABLE;
+        }
         iounit = get_iounit(s, &fidp->path);
         offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
         err = offset;
@@ -1432,6 +1578,14 @@ static void v9fs_lcreate(void *opaque)
         goto out;
     }
     fidp->fid_type = P9_FID_FILE;
+    fidp->open_flags = flags;
+    if (flags & O_EXCL) {
+        /*
+         * We let the host file system do O_EXCL check
+         * We should not reclaim such fd
+         */
+        fidp->flags |= FID_NON_RECLAIMABLE;
+    }
     iounit =  get_iounit(pdu->s, &fullname);
 
     err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
@@ -1993,6 +2147,14 @@ static void v9fs_create(void *opaque)
             goto out;
         }
         fidp->fid_type = P9_FID_FILE;
+        fidp->open_flags = omode_to_uflags(mode);
+        if (fidp->open_flags & O_EXCL) {
+            /*
+             * We let the host file system do O_EXCL check
+             * We should not reclaim such fd
+             */
+            fidp->flags |= FID_NON_RECLAIMABLE;
+        }
     }
     err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
     if (err < 0) {
@@ -2124,11 +2286,19 @@ static void v9fs_remove(void *opaque)
         err = -EINVAL;
         goto out_nofid;
     }
+    /*
+     * IF the file is unlinked, we cannot reopen
+     * the file later. So don't reclaim fd
+     */
+    err = v9fs_mark_fids_unreclaim(pdu->s, &fidp->path);
+    if (err < 0) {
+        goto out_err;
+    }
     err = v9fs_co_remove(pdu->s, &fidp->path);
     if (!err) {
         err = offset;
     }
-
+out_err:
     /* For TREMOVE we need to clunk the fid even on failed remove */
     clunk_fid(pdu->s, fidp->fid);
     put_fid(pdu->s, fidp);
@@ -2823,3 +2993,14 @@ void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
     }
     free_pdu(s, pdu);
 }
+
+void virtio_9p_set_fd_limit(void)
+{
+    struct rlimit rlim;
+    if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
+        fprintf(stderr, "Failed to get the resource limit\n");
+        exit(1);
+    }
+    open_fd_hw = rlim.rlim_cur - MIN(400, rlim.rlim_cur/3);
+    open_fd_rc = rlim.rlim_cur/2;
+}
diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
index e16e5f4..28fe1ff 100644
--- a/hw/9pfs/virtio-9p.h
+++ b/hw/9pfs/virtio-9p.h
@@ -5,6 +5,7 @@
 #include <dirent.h>
 #include <sys/time.h>
 #include <utime.h>
+#include <sys/resource.h>
 #include "hw/virtio.h"
 #include "fsdev/file-op-9p.h"
 
@@ -101,6 +102,9 @@ enum p9_proto_version {
 #define P9_NOTAG    (u16)(~0)
 #define P9_NOFID    (u32)(~0)
 #define P9_MAXWELEM 16
+
+#define FID_REFERENCED          0x1
+#define FID_NON_RECLAIMABLE     0x2
 static inline const char *rpath(FsContext *ctx, const char *path, char *buffer)
 {
     snprintf(buffer, PATH_MAX, "%s/%s", ctx->fs_root, path);
@@ -198,14 +202,21 @@ struct V9fsFidState
     int32_t fid;
     V9fsString path;
     union {
-	int fd;
-	DIR *dir;
-	V9fsXattr xattr;
+        int fd;
+        DIR *dir;
+        V9fsXattr xattr;
     } fs;
+    union {
+        int fd;
+        DIR *dir;
+    } fs_reclaim;
+    int flags;
+    int open_flags;
     uid_t uid;
     int ref;
     int clunked;
     V9fsFidState *next;
+    V9fsFidState *rclm_lst;
 };
 
 typedef struct V9fsState
@@ -354,6 +365,9 @@ typedef struct V9fsGetlock
     V9fsString client_id;
 } V9fsGetlock;
 
+extern int open_fd_hw;
+extern int total_open_fd;
+
 size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count,
                       size_t offset, size_t size, int pack);
 
@@ -364,4 +378,6 @@ static inline size_t do_pdu_unpack(void *dst, struct iovec *sg, int sg_count,
 }
 
 extern void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq);
+extern void virtio_9p_set_fd_limit(void);
+extern void v9fs_reclaim_fd(V9fsState *s);
 #endif
commit 84dfb926e508aeedd5088a4f029464bf2d5b3791
Author: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Date:   Wed May 18 17:38:07 2011 +0530

    hw/9pfs: Add reference counting for fid
    
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>

diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index ad70768..555f456 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -232,16 +232,17 @@ static size_t v9fs_string_size(V9fsString *str)
     return str->size;
 }
 
-static V9fsFidState *lookup_fid(V9fsState *s, int32_t fid)
+static V9fsFidState *get_fid(V9fsState *s, int32_t fid)
 {
     V9fsFidState *f;
 
     for (f = s->fid_list; f; f = f->next) {
+        BUG_ON(f->clunked);
         if (f->fid == fid) {
+            f->ref++;
             return f;
         }
     }
-
     return NULL;
 }
 
@@ -249,16 +250,17 @@ static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
 {
     V9fsFidState *f;
 
-    f = lookup_fid(s, fid);
-    if (f) {
-        return NULL;
+    for (f = s->fid_list; f; f = f->next) {
+        /* If fid is already there return NULL */
+        BUG_ON(f->clunked);
+        if (f->fid == fid) {
+            return NULL;
+        }
     }
-
     f = g_malloc0(sizeof(V9fsFidState));
-
     f->fid = fid;
     f->fid_type = P9_FID_NONE;
-
+    f->ref = 1;
     f->next = s->fid_list;
     s->fid_list = f;
 
@@ -299,9 +301,33 @@ free_value:
     return retval;
 }
 
-static int free_fid(V9fsState *s, int32_t fid)
+static int free_fid(V9fsState *s, V9fsFidState *fidp)
 {
     int retval = 0;
+
+    if (fidp->fid_type == P9_FID_FILE) {
+        retval = v9fs_co_close(s, fidp);
+    } else if (fidp->fid_type == P9_FID_DIR) {
+        retval = v9fs_co_closedir(s, fidp);
+    } else if (fidp->fid_type == P9_FID_XATTR) {
+        retval = v9fs_xattr_fid_clunk(s, fidp);
+    }
+    v9fs_string_free(&fidp->path);
+    g_free(fidp);
+    return retval;
+}
+
+static void put_fid(V9fsState *s, V9fsFidState *fidp)
+{
+    BUG_ON(!fidp->ref);
+    fidp->ref--;
+    if (!fidp->ref && fidp->clunked) {
+        free_fid(s, fidp);
+    }
+}
+
+static int clunk_fid(V9fsState *s, int32_t fid)
+{
     V9fsFidState **fidpp, *fidp;
 
     for (fidpp = &s->fid_list; *fidpp; fidpp = &(*fidpp)->next) {
@@ -313,20 +339,10 @@ static int free_fid(V9fsState *s, int32_t fid)
     if (*fidpp == NULL) {
         return -ENOENT;
     }
-
     fidp = *fidpp;
     *fidpp = fidp->next;
-
-    if (fidp->fid_type == P9_FID_FILE) {
-        retval = v9fs_co_close(s, fidp);
-    } else if (fidp->fid_type == P9_FID_DIR) {
-        retval = v9fs_co_closedir(s, fidp);
-    } else if (fidp->fid_type == P9_FID_XATTR) {
-        retval = v9fs_xattr_fid_clunk(s, fidp);
-    }
-    v9fs_string_free(&fidp->path);
-    g_free(fidp);
-    return retval;
+    fidp->clunked = 1;
+    return 0;
 }
 
 #define P9_QID_TYPE_DIR         0x80
@@ -1014,19 +1030,21 @@ static void v9fs_attach(void *opaque)
     fidp = alloc_fid(s, fid);
     if (fidp == NULL) {
         err = -EINVAL;
-        goto out;
+        goto out_nofid;
     }
     fidp->uid = n_uname;
     v9fs_string_sprintf(&fidp->path, "%s", "/");
     err = fid_to_qid(s, fidp, &qid);
     if (err < 0) {
         err = -EINVAL;
-        free_fid(s, fid);
+        clunk_fid(s, fid);
         goto out;
     }
     offset += pdu_marshal(pdu, offset, "Q", &qid);
     err = offset;
 out:
+    put_fid(s, fidp);
+out_nofid:
     complete_pdu(s, pdu, err);
     v9fs_string_free(&uname);
     v9fs_string_free(&aname);
@@ -1044,10 +1062,11 @@ static void v9fs_stat(void *opaque)
     V9fsState *s = pdu->s;
 
     pdu_unmarshal(pdu, offset, "d", &fid);
-    fidp = lookup_fid(s, fid);
+
+    fidp = get_fid(s, fid);
     if (fidp == NULL) {
         err = -ENOENT;
-        goto out;
+        goto out_nofid;
     }
     err = v9fs_co_lstat(s, &fidp->path, &stbuf);
     if (err < 0) {
@@ -1061,6 +1080,8 @@ static void v9fs_stat(void *opaque)
     err = offset;
     v9fs_stat_free(&v9stat);
 out:
+    put_fid(s, fidp);
+out_nofid:
     complete_pdu(s, pdu, err);
 }
 
@@ -1078,10 +1099,10 @@ static void v9fs_getattr(void *opaque)
 
     pdu_unmarshal(pdu, offset, "dq", &fid, &request_mask);
 
-    fidp = lookup_fid(s, fid);
+    fidp = get_fid(s, fid);
     if (fidp == NULL) {
         retval = -ENOENT;
-        goto out;
+        goto out_nofid;
     }
     /*
      * Currently we only support BASIC fields in stat, so there is no
@@ -1095,6 +1116,8 @@ static void v9fs_getattr(void *opaque)
     retval = offset;
     retval += pdu_marshal(pdu, offset, "A", &v9stat_dotl);
 out:
+    put_fid(s, fidp);
+out_nofid:
     complete_pdu(s, pdu, retval);
 }
 
@@ -1122,10 +1145,10 @@ static void v9fs_setattr(void *opaque)
 
     pdu_unmarshal(pdu, offset, "dI", &fid, &v9iattr);
 
-    fidp = lookup_fid(s, fid);
+    fidp = get_fid(s, fid);
     if (fidp == NULL) {
         err = -EINVAL;
-        goto out;
+        goto out_nofid;
     }
     if (v9iattr.valid & ATTR_MODE) {
         err = v9fs_co_chmod(s, &fidp->path, v9iattr.mode);
@@ -1187,6 +1210,8 @@ static void v9fs_setattr(void *opaque)
     }
     err = offset;
 out:
+    put_fid(s, fidp);
+out_nofid:
     complete_pdu(s, pdu, err);
 }
 
@@ -1213,7 +1238,7 @@ static void v9fs_walk(void *opaque)
     int32_t fid, newfid;
     V9fsString *wnames = NULL;
     V9fsFidState *fidp;
-    V9fsFidState *newfidp;
+    V9fsFidState *newfidp = NULL;;
     V9fsPDU *pdu = opaque;
     V9fsState *s = pdu->s;
 
@@ -1229,12 +1254,12 @@ static void v9fs_walk(void *opaque)
 
     } else if (nwnames > P9_MAXWELEM) {
         err = -EINVAL;
-        goto out;
+        goto out_nofid;
     }
-    fidp = lookup_fid(s, fid);
+    fidp = get_fid(s, fid);
     if (fidp == NULL) {
         err = -ENOENT;
-        goto out;
+        goto out_nofid;
     }
     if (fid == newfid) {
         BUG_ON(fidp->fid_type != P9_FID_NONE);
@@ -1267,7 +1292,7 @@ static void v9fs_walk(void *opaque)
             v9fs_string_copy(&newfidp->path, &path);
             err = v9fs_co_lstat(s, &newfidp->path, &stbuf);
             if (err < 0) {
-                free_fid(s, newfidp->fid);
+                clunk_fid(s, newfidp->fid);
                 v9fs_string_free(&path);
                 goto out;
             }
@@ -1277,6 +1302,11 @@ static void v9fs_walk(void *opaque)
     }
     err = v9fs_walk_marshal(pdu, nwnames, qids);
 out:
+    put_fid(s, fidp);
+    if (newfidp) {
+        put_fid(s, newfidp);
+    }
+out_nofid:
     complete_pdu(s, pdu, err);
     if (nwnames && nwnames <= P9_MAXWELEM) {
         for (name_idx = 0; name_idx < nwnames; name_idx++) {
@@ -1325,10 +1355,10 @@ static void v9fs_open(void *opaque)
     } else {
         pdu_unmarshal(pdu, offset, "db", &fid, &mode);
     }
-    fidp = lookup_fid(s, fid);
+    fidp = get_fid(s, fid);
     if (fidp == NULL) {
         err = -ENOENT;
-        goto out;
+        goto out_nofid;
     }
     BUG_ON(fidp->fid_type != P9_FID_NONE);
 
@@ -1364,6 +1394,8 @@ static void v9fs_open(void *opaque)
         err = offset;
     }
 out:
+    put_fid(s, fidp);
+out_nofid:
     complete_pdu(s, pdu, err);
 }
 
@@ -1385,10 +1417,10 @@ static void v9fs_lcreate(void *opaque)
     pdu_unmarshal(pdu, offset, "dsddd", &dfid, &name, &flags,
                   &mode, &gid);
 
-    fidp = lookup_fid(pdu->s, dfid);
+    fidp = get_fid(pdu->s, dfid);
     if (fidp == NULL) {
         err = -ENOENT;
-        goto out;
+        goto out_nofid;
     }
     v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
 
@@ -1415,6 +1447,8 @@ static void v9fs_lcreate(void *opaque)
     offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
     err = offset;
 out:
+    put_fid(pdu->s, fidp);
+out_nofid:
     complete_pdu(pdu->s, pdu, err);
     v9fs_string_free(&name);
     v9fs_string_free(&fullname);
@@ -1431,16 +1465,17 @@ static void v9fs_fsync(void *opaque)
     V9fsState *s = pdu->s;
 
     pdu_unmarshal(pdu, offset, "dd", &fid, &datasync);
-    fidp = lookup_fid(s, fid);
+    fidp = get_fid(s, fid);
     if (fidp == NULL) {
         err = -ENOENT;
-        goto out;
+        goto out_nofid;
     }
     err = v9fs_co_fsync(s, fidp, datasync);
     if (!err) {
         err = offset;
     }
-out:
+    put_fid(s, fidp);
+out_nofid:
     complete_pdu(s, pdu, err);
 }
 
@@ -1449,16 +1484,25 @@ static void v9fs_clunk(void *opaque)
     int err;
     int32_t fid;
     size_t offset = 7;
+    V9fsFidState *fidp;
     V9fsPDU *pdu = opaque;
     V9fsState *s = pdu->s;
 
     pdu_unmarshal(pdu, offset, "d", &fid);
-    err = free_fid(s, fid);
+
+    fidp = get_fid(s, fid);
+    if (fidp == NULL) {
+        err = -ENOENT;
+        goto out_nofid;
+    }
+    err = clunk_fid(s, fidp->fid);
     if (err < 0) {
         goto out;
     }
     err = offset;
 out:
+    put_fid(s, fidp);
+out_nofid:
     complete_pdu(s, pdu, err);
 }
 
@@ -1557,10 +1601,11 @@ static void v9fs_read(void *opaque)
     V9fsState *s = pdu->s;
 
     pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &max_count);
-    fidp = lookup_fid(s, fid);
+
+    fidp = get_fid(s, fid);
     if (fidp == NULL) {
         err = -EINVAL;
-        goto out;
+        goto out_nofid;
     }
     if (fidp->fid_type == P9_FID_DIR) {
 
@@ -1612,6 +1657,8 @@ static void v9fs_read(void *opaque)
         err = -EINVAL;
     }
 out:
+    put_fid(s, fidp);
+out_nofid:
     complete_pdu(s, pdu, err);
 }
 
@@ -1696,8 +1743,12 @@ static void v9fs_readdir(void *opaque)
 
     pdu_unmarshal(pdu, offset, "dqd", &fid, &initial_offset, &max_count);
 
-    fidp = lookup_fid(s, fid);
-    if (fidp == NULL || !fidp->fs.dir) {
+    fidp = get_fid(s, fid);
+    if (fidp == NULL) {
+        retval = -EINVAL;
+        goto out_nofid;
+    }
+    if (!fidp->fs.dir) {
         retval = -EINVAL;
         goto out;
     }
@@ -1715,6 +1766,8 @@ static void v9fs_readdir(void *opaque)
     retval += pdu_marshal(pdu, offset, "d", count);
     retval += count;
 out:
+    put_fid(s, fidp);
+out_nofid:
     complete_pdu(s, pdu, retval);
 }
 
@@ -1779,10 +1832,11 @@ static void v9fs_write(void *opaque)
     V9fsState *s = pdu->s;
 
     pdu_unmarshal(pdu, offset, "dqdv", &fid, &off, &count, sg, &cnt);
-    fidp = lookup_fid(s, fid);
+
+    fidp = get_fid(s, fid);
     if (fidp == NULL) {
         err = -EINVAL;
-        goto out;
+        goto out_nofid;
     }
     if (fidp->fid_type == P9_FID_FILE) {
         if (fidp->fs.fd == -1) {
@@ -1822,6 +1876,8 @@ static void v9fs_write(void *opaque)
     offset += pdu_marshal(pdu, offset, "d", total);
     err = offset;
 out:
+    put_fid(s, fidp);
+out_nofid:
     complete_pdu(s, pdu, err);
 }
 
@@ -1846,10 +1902,10 @@ static void v9fs_create(void *opaque)
     pdu_unmarshal(pdu, offset, "dsdbs", &fid, &name,
                   &perm, &mode, &extension);
 
-    fidp = lookup_fid(pdu->s, fid);
+    fidp = get_fid(pdu->s, fid);
     if (fidp == NULL) {
         err = -EINVAL;
-        goto out;
+        goto out_nofid;
     }
 
     v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
@@ -1879,15 +1935,17 @@ static void v9fs_create(void *opaque)
         }
     } else if (perm & P9_STAT_MODE_LINK) {
         int32_t nfid = atoi(extension.data);
-        V9fsFidState *nfidp = lookup_fid(pdu->s, nfid);
+        V9fsFidState *nfidp = get_fid(pdu->s, nfid);
         if (nfidp == NULL) {
             err = -EINVAL;
             goto out;
         }
         err = v9fs_co_link(pdu->s, &nfidp->path, &fullname);
         if (err < 0) {
+            put_fid(pdu->s, nfidp);
             goto out;
         }
+        put_fid(pdu->s, nfidp);
     } else if (perm & P9_STAT_MODE_DEVICE) {
         char ctype;
         uint32_t major, minor;
@@ -1950,6 +2008,8 @@ static void v9fs_create(void *opaque)
     offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
     err = offset;
 out:
+    put_fid(pdu->s, fidp);
+out_nofid:
    complete_pdu(pdu->s, pdu, err);
    v9fs_string_free(&name);
    v9fs_string_free(&extension);
@@ -1973,10 +2033,10 @@ static void v9fs_symlink(void *opaque)
     v9fs_string_init(&fullname);
     pdu_unmarshal(pdu, offset, "dssd", &dfid, &name, &symname, &gid);
 
-    dfidp = lookup_fid(pdu->s, dfid);
+    dfidp = get_fid(pdu->s, dfid);
     if (dfidp == NULL) {
         err = -EINVAL;
-        goto out;
+        goto out_nofid;
     }
 
     v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name.data);
@@ -1992,6 +2052,8 @@ static void v9fs_symlink(void *opaque)
     offset += pdu_marshal(pdu, offset, "Q", &qid);
     err = offset;
 out:
+    put_fid(pdu->s, dfidp);
+out_nofid:
     complete_pdu(pdu->s, pdu, err);
     v9fs_string_free(&name);
     v9fs_string_free(&symname);
@@ -2021,13 +2083,13 @@ static void v9fs_link(void *opaque)
 
     pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
 
-    dfidp = lookup_fid(s, dfid);
+    dfidp = get_fid(s, dfid);
     if (dfidp == NULL) {
         err = -ENOENT;
-        goto out;
+        goto out_nofid;
     }
 
-    oldfidp = lookup_fid(s, oldfid);
+    oldfidp = get_fid(s, oldfid);
     if (oldfidp == NULL) {
         err = -ENOENT;
         goto out;
@@ -2041,6 +2103,8 @@ static void v9fs_link(void *opaque)
     v9fs_string_free(&fullname);
 
 out:
+    put_fid(s, dfidp);
+out_nofid:
     v9fs_string_free(&name);
     complete_pdu(s, pdu, err);
 }
@@ -2055,10 +2119,10 @@ static void v9fs_remove(void *opaque)
 
     pdu_unmarshal(pdu, offset, "d", &fid);
 
-    fidp = lookup_fid(pdu->s, fid);
+    fidp = get_fid(pdu->s, fid);
     if (fidp == NULL) {
         err = -EINVAL;
-        goto out;
+        goto out_nofid;
     }
     err = v9fs_co_remove(pdu->s, &fidp->path);
     if (!err) {
@@ -2066,8 +2130,9 @@ static void v9fs_remove(void *opaque)
     }
 
     /* For TREMOVE we need to clunk the fid even on failed remove */
-    free_fid(pdu->s, fidp->fid);
-out:
+    clunk_fid(pdu->s, fidp->fid);
+    put_fid(pdu->s, fidp);
+out_nofid:
     complete_pdu(pdu->s, pdu, err);
 }
 
@@ -2076,14 +2141,14 @@ static int v9fs_complete_rename(V9fsState *s, V9fsFidState *fidp,
 {
     char *end;
     int err = 0;
+    V9fsFidState *dirfidp = NULL;
     char *old_name, *new_name;
 
     if (newdirfid != -1) {
-        V9fsFidState *dirfidp;
-        dirfidp = lookup_fid(s, newdirfid);
+        dirfidp = get_fid(s, newdirfid);
         if (dirfidp == NULL) {
             err = -ENOENT;
-            goto out;
+            goto out_nofid;
         }
         BUG_ON(dirfidp->fid_type != P9_FID_NONE);
 
@@ -2136,6 +2201,10 @@ static int v9fs_complete_rename(V9fsState *s, V9fsFidState *fidp,
         v9fs_string_copy(&fidp->path, name);
     }
 out:
+    if (dirfidp) {
+        put_fid(s, dirfidp);
+    }
+out_nofid:
     return err;
 }
 
@@ -2152,10 +2221,10 @@ static void v9fs_rename(void *opaque)
 
     pdu_unmarshal(pdu, offset, "dds", &fid, &newdirfid, &name);
 
-    fidp = lookup_fid(s, fid);
+    fidp = get_fid(s, fid);
     if (fidp == NULL) {
         err = -ENOENT;
-        goto out;
+        goto out_nofid;
     }
     BUG_ON(fidp->fid_type != P9_FID_NONE);
 
@@ -2163,7 +2232,8 @@ static void v9fs_rename(void *opaque)
     if (!err) {
         err = offset;
     }
-out:
+    put_fid(s, fidp);
+out_nofid:
     complete_pdu(s, pdu, err);
     v9fs_string_free(&name);
 }
@@ -2181,10 +2251,11 @@ static void v9fs_wstat(void *opaque)
     V9fsState *s = pdu->s;
 
     pdu_unmarshal(pdu, offset, "dwS", &fid, &unused, &v9stat);
-    fidp = lookup_fid(s, fid);
+
+    fidp = get_fid(s, fid);
     if (fidp == NULL) {
         err = -EINVAL;
-        goto out;
+        goto out_nofid;
     }
     /* do we need to sync the file? */
     if (donttouch_stat(&v9stat)) {
@@ -2250,6 +2321,8 @@ static void v9fs_wstat(void *opaque)
     }
     err = offset;
 out:
+    put_fid(s, fidp);
+out_nofid:
     v9fs_stat_free(&v9stat);
     complete_pdu(s, pdu, err);
 }
@@ -2310,10 +2383,10 @@ static void v9fs_statfs(void *opaque)
     V9fsState *s = pdu->s;
 
     pdu_unmarshal(pdu, offset, "d", &fid);
-    fidp = lookup_fid(s, fid);
+    fidp = get_fid(s, fid);
     if (fidp == NULL) {
         retval = -ENOENT;
-        goto out;
+        goto out_nofid;
     }
     retval = v9fs_co_statfs(s, &fidp->path, &stbuf);
     if (retval < 0) {
@@ -2322,6 +2395,8 @@ static void v9fs_statfs(void *opaque)
     retval = offset;
     retval += v9fs_fill_statfs(s, pdu, &stbuf);
 out:
+    put_fid(s, fidp);
+out_nofid:
     complete_pdu(s, pdu, retval);
     return;
 }
@@ -2347,10 +2422,10 @@ static void v9fs_mknod(void *opaque)
     pdu_unmarshal(pdu, offset, "dsdddd", &fid, &name, &mode,
                   &major, &minor, &gid);
 
-    fidp = lookup_fid(s, fid);
+    fidp = get_fid(s, fid);
     if (fidp == NULL) {
         err = -ENOENT;
-        goto out;
+        goto out_nofid;
     }
     v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
     err = v9fs_co_mknod(s, &fullname, fidp->uid, gid,
@@ -2366,6 +2441,8 @@ static void v9fs_mknod(void *opaque)
     err = offset;
     err += pdu_marshal(pdu, offset, "Q", &qid);
 out:
+    put_fid(s, fidp);
+out_nofid:
     complete_pdu(s, pdu, err);
     v9fs_string_free(&fullname);
     v9fs_string_free(&name);
@@ -2399,12 +2476,12 @@ static void v9fs_lock(void *opaque)
     /* We support only block flag now (that too ignored currently) */
     if (flock->flags & ~P9_LOCK_FLAGS_BLOCK) {
         err = -EINVAL;
-        goto out;
+        goto out_nofid;
     }
-    fidp = lookup_fid(s, fid);
+    fidp = get_fid(s, fid);
     if (fidp == NULL) {
         err = -ENOENT;
-        goto out;
+        goto out_nofid;
     }
     err = v9fs_co_fstat(s, fidp->fs.fd, &stbuf);
     if (err < 0) {
@@ -2412,6 +2489,8 @@ static void v9fs_lock(void *opaque)
     }
     status = P9_LOCK_SUCCESS;
 out:
+    put_fid(s, fidp);
+out_nofid:
     err = offset;
     err += pdu_marshal(pdu, offset, "b", status);
     complete_pdu(s, pdu, err);
@@ -2437,10 +2516,10 @@ static void v9fs_getlock(void *opaque)
                   &glock->start, &glock->length, &glock->proc_id,
                   &glock->client_id);
 
-    fidp = lookup_fid(s, fid);
+    fidp = get_fid(s, fid);
     if (fidp == NULL) {
         err = -ENOENT;
-        goto out;
+        goto out_nofid;
     }
     err = v9fs_co_fstat(s, fidp->fs.fd, &stbuf);
     if (err < 0) {
@@ -2452,6 +2531,8 @@ static void v9fs_getlock(void *opaque)
                           &glock->client_id);
     err = offset;
 out:
+    put_fid(s, fidp);
+out_nofid:
     complete_pdu(s, pdu, err);
     g_free(glock);
 }
@@ -2472,10 +2553,10 @@ static void v9fs_mkdir(void *opaque)
     v9fs_string_init(&fullname);
     pdu_unmarshal(pdu, offset, "dsdd", &fid, &name, &mode, &gid);
 
-    fidp = lookup_fid(pdu->s, fid);
+    fidp = get_fid(pdu->s, fid);
     if (fidp == NULL) {
         err = -ENOENT;
-        goto out;
+        goto out_nofid;
     }
     v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
     err = v9fs_co_mkdir(pdu->s, fullname.data, mode, fidp->uid, gid);
@@ -2490,6 +2571,8 @@ static void v9fs_mkdir(void *opaque)
     offset += pdu_marshal(pdu, offset, "Q", &qid);
     err = offset;
 out:
+    put_fid(pdu->s, fidp);
+out_nofid:
     complete_pdu(pdu->s, pdu, err);
     v9fs_string_free(&fullname);
     v9fs_string_free(&name);
@@ -2503,15 +2586,15 @@ static void v9fs_xattrwalk(void *opaque)
     size_t offset = 7;
     int32_t fid, newfid;
     V9fsFidState *file_fidp;
-    V9fsFidState *xattr_fidp;
+    V9fsFidState *xattr_fidp = NULL;
     V9fsPDU *pdu = opaque;
     V9fsState *s = pdu->s;
 
     pdu_unmarshal(pdu, offset, "dds", &fid, &newfid, &name);
-    file_fidp = lookup_fid(s, fid);
+    file_fidp = get_fid(s, fid);
     if (file_fidp == NULL) {
         err = -ENOENT;
-        goto out;
+        goto out_nofid;
     }
     xattr_fidp = alloc_fid(s, newfid);
     if (xattr_fidp == NULL) {
@@ -2526,7 +2609,7 @@ static void v9fs_xattrwalk(void *opaque)
         size = v9fs_co_llistxattr(s, &xattr_fidp->path, NULL, 0);
         if (size < 0) {
             err = size;
-            free_fid(s, xattr_fidp->fid);
+            clunk_fid(s, xattr_fidp->fid);
             goto out;
         }
         /*
@@ -2541,7 +2624,7 @@ static void v9fs_xattrwalk(void *opaque)
                                      xattr_fidp->fs.xattr.value,
                                      xattr_fidp->fs.xattr.len);
             if (err < 0) {
-                free_fid(s, xattr_fidp->fid);
+                clunk_fid(s, xattr_fidp->fid);
                 goto out;
             }
         }
@@ -2556,7 +2639,7 @@ static void v9fs_xattrwalk(void *opaque)
                                  &name, NULL, 0);
         if (size < 0) {
             err = size;
-            free_fid(s, xattr_fidp->fid);
+            clunk_fid(s, xattr_fidp->fid);
             goto out;
         }
         /*
@@ -2571,7 +2654,7 @@ static void v9fs_xattrwalk(void *opaque)
                                     &name, xattr_fidp->fs.xattr.value,
                                     xattr_fidp->fs.xattr.len);
             if (err < 0) {
-                free_fid(s, xattr_fidp->fid);
+                clunk_fid(s, xattr_fidp->fid);
                 goto out;
             }
         }
@@ -2579,6 +2662,11 @@ static void v9fs_xattrwalk(void *opaque)
         err = offset;
     }
 out:
+    put_fid(s, file_fidp);
+    if (xattr_fidp) {
+        put_fid(s, xattr_fidp);
+    }
+out_nofid:
     complete_pdu(s, pdu, err);
     v9fs_string_free(&name);
 }
@@ -2599,10 +2687,10 @@ static void v9fs_xattrcreate(void *opaque)
     pdu_unmarshal(pdu, offset, "dsqd",
                   &fid, &name, &size, &flags);
 
-    file_fidp = lookup_fid(s, fid);
+    file_fidp = get_fid(s, fid);
     if (file_fidp == NULL) {
         err = -EINVAL;
-        goto out;
+        goto out_nofid;
     }
     /* Make the file fid point to xattr */
     xattr_fidp = file_fidp;
@@ -2618,7 +2706,8 @@ static void v9fs_xattrcreate(void *opaque)
         xattr_fidp->fs.xattr.value = NULL;
     }
     err = offset;
-out:
+    put_fid(s, file_fidp);
+out_nofid:
     complete_pdu(s, pdu, err);
     v9fs_string_free(&name);
 }
@@ -2633,10 +2722,10 @@ static void v9fs_readlink(void *opaque)
     V9fsFidState *fidp;
 
     pdu_unmarshal(pdu, offset, "d", &fid);
-    fidp = lookup_fid(pdu->s, fid);
+    fidp = get_fid(pdu->s, fid);
     if (fidp == NULL) {
         err = -ENOENT;
-        goto out;
+        goto out_nofid;
     }
 
     v9fs_string_init(&target);
@@ -2648,6 +2737,8 @@ static void v9fs_readlink(void *opaque)
     err = offset;
     v9fs_string_free(&target);
 out:
+    put_fid(pdu->s, fidp);
+out_nofid:
     complete_pdu(pdu->s, pdu, err);
 }
 
diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
index 1d8c1b1..e16e5f4 100644
--- a/hw/9pfs/virtio-9p.h
+++ b/hw/9pfs/virtio-9p.h
@@ -203,6 +203,8 @@ struct V9fsFidState
 	V9fsXattr xattr;
     } fs;
     uid_t uid;
+    int ref;
+    int clunked;
     V9fsFidState *next;
 };
 


More information about the Spice-commits mailing list