[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] [ioemu] Update to qemu 0.90.



# HG changeset patch
# User Christian Limpach <Christian.Limpach@xxxxxxxxxxxxx>
# Date 1178716635 -3600
# Node ID 00618037d37d04e614080d3067cc5ba6b1b1ef9e
# Parent  d2ef85c6bf84cc619ca2d42c2edfc6229e70a6ad
[ioemu] Update to qemu 0.90.

Signed-off-by: Christian Limpach <Christian.Limpach@xxxxxxxxxxxxx>
---
 tools/ioemu/.CVS/Entries.Log                        |    7 
 tools/ioemu/README.distrib                          |   16 
 tools/ioemu/hw/acpi-dsdt.dsl                        |  559 ----
 tools/ioemu/hw/acpi-dsdt.hex                        |  278 --
 tools/ioemu/hw/lance.c                              |  462 ----
 tools/ioemu/.CVS/Entries                            |  208 -
 tools/ioemu/.CVS/Tag                                |    2 
 tools/ioemu/.cvsignore                              |   21 
 tools/ioemu/Changelog                               |   18 
 tools/ioemu/LICENSE                                 |   15 
 tools/ioemu/Makefile                                |   48 
 tools/ioemu/Makefile.target                         |  225 +-
 tools/ioemu/VERSION                                 |    2 
 tools/ioemu/audio/.CVS/Entries                      |   38 
 tools/ioemu/audio/.CVS/Tag                          |    2 
 tools/ioemu/audio/wavaudio.c                        |    4 
 tools/ioemu/audio/wavcapture.c                      |   31 
 tools/ioemu/block-bochs.c                           |   48 
 tools/ioemu/block-cloop.c                           |    6 
 tools/ioemu/block-cow.c                             |   38 
 tools/ioemu/block-dmg.c                             |    8 
 tools/ioemu/block-qcow.c                            |  382 ++-
 tools/ioemu/block-qcow2.c                           | 2246 ++++++++++++++++++++
 tools/ioemu/block-raw.c                             | 1353 ++++++++++++
 tools/ioemu/block-vmdk.c                            |  408 +++
 tools/ioemu/block-vpc.c                             |   13 
 tools/ioemu/block-vvfat.c                           |   26 
 tools/ioemu/block.c                                 | 1330 ++++++++---
 tools/ioemu/block_int.h                             |   61 
 tools/ioemu/check_ops.sh                            |   47 
 tools/ioemu/configure                               |  179 +
 tools/ioemu/console.c                               |  208 +
 tools/ioemu/cpu-all.h                               |   18 
 tools/ioemu/cpu-defs.h                              |    8 
 tools/ioemu/cpu-exec.c                              |  238 +-
 tools/ioemu/cutils.c                                |   83 
 tools/ioemu/disas.c                                 |   14 
 tools/ioemu/dyngen-exec.h                           |    5 
 tools/ioemu/dyngen.c                                |  301 ++
 tools/ioemu/dyngen.h                                |   60 
 tools/ioemu/elf.h                                   |    2 
 tools/ioemu/elf_ops.h                               |    4 
 tools/ioemu/exec-all.h                              |   12 
 tools/ioemu/exec.c                                  |   33 
 tools/ioemu/fpu/.CVS/Entries                        |   12 
 tools/ioemu/fpu/.CVS/Tag                            |    2 
 tools/ioemu/fpu/softfloat-native.c                  |   34 
 tools/ioemu/fpu/softfloat-native.h                  |   62 
 tools/ioemu/fpu/softfloat-specialize.h              |   16 
 tools/ioemu/fpu/softfloat.c                         |   65 
 tools/ioemu/fpu/softfloat.h                         |   68 
 tools/ioemu/gdbstub.c                               |  411 +++
 tools/ioemu/gdbstub.h                               |   10 
 tools/ioemu/hostregs_helper.h                       |   98 
 tools/ioemu/hw/.CVS/Entries                         |  185 -
 tools/ioemu/hw/.CVS/Tag                             |    2 
 tools/ioemu/hw/acpi.c                               |  670 ++---
 tools/ioemu/hw/adb.c                                |    4 
 tools/ioemu/hw/apb_pci.c                            |   49 
 tools/ioemu/hw/apic.c                               |   16 
 tools/ioemu/hw/arm_boot.c                           |   54 
 tools/ioemu/hw/arm_gic.c                            |  547 ++++
 tools/ioemu/hw/arm_sysctl.c                         |  208 +
 tools/ioemu/hw/arm_timer.c                          |   12 
 tools/ioemu/hw/cirrus_vga.c                         |   32 
 tools/ioemu/hw/cs4231.c                             |  183 +
 tools/ioemu/hw/esp.c                                |  392 +--
 tools/ioemu/hw/fdc.c                                |   43 
 tools/ioemu/hw/grackle_pci.c                        |   15 
 tools/ioemu/hw/gt64xxx.c                            |  648 +++++
 tools/ioemu/hw/i8259.c                              |    7 
 tools/ioemu/hw/ide.c                                |  813 +++----
 tools/ioemu/hw/integratorcp.c                       |    6 
 tools/ioemu/hw/iommu.c                              |   45 
 tools/ioemu/hw/isa_mmio.c                           |  102 
 tools/ioemu/hw/lsi53c895a.c                         |  499 +++-
 tools/ioemu/hw/mc146818rtc.c                        |   26 
 tools/ioemu/hw/mips_int.c                           |   39 
 tools/ioemu/hw/mips_malta.c                         |  590 +++++
 tools/ioemu/hw/mips_r4k.c                           |  384 +--
 tools/ioemu/hw/mips_timer.c                         |   83 
 tools/ioemu/hw/ne2000.c                             |   36 
 tools/ioemu/hw/pc.c                                 |  251 --
 tools/ioemu/hw/pci.c                                |  167 +
 tools/ioemu/hw/pcnet.c                              |  601 +++--
 tools/ioemu/hw/pflash_cfi02.c                       |    1 
 tools/ioemu/hw/piix4acpi.c                          |   16 
 tools/ioemu/hw/piix_pci.c                           |  523 ++--
 tools/ioemu/hw/pl011.c                              |    4 
 tools/ioemu/hw/pl080.c                              |   32 
 tools/ioemu/hw/pl110.c                              |    5 
 tools/ioemu/hw/pl110_template.h                     |    2 
 tools/ioemu/hw/ppc.c                                |   58 
 tools/ioemu/hw/ppc_chrp.c                           |   26 
 tools/ioemu/hw/ppc_prep.c                           |    5 
 tools/ioemu/hw/prep_pci.c                           |   14 
 tools/ioemu/hw/ps2.c                                |    2 
 tools/ioemu/hw/realview.c                           |  138 +
 tools/ioemu/hw/rtl8139.c                            |   20 
 tools/ioemu/hw/scsi-disk.c                          |  507 ++--
 tools/ioemu/hw/serial.c                             |   23 
 tools/ioemu/hw/sh7750.c                             |   10 
 tools/ioemu/hw/slavio_misc.c                        |    3 
 tools/ioemu/hw/slavio_serial.c                      |  282 +-
 tools/ioemu/hw/smbus.h                              |   38 
 tools/ioemu/hw/smbus_eeprom.c                       |   94 
 tools/ioemu/hw/smc91c111.c                          |    5 
 tools/ioemu/hw/sparc32_dma.c                        |  283 ++
 tools/ioemu/hw/sun4m.c                              |   28 
 tools/ioemu/hw/sun4u.c                              |    2 
 tools/ioemu/hw/tcx.c                                |   88 
 tools/ioemu/hw/unin_pci.c                           |   17 
 tools/ioemu/hw/usb-hid.c                            |   26 
 tools/ioemu/hw/usb-hub.c                            |   48 
 tools/ioemu/hw/usb-msd.c                            |  244 +-
 tools/ioemu/hw/usb-ohci.c                           |  178 +
 tools/ioemu/hw/usb-uhci.c                           |  263 +-
 tools/ioemu/hw/usb.c                                |   37 
 tools/ioemu/hw/usb.h                                |   58 
 tools/ioemu/hw/versatile_pci.c                      |   41 
 tools/ioemu/hw/versatilepb.c                        |  198 -
 tools/ioemu/hw/vga.c                                |  187 +
 tools/ioemu/hw/vga_int.h                            |    7 
 tools/ioemu/hw/xen_platform.c                       |   19 
 tools/ioemu/keymaps.c                               |   63 
 tools/ioemu/keymaps/.CVS/Entries                    |   70 
 tools/ioemu/keymaps/.CVS/Tag                        |    2 
 tools/ioemu/keymaps/ja                              |    1 
 tools/ioemu/kqemu.c                                 |   11 
 tools/ioemu/loader.c                                |   12 
 tools/ioemu/monitor.c                               |  133 -
 tools/ioemu/osdep.c                                 |  458 ----
 tools/ioemu/osdep.h                                 |   39 
 tools/ioemu/patches/acpi-poweroff-support           |    2 
 tools/ioemu/patches/acpi-support                    |  101 
 tools/ioemu/patches/acpi-timer-support              |    2 
 tools/ioemu/patches/domain-destroy                  |   10 
 tools/ioemu/patches/domain-reset                    |   20 
 tools/ioemu/patches/domain-timeoffset               |   66 
 tools/ioemu/patches/fix-interrupt-routing           |   31 
 tools/ioemu/patches/fix-vga-scanning-code-overflow  |    8 
 tools/ioemu/patches/hypervisor-pit                  |   18 
 tools/ioemu/patches/hypervisor-rtc                  |   12 
 tools/ioemu/patches/ide-error-reporting             |   36 
 tools/ioemu/patches/ioemu-buffer-pio-ia64           |   47 
 tools/ioemu/patches/ioemu-ia64                      |   21 
 tools/ioemu/patches/ioemu-save-restore              |   85 
 tools/ioemu/patches/ioemu-save-restore-acpi         |   11 
 tools/ioemu/patches/ioemu-save-restore-ide          |   16 
 tools/ioemu/patches/ioemu-save-restore-logdirty     |   12 
 tools/ioemu/patches/ioemu-save-restore-ne2000       |   21 
 tools/ioemu/patches/ioemu-save-restore-pcnet        |   84 
 tools/ioemu/patches/ioemu-save-restore-rtl8139      |   10 
 tools/ioemu/patches/ioemu-save-restore-timer        |    4 
 tools/ioemu/patches/ioemu-save-restore-usb          |   54 
 tools/ioemu/patches/ne2000-bounds-checks            |    2 
 tools/ioemu/patches/qemu-64bit                      |   32 
 tools/ioemu/patches/qemu-allow-disable-sdl          |    8 
 tools/ioemu/patches/qemu-block-device-bounds-checks |   22 
 tools/ioemu/patches/qemu-bootorder                  |   79 
 tools/ioemu/patches/qemu-bugfixes                   |   19 
 tools/ioemu/patches/qemu-cirrus-bounds-checks       |    6 
 tools/ioemu/patches/qemu-cleanup                    |   36 
 tools/ioemu/patches/qemu-daemonize                  |    4 
 tools/ioemu/patches/qemu-dm                         |  176 -
 tools/ioemu/patches/qemu-dma-null-pointer-check     |    2 
 tools/ioemu/patches/qemu-hvm-banner                 |   20 
 tools/ioemu/patches/qemu-infrastructure             |    7 
 tools/ioemu/patches/qemu-init-vgabios               |   12 
 tools/ioemu/patches/qemu-logging                    |   18 
 tools/ioemu/patches/qemu-no-apic                    |   18 
 tools/ioemu/patches/qemu-nobios                     |   17 
 tools/ioemu/patches/qemu-pci                        |   20 
 tools/ioemu/patches/qemu-pci-vendor-ids             |   16 
 tools/ioemu/patches/qemu-serial-fixes               |   18 
 tools/ioemu/patches/qemu-smp                        |   24 
 tools/ioemu/patches/qemu-target-i386-dm             |   59 
 tools/ioemu/patches/qemu-timer                      |   10 
 tools/ioemu/patches/qemu-tunable-ide-write-cache    |   21 
 tools/ioemu/patches/remove-pci-bridge-setup         |   35 
 tools/ioemu/patches/rtl8139-bound-chaining          |    2 
 tools/ioemu/patches/scsi                            |   70 
 tools/ioemu/patches/serial-non-block                |    4 
 tools/ioemu/patches/serial-port-rate-limit          |   20 
 tools/ioemu/patches/series                          |   11 
 tools/ioemu/patches/shadow-vram                     |   16 
 tools/ioemu/patches/shared-vram                     |   44 
 tools/ioemu/patches/support-xm-console              |   31 
 tools/ioemu/patches/tpm-tis-device                  |   19 
 tools/ioemu/patches/usb-mouse-tablet-status-check   |   52 
 tools/ioemu/patches/vnc-access-monitor-vt           |   92 
 tools/ioemu/patches/vnc-backoff-screen-scan         |   32 
 tools/ioemu/patches/vnc-cleanup                     |   20 
 tools/ioemu/patches/vnc-display-find-unused         |  106 
 tools/ioemu/patches/vnc-fix-signedness              |   70 
 tools/ioemu/patches/vnc-fix-version-check           |    4 
 tools/ioemu/patches/vnc-fixes                       |   85 
 tools/ioemu/patches/vnc-listen-specific-interface   |  115 -
 tools/ioemu/patches/vnc-password                    |   38 
 tools/ioemu/patches/vnc-protocol-fixes              |    8 
 tools/ioemu/patches/vnc-start-vncviewer             |   48 
 tools/ioemu/patches/vnc-title-domain-name           |    6 
 tools/ioemu/patches/xen-build                       |   98 
 tools/ioemu/patches/xen-domain-name                 |   30 
 tools/ioemu/patches/xen-domid                       |   27 
 tools/ioemu/patches/xen-mapcache                    |   26 
 tools/ioemu/patches/xen-mm                          |   45 
 tools/ioemu/patches/xen-network                     |   22 
 tools/ioemu/patches/xen-platform-device             |   20 
 tools/ioemu/patches/xen-support-buffered-ioreqs     |   12 
 tools/ioemu/patches/xenstore                        |   21 
 tools/ioemu/patches/xenstore-block-device-config    |   84 
 tools/ioemu/patches/xenstore-device-info-functions  |    6 
 tools/ioemu/patches/xenstore-write-vnc-port         |   15 
 tools/ioemu/pc-bios/.CVS/Entries                    |   29 
 tools/ioemu/pc-bios/.CVS/Tag                        |    2 
 tools/ioemu/pc-bios/README                          |    6 
 tools/ioemu/pc-bios/bios.diff                       |  252 --
 tools/ioemu/qemu-doc.texi                           |  604 +++--
 tools/ioemu/qemu-img.c                              |  132 -
 tools/ioemu/qemu-img.texi                           |   20 
 tools/ioemu/qemu_socket.h                           |    1 
 tools/ioemu/sdl.c                                   |   87 
 tools/ioemu/tap-win32.c                             |   31 
 tools/ioemu/target-i386-dm/helper2.c                |    6 
 tools/ioemu/target-i386-dm/piix_pci-dm.c            |  102 
 tools/ioemu/target-i386-dm/rtc-dm.c                 |   19 
 tools/ioemu/target-i386/.CVS/Entries                |   24 
 tools/ioemu/target-i386/.CVS/Tag                    |    2 
 tools/ioemu/target-i386/cpu.h                       |   19 
 tools/ioemu/target-i386/exec.h                      |    2 
 tools/ioemu/target-i386/helper.c                    |  326 ++
 tools/ioemu/target-i386/helper2.c                   |   11 
 tools/ioemu/target-i386/op.c                        |    9 
 tools/ioemu/target-i386/ops_sse.h                   |   19 
 tools/ioemu/target-i386/translate.c                 |  120 -
 tools/ioemu/tests/.CVS/Entries                      |   35 
 tools/ioemu/tests/.CVS/Tag                          |    2 
 tools/ioemu/tests/Makefile                          |   11 
 tools/ioemu/tests/hello-mips.c                      |   64 
 tools/ioemu/tests/test-i386.c                       |   36 
 tools/ioemu/translate-all.c                         |    2 
 tools/ioemu/usb-linux.c                             |   11 
 tools/ioemu/vl.c                                    | 1794 ++++++++++++---
 tools/ioemu/vl.h                                    |  349 ++-
 tools/ioemu/vnc.c                                   |  406 ++-
 tools/ioemu/vnc_keysym.h                            |   14 
 tools/ioemu/vnchextile.h                            |    2 
 tools/ioemu/x_keymap.c                              |  110 
 ioemu/pc-bios/pxe-ne2k_pci.bin                      |    0 
 ioemu/pc-bios/pxe-pcnet.bin                         |    0 
 ioemu/pc-bios/pxe-rtl8139.bin                       |    0 
 252 files changed, 18815 insertions(+), 9370 deletions(-)

diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/.CVS/Entries
--- a/tools/ioemu/.CVS/Entries  Tue May 08 10:38:06 2007 +0100
+++ b/tools/ioemu/.CVS/Entries  Wed May 09 14:17:15 2007 +0100
@@ -1,109 +1,117 @@ D/audio////
 D/audio////
 D/hw////
-D/linux-user////
 D/pc-bios////
-D/slirp////
-D/target-arm////
 D/target-i386////
-D/target-ppc////
-D/target-sparc////
 D/tests////
 D/fpu////
 D/keymaps////
+/.cvsignore/1.16/Thu May  3 17:17:53 2007//Trelease_0_9_0
+/COPYING/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_9_0
+/COPYING.LIB/1.2/Thu Jul 13 09:23:22 2006//Trelease_0_9_0
+/Changelog/1.128/Thu May  3 17:17:53 2007//Trelease_0_9_0
+/LICENSE/1.3/Thu May  3 17:17:53 2007//Trelease_0_9_0
+/Makefile/1.112/Thu May  3 17:17:53 2007//Trelease_0_9_0
+/Makefile.target/1.144/Thu May  3 17:17:53 2007//Trelease_0_9_0
+/README/1.12/Wed Oct 18 10:11:20 2006//Trelease_0_9_0
+/TODO/1.39/Fri Jan  5 14:34:35 2007//Trelease_0_9_0
+/VERSION/1.30/Thu May  3 17:17:53 2007//Trelease_0_9_0
+/a.out.h/1.2/Wed Oct 18 10:11:20 2006//Trelease_0_9_0
+/aes.c/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_9_0
+/aes.h/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_9_0
+/alpha-dis.c/1.3/Thu May  3 17:17:54 2007//Trelease_0_9_0
+/alpha.ld/1.1/Thu May  3 17:17:54 2007//Trelease_0_9_0
+/arm-dis.c/1.3/Thu May  3 17:17:54 2007//Trelease_0_9_0
+/arm-semi.c/1.2/Sun Jan 28 03:10:55 2007//Trelease_0_9_0
+/arm.ld/1.2/Thu May  3 17:17:54 2007//Trelease_0_9_0
+/block-bochs.c/1.3/Thu May  3 17:17:54 2007//Trelease_0_9_0
+/block-cloop.c/1.4/Thu May  3 17:17:54 2007//Trelease_0_9_0
+/block-cow.c/1.7/Thu May  3 17:17:54 2007//Trelease_0_9_0
+/block-dmg.c/1.5/Thu May  3 17:17:54 2007//Trelease_0_9_0
+/block-qcow.c/1.11/Thu May  3 17:17:54 2007//Trelease_0_9_0
+/block-qcow2.c/1.4/Mon Aug  7 02:38:06 2006//Trelease_0_9_0
+/block-raw.c/1.17/Thu Jan 18 00:22:11 2007//Trelease_0_9_0
+/block-vmdk.c/1.10/Thu May  3 17:17:55 2007//Trelease_0_9_0
+/block-vpc.c/1.4/Thu May  3 17:17:55 2007//Trelease_0_9_0
+/block-vvfat.c/1.8/Thu May  3 17:17:55 2007//Trelease_0_9_0
+/block.c/1.42/Thu May  3 17:17:55 2007//Trelease_0_9_0
+/block_int.h/1.10/Thu May  3 17:17:55 2007//Trelease_0_9_0
+/bswap.h/1.5/Thu Jul 13 09:23:22 2006//Trelease_0_9_0
+/check_ops.sh/1.1/Sun Jan  7 19:38:08 2007//Trelease_0_9_0
+/cocoa.m/1.10/Fri Jan  5 14:34:35 2007//Trelease_0_9_0
+/configure/1.120/Thu May  3 17:17:55 2007//Trelease_0_9_0
+/console.c/1.11/Thu May  3 17:17:55 2007//Trelease_0_9_0
+/cpu-all.h/1.60/Thu May  3 17:17:55 2007//Trelease_0_9_0
+/cpu-defs.h/1.17/Thu May  3 17:17:55 2007//Trelease_0_9_0
+/cpu-exec.c/1.93/Thu May  3 17:17:55 2007//Trelease_0_9_0
+/cutils.c/1.1/Sun Jan  7 22:04:40 2007//Trelease_0_9_0
+/dis-asm.h/1.11/Wed Oct 18 10:11:20 2006//Trelease_0_9_0
+/disas.c/1.34/Thu May  3 17:17:55 2007//Trelease_0_9_0
+/disas.h/1.7/Thu May  3 17:17:36 2007//Trelease_0_9_0
+/dyngen-exec.h/1.31/Thu May  3 17:17:55 2007//Trelease_0_9_0
+/dyngen-op.h/1.1/Wed Oct 18 10:11:20 2006//Trelease_0_9_0
+/dyngen.c/1.47/Thu May  3 17:17:55 2007//Trelease_0_9_0
+/dyngen.h/1.12/Thu May  3 17:17:55 2007//Trelease_0_9_0
+/elf.h/1.8/Thu May  3 17:17:55 2007//Trelease_0_9_0
+/elf_ops.h/1.5/Thu May  3 17:17:55 2007//Trelease_0_9_0
+/exec-all.h/1.49/Thu May  3 17:17:55 2007//Trelease_0_9_0
+/exec.c/1.85/Thu May  3 17:17:55 2007//Trelease_0_9_0
+/gdbstub.c/1.47/Thu May  3 17:17:55 2007//Trelease_0_9_0
+/gdbstub.h/1.5/Thu May  3 17:17:55 2007//Trelease_0_9_0
+/hostregs_helper.h/1.1/Sun Feb  4 13:37:44 2007//Trelease_0_9_0
+/i386-dis.c/1.5/Wed Oct 18 10:11:21 2006//Trelease_0_9_0
+/i386-vl.ld/1.3/Wed Oct 18 10:11:21 2006//Trelease_0_9_0
+/i386.ld/1.2/Wed Oct 18 10:11:21 2006//Trelease_0_9_0
+/ia64.ld/1.1/Wed Oct 18 10:11:21 2006//Trelease_0_9_0
+/keymaps.c/1.2/Thu May  3 17:17:34 2007//Trelease_0_9_0
+/kqemu.c/1.15/Thu May  3 17:17:55 2007//Trelease_0_9_0
+/kqemu.h/1.1/Wed Oct 18 10:11:21 2006//Trelease_0_9_0
+/loader.c/1.4/Thu May  3 17:17:55 2007//Trelease_0_9_0
+/m68k-dis.c/1.1/Thu May  3 17:17:56 2007//Trelease_0_9_0
+/m68k.ld/1.1/Thu May  3 17:17:56 2007//Trelease_0_9_0
+/mips-dis.c/1.4/Thu May  3 17:17:57 2007//Trelease_0_9_0
+/monitor.c/1.64/Thu May  3 17:17:57 2007//Trelease_0_9_0
+/osdep.c/1.15/Thu May  3 17:17:57 2007//Trelease_0_9_0
+/osdep.h/1.8/Thu May  3 17:17:57 2007//Trelease_0_9_0
+/ppc-dis.c/1.7/Thu May  3 17:17:58 2007//Trelease_0_9_0
+/ppc.ld/1.2/Thu May  3 17:17:58 2007//Trelease_0_9_0
+/qemu-binfmt-conf.sh/1.4/Wed Oct 18 10:11:21 2006//Trelease_0_9_0
+/qemu-doc.texi/1.128/Thu May  3 17:17:58 2007//Trelease_0_9_0
+/qemu-img.c/1.16/Thu May  3 17:17:58 2007//Trelease_0_9_0
+/qemu-img.texi/1.3/Thu May  3 17:17:58 2007//Trelease_0_9_0
+/qemu-tech.texi/1.9/Wed Oct 18 10:11:21 2006//Trelease_0_9_0
+/qemu_socket.h/1.2/Thu May  3 17:17:58 2007//Trelease_0_9_0
+/readline.c/1.1/Wed Oct 18 10:11:21 2006//Trelease_0_9_0
+/s390.ld/1.1/Thu May  3 17:17:58 2007//Trelease_0_9_0
+/sdl.c/1.34/Thu May  3 17:17:58 2007//Trelease_0_9_0
+/sdl_keysym.h/1.3/Wed Oct 18 10:11:21 2006//Trelease_0_9_0
+/sh4-dis.c/1.1/Thu May  3 17:17:58 2007//Trelease_0_9_0
+/softmmu_exec.h/1.1/Wed Oct 18 10:11:21 2006//Trelease_0_9_0
+/softmmu_header.h/1.13/Wed Oct 18 10:11:21 2006//Trelease_0_9_0
+/softmmu_template.h/1.16/Wed Oct 18 10:11:21 2006//Trelease_0_9_0
+/sparc-dis.c/1.3/Thu May  3 17:17:59 2007//Trelease_0_9_0
+/sparc.ld/1.1/Thu May  3 17:17:59 2007//Trelease_0_9_0
+/sparc64.ld/1.1/Fri Aug  4 21:55:15 2006//Trelease_0_9_0
+/tap-win32.c/1.4/Thu May  3 17:17:59 2007//Trelease_0_9_0
+/texi2pod.pl/1.1/Wed Oct 18 10:11:21 2006//Trelease_0_9_0
+/thunk.c/1.6/Wed Oct 18 10:11:21 2006//Trelease_0_9_0
+/thunk.h/1.13/Thu Jul 13 09:23:22 2006//Trelease_0_9_0
+/translate-all.c/1.15/Thu May  3 17:17:59 2007//Trelease_0_9_0
+/translate-op.c/1.1/Wed Oct 18 10:11:21 2006//Trelease_0_9_0
+/usb-linux.c/1.10/Thu May  3 17:17:59 2007//Trelease_0_9_0
+/vgafont.h/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_9_0
+/vl.c/1.248/Thu May  3 17:17:59 2007//Trelease_0_9_0
+/vl.h/1.184/Thu May  3 17:17:59 2007//Trelease_0_9_0
+/vnc.c/1.12/Thu May  3 17:17:59 2007//Trelease_0_9_0
+/vnc_keysym.h/1.2/Thu May  3 17:17:59 2007//Trelease_0_9_0
+/vnchextile.h/1.3/Thu May  3 17:17:59 2007//Trelease_0_9_0
+/x86_64.ld/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_9_0
+/x_keymap.c/1.1/Wed Jan 24 21:40:21 2007//Trelease_0_9_0
+D/darwin-user////
+D/linux-user////
+D/slirp////
+D/target-arm////
+D/target-m68k////
 D/target-mips////
+D/target-ppc////
 D/target-sh4////
-/.cvsignore/1.14/Sun Aug  6 01:03:44 2006//Trelease_0_8_2
-/COPYING/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2
-/COPYING.LIB/1.2/Thu Jul 13 09:23:22 2006//Trelease_0_8_2
-/Changelog/1.121/Sun Aug  6 01:03:44 2006//Trelease_0_8_2
-/LICENSE/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
-/Makefile/1.104/Sun Aug  6 01:03:44 2006//Trelease_0_8_2
-/Makefile.target/1.121/Sun Aug  6 01:03:44 2006//Trelease_0_8_2
-/README/1.12/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
-/README.distrib/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
-/TODO/1.39/Sun Aug  6 01:03:44 2006//Trelease_0_8_2
-/VERSION/1.29/Sun Aug  6 01:03:44 2006//Trelease_0_8_2
-/a.out.h/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
-/aes.c/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2
-/aes.h/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2
-/alpha-dis.c/1.3/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
-/alpha.ld/1.1/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
-/arm-dis.c/1.3/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
-/arm.ld/1.1/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
-/block-bochs.c/1.1/Sun Aug  6 00:55:02 2006//Trelease_0_8_2
-/block-cloop.c/1.3/Sun Aug  6 00:55:02 2006//Trelease_0_8_2
-/block-cow.c/1.6/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
-/block-dmg.c/1.4/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
-/block-qcow.c/1.7/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
-/block-vmdk.c/1.8/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
-/block-vpc.c/1.3/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
-/block-vvfat.c/1.6/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
-/block.c/1.28/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
-/block_int.h/1.5/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
-/bswap.h/1.5/Thu Jul 13 09:23:22 2006//Trelease_0_8_2
-/cocoa.m/1.10/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
-/configure/1.110/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
-/console.c/1.8/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
-/cpu-all.h/1.57/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
-/cpu-defs.h/1.16/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
-/cpu-exec.c/1.83/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
-/dis-asm.h/1.11/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
-/disas.c/1.31/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
-/disas.h/1.7/Sun Aug  6 00:55:03 2006//Trelease_0_8_2
-/dyngen-exec.h/1.29/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
-/dyngen-op.h/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
-/dyngen.c/1.45/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
-/dyngen.h/1.11/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
-/elf.h/1.7/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
-/elf_ops.h/1.3/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
-/exec-all.h/1.48/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
-/exec.c/1.82/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
-/gdbstub.c/1.40/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
-/gdbstub.h/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
-/i386-dis.c/1.5/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
-/i386-vl.ld/1.3/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
-/i386.ld/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
-/ia64.ld/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
-/keymaps.c/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
-/kqemu.c/1.12/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
-/kqemu.h/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
-/linux-2.6.9-qemu-fast.patch/1.1/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
-/loader.c/1.3/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
-/m68k-dis.c/1.1/Sun Aug  6 01:03:46 2006//Trelease_0_8_2
-/m68k.ld/1.1/Sun Aug  6 01:03:46 2006//Trelease_0_8_2
-/mips-dis.c/1.4/Sun Aug  6 01:03:47 2006//Trelease_0_8_2
-/monitor.c/1.54/Sun Aug  6 01:03:47 2006//Trelease_0_8_2
-/osdep.c/1.11/Sun Aug  6 01:03:47 2006//Trelease_0_8_2
-/osdep.h/1.6/Sun Aug  6 01:03:47 2006//Trelease_0_8_2
-/ppc-dis.c/1.7/Sun Aug  6 01:03:48 2006//Trelease_0_8_2
-/ppc.ld/1.2/Sun Aug  6 01:03:48 2006//Trelease_0_8_2
-/qemu-binfmt-conf.sh/1.4/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
-/qemu-doc.texi/1.100/Sun Aug  6 01:03:48 2006//Trelease_0_8_2
-/qemu-img.c/1.10/Sun Aug  6 01:03:48 2006//Trelease_0_8_2
-/qemu-img.texi/1.2/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
-/qemu-tech.texi/1.9/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
-/qemu_socket.h/1.1/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
-/readline.c/1.1/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
-/s390.ld/1.1/Sun Aug  6 01:03:48 2006//Trelease_0_8_2
-/sdl.c/1.29/Sun Aug  6 01:03:48 2006//Trelease_0_8_2
-/sdl_keysym.h/1.3/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
-/sh4-dis.c/1.1/Sun Aug  6 01:03:48 2006//Trelease_0_8_2
-/softmmu_exec.h/1.1/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
-/softmmu_header.h/1.13/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
-/softmmu_template.h/1.16/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
-/sparc-dis.c/1.3/Sun Aug  6 01:03:49 2006//Trelease_0_8_2
-/sparc.ld/1.1/Sun Aug  6 01:03:49 2006//Trelease_0_8_2
-/tap-win32.c/1.3/Sun Aug  6 01:03:49 2006//Trelease_0_8_2
-/texi2pod.pl/1.1/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
-/thunk.c/1.6/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
-/thunk.h/1.13/Thu Jul 13 09:23:22 2006//Trelease_0_8_2
-/translate-all.c/1.14/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
-/translate-op.c/1.1/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
-/usb-linux.c/1.8/Sun Aug  6 01:03:49 2006//Trelease_0_8_2
-/vgafont.h/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2
-/vl.c/1.202/Sun Aug  6 01:03:49 2006//Trelease_0_8_2
-/vl.h/1.136/Sun Aug  6 01:03:49 2006//Trelease_0_8_2
-/vnc.c/1.7/Sun Aug  6 01:03:49 2006//Trelease_0_8_2
-/vnc_keysym.h/1.1/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
-/vnchextile.h/1.2/Sun Aug  6 01:03:49 2006//Trelease_0_8_2
-/x86_64.ld/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2
+D/target-sparc////
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/.CVS/Entries.Log
--- a/tools/ioemu/.CVS/Entries.Log      Tue May 08 10:38:06 2007 +0100
+++ /dev/null   Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-A D/linux-user////
-A D/slirp////
-A D/target-arm////
-A D/target-mips////
-A D/target-ppc////
-A D/target-sh4////
-A D/target-sparc////
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/.CVS/Tag
--- a/tools/ioemu/.CVS/Tag      Tue May 08 10:38:06 2007 +0100
+++ b/tools/ioemu/.CVS/Tag      Wed May 09 14:17:15 2007 +0100
@@ -1,1 +1,1 @@ Nrelease_0_8_2
-Nrelease_0_8_2
+Nrelease_0_9_0
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/.cvsignore
--- a/tools/ioemu/.cvsignore    Tue May 08 10:38:06 2007 +0100
+++ b/tools/ioemu/.cvsignore    Wed May 09 14:17:15 2007 +0100
@@ -1,14 +1,16 @@ arm-user
-arm-user
+arm-linux-user
 arm-softmmu
-armeb-user
+armeb-linux-user
 config-host.*
 dyngen
 i386
 i386-softmmu
-i386-user
+i386-darwin-user
+i386-linux-user
 ppc-softmmu
 ppc64-softmmu
-ppc-user
+ppc-darwin-user
+ppc-linux-user
 qemu-doc.html
 qemu-tech.html
 qemu-doc.info
@@ -17,18 +19,19 @@ qemu.pod
 qemu.pod
 qemu-img.1
 qemu-img.pod
-sparc-user
+sparc-linux-user
 qemu-img
 sparc-softmmu
 x86_64-softmmu
-sparc64-user
+sparc64-linux-user
 sparc64-softmmu
 mips-softmmu
 mipsel-softmmu
-mips-user
-mipsel-user
+mips-linux-user
+mipsel-linux-user
+m68k-linux-user
 .gdbinit
-sh4-user
+sh4-linux-user
 sh4-softmmu
 *.aux
 *.cp
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/Changelog
--- a/tools/ioemu/Changelog     Tue May 08 10:38:06 2007 +0100
+++ b/tools/ioemu/Changelog     Wed May 09 14:17:15 2007 +0100
@@ -1,3 +1,21 @@ version 0.8.2:
+version 0.9.0:
+
+  - Support for relative paths in backing files for disk images
+  - Async file I/O API
+  - New qcow2 disk image format
+  - Support of multiple VM snapshots
+  - Linux: specific host CDROM and floppy support
+  - SMM support
+  - Moved PCI init, MP table init and ACPI table init to Bochs BIOS
+  - Support for MIPS32 Release 2 instruction set (Thiemo Seufer)
+  - MIPS Malta system emulation (Aurelien Jarno, Stefan Weil)
+  - Darwin userspace emulation (Pierre d'Herbemont)
+  - m68k user support (Paul Brook)
+  - several x86 and x86_64 emulation fixes
+  - Mouse relative offset VNC extension (Anthony Liguori)
+  - PXE boot support (Anthony Liguori)
+  - '-daemonize' option (Anthony Liguori)
+
 version 0.8.2:
 
   - ACPI support
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/LICENSE
--- a/tools/ioemu/LICENSE       Tue May 08 10:38:06 2007 +0100
+++ b/tools/ioemu/LICENSE       Wed May 09 14:17:15 2007 +0100
@@ -1,11 +1,14 @@ The following points clarify the QEMU li
-The following points clarify the QEMU licenses:
+The following points clarify the QEMU license:
 
-1) The QEMU virtual CPU core library (libqemu.a) and the QEMU PC
-   system emulator are released under the GNU Lesser General Public
-   License.
+1) QEMU as a whole is released under the GNU General Public License
 
-2) The Linux user mode QEMU emulator is released under the GNU General
-   Public License.
+2) Parts of QEMU have specific licenses which are compatible with the
+GNU General Public License. Hence each source file contains its own
+licensing information.
+
+In particular, the QEMU virtual CPU core library (libqemu.a) is
+released under the GNU Lesser General Public License. Many hardware
+device emulation sources are released under the BSD license.
 
 3) QEMU is a trademark of Fabrice Bellard.
 
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/Makefile
--- a/tools/ioemu/Makefile      Tue May 08 10:38:06 2007 +0100
+++ b/tools/ioemu/Makefile      Wed May 09 14:17:15 2007 +0100
@@ -8,24 +8,31 @@ include $(XEN_ROOT)/tools/Rules.mk
 .PHONY: all clean distclean dvi info install install-doc tar tarbin \
        speed test test2 html dvi info
 
-CFLAGS+=-Wall -O2 -g -fno-strict-aliasing -I.
-ifdef CONFIG_DARWIN
-CFLAGS+= -mdynamic-no-pic
+BASE_CFLAGS=
+BASE_LDFLAGS=
+
+BASE_CFLAGS += $(OS_CFLAGS)
+ifeq ($(ARCH),sparc)
+BASE_CFLAGS += -mcpu=ultrasparc
 endif
-ifeq ($(ARCH),sparc)
-CFLAGS+=-mcpu=ultrasparc
-endif
-LDFLAGS=-g
+CPPFLAGS += -I. -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
 LIBS=
-DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
 TOOLS=qemu-img$(EXESUF)
 ifdef CONFIG_STATIC
-LDFLAGS+=-static
+BASE_LDFLAGS += -static
 endif
 ifdef BUILD_DOCS
 DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1
 else
 DOCS=
+endif
+
+ifndef CONFIG_DARWIN
+ifndef CONFIG_WIN32
+ifndef CONFIG_SOLARIS
+LIBS+=-lrt
+endif
+endif
 endif
 
 TOOLS=
@@ -36,12 +43,12 @@ subdir-%:
        $(MAKE) -C $(subst subdir-,,$@) all
 
 recurse-all: $(patsubst %,subdir-%, $(TARGET_DIRS))
-        
-qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c 
block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c block-vvfat.c
-       $(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS)
+
+qemu-img$(EXESUF): qemu-img.c cutils.c block.c block-raw.c block-cow.c 
block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c 
block-vpc.c block-vvfat.c block-qcow2.c
+       $(CC) -DQEMU_TOOL $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $(LDFLAGS) 
$(BASE_LDFLAGS) -o $@ $^ -lz $(LIBS)
 
 dyngen$(EXESUF): dyngen.c
-       $(HOST_CC) $(CFLAGS) $(DEFINES) -o $@ $^
+       $(HOST_CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -o $@ $^
 
 clean:
 # avoid old build problems by removing potentially incorrect old files
@@ -65,7 +72,7 @@ common  de-ch  es     fo  fr-ca  hu     
 
 install-doc: $(DOCS)
        mkdir -p "$(DESTDIR)$(docdir)"
-       $(INSTALL_DATA) qemu-doc.html  qemu-tech.html "$(DESTDIR)$(docdir)"
+       $(INSTALL_DATA) -m 644 qemu-doc.html  qemu-tech.html 
"$(DESTDIR)$(docdir)"
 ifndef CONFIG_WIN32
        mkdir -p "$(DESTDIR)$(mandir)/man1"
        $(INSTALL_DATA) qemu.1 qemu-img.1 "$(DESTDIR)$(mandir)/man1"
@@ -76,13 +83,14 @@ install: all $(if $(BUILD_DOCS),install-
 #      $(INSTALL) -m 755 -s $(TOOLS) "$(DESTDIR)$(bindir)"
 #      mkdir -p "$(DESTDIR)$(datadir)"
 #      for x in bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \
-#                      video.x openbios-sparc32 linux_boot.bin; do \
-#              $(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; 
\
+#              video.x openbios-sparc32 linux_boot.bin pxe-ne2k_pci.bin \
+#              pxe-rtl8139.bin pxe-pcnet.bin; do \
+#              $(INSTALL) -m 644 $(SRC_PATH)/pc-bios/$$x 
"$(DESTDIR)$(datadir)"; \
 #      done
 ifndef CONFIG_WIN32
        mkdir -p "$(DESTDIR)$(datadir)/keymaps"
        for x in $(KEYMAPS); do \
-               $(INSTALL_DATA) $(SRC_PATH)/keymaps/$$x 
"$(DESTDIR)$(datadir)/keymaps"; \
+               $(INSTALL_DATA) -m 644 $(SRC_PATH)/keymaps/$$x 
"$(DESTDIR)$(datadir)/keymaps"; \
        done
 endif
        for d in $(TARGET_DIRS); do \
@@ -125,7 +133,8 @@ dvi: qemu-doc.dvi qemu-tech.dvi
 
 html: qemu-doc.html qemu-tech.html
 
-FILE=qemu-$(shell cat VERSION)
+VERSION ?= $(shell cat VERSION)
+FILE = qemu-$(VERSION)
 
 # tar release (use 'make -k tar' on a checkouted tree)
 tar:
@@ -159,6 +168,9 @@ tarbin:
        $(datadir)/video.x \
        $(datadir)/openbios-sparc32 \
        $(datadir)/linux_boot.bin \
+        $(datadir)/pxe-ne2k_pci.bin \
+       $(datadir)/pxe-rtl8139.bin \
+        $(datadir)/pxe-pcnet.bin \
        $(docdir)/qemu-doc.html \
        $(docdir)/qemu-tech.html \
        $(mandir)/man1/qemu.1 $(mandir)/man1/qemu-img.1 )
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/Makefile.target
--- a/tools/ioemu/Makefile.target       Tue May 08 10:38:06 2007 +0100
+++ b/tools/ioemu/Makefile.target       Wed May 09 14:17:15 2007 +0100
@@ -15,21 +15,24 @@ endif
 endif
 TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH)$(TARGET_SUB)
 VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw:$(SRC_PATH)/audio
-DEFINES=-I. -I.. -I$(TARGET_PATH) -I$(SRC_PATH)
-DEFINES+= -I$(XEN_ROOT)/tools/libxc
-DEFINES+= -I$(XEN_ROOT)/tools/xenstore
-ifdef CONFIG_USER_ONLY
+CPPFLAGS=-I. -I.. -I$(TARGET_PATH) -I$(SRC_PATH)
+CPPFLAGS+= -I$(XEN_ROOT)/tools/libxc
+CPPFLAGS+= -I$(XEN_ROOT)/tools/xenstore
+ifdef CONFIG_DARWIN_USER
+VPATH+=:$(SRC_PATH)/darwin-user
+CPPFLAGS+=-I$(SRC_PATH)/darwin-user -I$(SRC_PATH)/darwin-user/$(TARGET_ARCH)
+endif
+ifdef CONFIG_LINUX_USER
 VPATH+=:$(SRC_PATH)/linux-user
-DEFINES+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ARCH)
-endif
-CFLAGS+=-Wall -O2 -g -fno-strict-aliasing
+CPPFLAGS+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ARCH)
+endif
+BASE_CFLAGS=
+BASE_LDFLAGS=
 SSE2 := $(call cc-option,$(CC),-msse2,)
 ifeq ($(SSE2),-msse2)
 CFLAGS += -DUSE_SSE2=1 -msse2
 endif
-CFLAGS+= $(LOCAL_CFLAGS)
 #CFLAGS+=-Werror
-LDFLAGS=-g
 LIBS=
 HELPER_CFLAGS=$(CFLAGS)
 DYNGEN=../dyngen$(EXESUF)
@@ -74,18 +77,20 @@ endif # !CONFIG_USER_ONLY
 endif # !CONFIG_USER_ONLY
 
 ifdef CONFIG_STATIC
-LDFLAGS+=-static
-endif
+BASE_LDFLAGS+=-static
+endif
+
+# We require -O2 to avoid the stack setup prologue in EXIT_TB
+OP_CFLAGS = -Wall -O2 -g -fno-strict-aliasing
 
 ifeq ($(ARCH),i386)
-CFLAGS+=-fomit-frame-pointer
-OP_CFLAGS=$(CFLAGS) -mpreferred-stack-boundary=2
+HELPER_CFLAGS+=-fomit-frame-pointer
+OP_CFLAGS+=-mpreferred-stack-boundary=2 -fomit-frame-pointer
 ifeq ($(HAVE_GCC3_OPTIONS),yes)
 OP_CFLAGS+= -falign-functions=0 -fno-gcse
 else
 OP_CFLAGS+= -malign-functions=0
 endif
-
 ifdef TARGET_GPROF
 USE_I386_LD=y
 endif
@@ -93,76 +98,80 @@ USE_I386_LD=y
 USE_I386_LD=y
 endif
 ifdef USE_I386_LD
-LDFLAGS+=-Wl,-T,$(SRC_PATH)/i386.ld
-else
+BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
+else
+ifdef CONFIG_LINUX_USER
 # WARNING: this LDFLAGS is _very_ tricky : qemu is an ELF shared object
 # that the kernel ELF loader considers as an executable. I think this
 # is the simplest way to make it self virtualizable!
-LDFLAGS+=-Wl,-shared
+BASE_LDFLAGS+=-Wl,-shared
+endif
 endif
 endif
 
 ifeq ($(ARCH),x86_64)
-OP_CFLAGS=$(CFLAGS) -falign-functions=0
-LDFLAGS+=-Wl,-T,$(SRC_PATH)/x86_64.ld
+BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
 endif
 
 ifeq ($(ARCH),ppc)
-CFLAGS+= -D__powerpc__
-OP_CFLAGS=$(CFLAGS)
-LDFLAGS+=-Wl,-T,$(SRC_PATH)/ppc.ld
+CPPFLAGS+= -D__powerpc__
+ifdef CONFIG_LINUX_USER
+BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
+endif
 endif
 
 ifeq ($(ARCH),s390)
-OP_CFLAGS=$(CFLAGS)
-LDFLAGS+=-Wl,-T,$(SRC_PATH)/s390.ld
+BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
 endif
 
 ifeq ($(ARCH),sparc)
 ifeq ($(CONFIG_SOLARIS),yes)
-CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g2 -ffixed-g3
-LDFLAGS+=-m32
-OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -fno-omit-frame-pointer -ffixed-i0
-else
-CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
-LDFLAGS+=-m32
-OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
+BASE_CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g2 -ffixed-g3
+BASE_LDFLAGS+=-m32
+OP_CFLAGS+=-fno-delayed-branch -fno-omit-frame-pointer -ffixed-i0
+else
+BASE_CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
+BASE_LDFLAGS+=-m32
+OP_CFLAGS+=-fno-delayed-branch -ffixed-i0
 HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat
 # -static is used to avoid g1/g3 usage by the dynamic linker
-LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc.ld -static
+BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld -static
 endif
 endif
 
 ifeq ($(ARCH),sparc64)
-CFLAGS+=-mcpu=ultrasparc -m64 -ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7
-LDFLAGS+=-m64
-LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc64.ld
-OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
+BASE_CFLAGS+=-mcpu=ultrasparc -m64 -ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7
+BASE_LDFLAGS+=-m64
+BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
+OP_CFLAGS+=-mcpu=ultrasparc -m64 -ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7 
-fno-delayed-branch -ffixed-i0
 endif
 
 ifeq ($(ARCH),alpha)
-# -msmall-data is not used because we want two-instruction relocations
-# for the constant constructions
-OP_CFLAGS=-Wall -O2 -g
+# -msmall-data is not used for OP_CFLAGS because we want two-instruction
+# relocations for the constant constructions
 # Ensure there's only a single GP
-CFLAGS += -msmall-data
-LDFLAGS+=-Wl,-T,$(SRC_PATH)/alpha.ld
+BASE_CFLAGS+=-msmall-data
+BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
 endif
 
 ifeq ($(ARCH),ia64)
-CFLAGS += -mno-sdata
-OP_CFLAGS=$(CFLAGS)
-LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/ia64.ld
+BASE_CFLAGS+=-mno-sdata
+OP_CFLAGS+=-mno-sdata
+BASE_LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/$(ARCH).ld
 endif
 
 ifeq ($(ARCH),arm)
-OP_CFLAGS=$(CFLAGS) -mno-sched-prolog -fno-omit-frame-pointer
-LDFLAGS+=-Wl,-T,$(SRC_PATH)/arm.ld
+OP_CFLAGS+=-mno-sched-prolog -fno-omit-frame-pointer
+BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
 endif
 
 ifeq ($(ARCH),m68k)
-OP_CFLAGS=$(CFLAGS) -fomit-frame-pointer
-LDFLAGS+=-Wl,-T,m68k.ld
+OP_CFLAGS+=-fomit-frame-pointer
+BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
+endif
+
+ifeq ($(ARCH),mips)
+BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
 endif
 
 ifeq ($(HAVE_GCC3_OPTIONS),yes)
@@ -171,14 +180,20 @@ endif
 endif
 
 ifeq ($(CONFIG_DARWIN),yes)
-OP_CFLAGS+= -mdynamic-no-pic
 LIBS+=-lmx
 endif
 
+ifdef CONFIG_DARWIN_USER
+# Leave some space for the regular program loading zone
+BASE_LDFLAGS+=-Wl,-segaddr,__STD_PROG_ZONE,0x1000 -image_base 0x0e000000
+endif
+
+OP_CFLAGS+=$(OS_CFLAGS)
+
 #########################################################
 
-DEFINES+=-D_GNU_SOURCE
-#-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
+CPPFLAGS+=-D_GNU_SOURCE
+# -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
 LIBS+=-lm
 LIBS+=-L../../libxc -lxenctrl -lxenguest
 LIBS+=-L../../xenstore -lxenstore
@@ -195,10 +210,11 @@ endif
 
 # profiling code
 ifdef TARGET_GPROF
-LDFLAGS+=-p
-main.o: CFLAGS+=-p
-endif
-
+BASE_LDFLAGS+=-p
+main.o: BASE_CFLAGS+=-p
+endif
+
+ifdef CONFIG_LINUX_USER
 OBJS= main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o \
       elfload.o linuxload.o
 ifdef TARGET_HAS_BFLT
@@ -213,6 +229,15 @@ nwfpe/fpa11_cpdt.o nwfpe/fpa11_cprt.o nw
 nwfpe/fpa11_cpdt.o nwfpe/fpa11_cprt.o nwfpe/fpopcode.o nwfpe/single_cpdo.o \
  nwfpe/double_cpdo.o nwfpe/extended_cpdo.o arm-semi.o
 endif
+ifeq ($(TARGET_ARCH), m68k)
+OBJS+= m68k-sim.o m68k-semi.o
+endif
+endif #CONFIG_LINUX_USER
+
+ifdef CONFIG_DARWIN_USER
+OBJS= main.o commpage.o machload.o mmap.o osdep.o signal.o syscall.o thunk.o
+endif
+
 SRCS:= $(OBJS:.o=.c)
 OBJS+= libqemu.a
 
@@ -224,7 +249,7 @@ else
 else
 LIBOBJS+=fpu/softfloat-native.o
 endif
-DEFINES+=-I$(SRC_PATH)/fpu
+CPPFLAGS+=-I$(SRC_PATH)/fpu
 
 ifeq ($(TARGET_ARCH), i386)
 LIBOBJS+=helper.o helper2.o
@@ -257,6 +282,10 @@ LIBOBJS+= op_helper.o helper.o
 LIBOBJS+= op_helper.o helper.o
 endif
 
+ifeq ($(TARGET_BASE_ARCH), m68k)
+LIBOBJS+= helper.o
+endif
+
 # NOTE: the disassembler code is only needed for debugging
 LIBOBJS+=disas.o 
 ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386)
@@ -304,7 +333,7 @@ all: $(PROGS)
 all: $(PROGS)
 
 $(QEMU_USER): $(OBJS)
-       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^  $(LIBS)
+       $(CC) $(CFLAGS) $(LDFLAGS) $(BASE_LDFLAGS) -o $@ $^  $(LIBS)
 ifeq ($(ARCH),alpha)
 # Mark as 32 bit binary, i. e. it will be mapped into the low 31 bit of
 # the address space (31 bit so sign extending doesn't matter)
@@ -312,8 +341,10 @@ endif
 endif
 
 # must use static linking to avoid leaving stuff in virtual address space
-VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o
-VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o 
block-bochs.o block-vpc.o block-vvfat.o
+VL_OBJS=vl.o osdep.o readline.o monitor.o pci.o console.o isa_mmio.o
+VL_OBJS+=cutils.o
+VL_OBJS+=block.o block-raw.o
+VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o 
block-bochs.o block-vpc.o block-vvfat.o block-qcow2.o
 ifdef CONFIG_WIN32
 VL_OBJS+=tap-win32.o
 endif
@@ -339,7 +370,7 @@ endif
 endif
 ifdef CONFIG_FMOD
 AUDIODRV += fmodaudio.o
-audio.o fmodaudio.o: DEFINES := -I$(CONFIG_FMOD_INC) $(DEFINES)
+audio.o fmodaudio.o: CPPFLAGS := -I$(CONFIG_FMOD_INC) $(CPPFLAGS)
 LIBS += $(CONFIG_FMOD_LIB)
 endif
 ifdef CONFIG_ADLIB
@@ -365,23 +396,25 @@ VL_OBJS+= fdc.o serial.o pc.o
 VL_OBJS+= fdc.o serial.o pc.o
 endif
 VL_OBJS+= cirrus_vga.o mixeng.o parallel.o acpi.o
-VL_OBJS+= usb-uhci.o
+VL_OBJS+= usb-uhci.o smbus_eeprom.o
 VL_OBJS+= piix4acpi.o
 VL_OBJS+= xenstore.o
 VL_OBJS+= xen_platform.o
 VL_OBJS+= tpm_tis.o
-DEFINES += -DHAS_AUDIO
+CPPFLAGS += -DHAS_AUDIO
 endif
 ifeq ($(TARGET_BASE_ARCH), ppc)
 VL_OBJS+= ppc.o ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
 VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o
 VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.o
 VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o
+CPPFLAGS += -DHAS_AUDIO
+endif
+ifeq ($(TARGET_ARCH), mips)
+VL_OBJS+= mips_r4k.o mips_malta.o mips_timer.o mips_int.o dma.o vga.o serial.o 
i8254.o i8259.o
+VL_OBJS+= ide.o gt64xxx.o pckbd.o ps2.o fdc.o mc146818rtc.o usb-uhci.o acpi.o
+VL_OBJS+= piix_pci.o parallel.o mixeng.o cirrus_vga.o $(SOUND_HW) $(AUDIODRV)
 DEFINES += -DHAS_AUDIO
-endif
-ifeq ($(TARGET_ARCH), mips)
-VL_OBJS+= mips_r4k.o dma.o vga.o serial.o i8254.o i8259.o
-#VL_OBJS+= #ide.o pckbd.o fdc.o m48t59.o
 endif
 ifeq ($(TARGET_BASE_ARCH), sparc)
 ifeq ($(TARGET_ARCH), sparc64)
@@ -389,14 +422,17 @@ VL_OBJS+= fdc.o mc146818rtc.o serial.o m
 VL_OBJS+= fdc.o mc146818rtc.o serial.o m48t59.o
 VL_OBJS+= cirrus_vga.o parallel.o
 else
-VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t59.o slavio_intctl.o
-VL_OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o
+VL_OBJS+= sun4m.o tcx.o pcnet.o iommu.o m48t59.o slavio_intctl.o
+VL_OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o 
sparc32_dma.o
+VL_OBJS+= cs4231.o
 endif
 endif
 ifeq ($(TARGET_BASE_ARCH), arm)
 VL_OBJS+= integratorcp.o versatilepb.o ps2.o smc91c111.o arm_pic.o arm_timer.o
 VL_OBJS+= arm_boot.o pl011.o pl050.o pl080.o pl110.o pl190.o
 VL_OBJS+= versatile_pci.o
+VL_OBJS+= arm_gic.o realview.o arm_sysctl.o
+VL_OBJS+= arm-semi.o
 endif
 ifeq ($(TARGET_BASE_ARCH), sh4)
 VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o
@@ -405,7 +441,7 @@ VL_OBJS+=gdbstub.o
 VL_OBJS+=gdbstub.o 
 endif
 ifdef CONFIG_SDL
-VL_OBJS+=sdl.o
+VL_OBJS+=sdl.o x_keymap.o
 endif
 VL_OBJS+=vnc.o
 VL_OBJS+=d3des.o
@@ -417,7 +453,7 @@ endif
 endif
 endif
 ifdef CONFIG_SLIRP
-DEFINES+=-I$(SRC_PATH)/slirp
+CPPFLAGS+=-I$(SRC_PATH)/slirp
 SLIRP_OBJS=cksum.o if.o ip_icmp.o ip_input.o ip_output.o \
 slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tcp_output.o \
 tcp_subr.o tcp_timer.o udp.o bootp.o debug.o tftp.o
@@ -440,7 +476,7 @@ endif
 endif
 endif
 ifdef TARGET_GPROF
-vl.o: CFLAGS+=-p
+vl.o: BASE_CFLAGS+=-p
 VL_LDFLAGS+=-p
 endif
 
@@ -461,25 +497,25 @@ endif
        $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) 
$(VL_LIBS)
 
 cocoa.o: cocoa.m
-       $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
+       $(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
 
 sdl.o: sdl.c keymaps.c sdl_keysym.h
-       $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
+       $(CC) $(CFLAGS) $(CPPFLAGS) $(SDL_CFLAGS) $(BASE_CFLAGS) -c -o $@ $<
 
 vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h
-       $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
+       $(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
 
 d3des.o: d3des.c d3des.h
        $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
 
 sdlaudio.o: sdlaudio.c
-       $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
+       $(CC) $(CFLAGS) $(CPPFLAGS) $(SDL_CFLAGS) $(BASE_CFLAGS) -c -o $@ $<
 
 depend: $(SRCS)
-       $(CC) -MM $(CFLAGS) $(DEFINES) $^ 1>.depend
+       $(CC) -MM $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $^ 1>.depend
 
 vldepend: $(VL_OBJS:.o=.c)
-       $(CC) -MM $(CFLAGS) $(DEFINES) $^ 1>.depend
+       $(CC) -MM $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $^ 1>.depend
 
 # libqemu 
 
@@ -503,10 +539,26 @@ gen-op.h: op.o $(DYNGEN)
        $(DYNGEN) -g -o $@ $<
 
 op.o: op.c
-       $(CC) $(OP_CFLAGS) $(DEFINES) -c -o $@ $<
-
+       $(CC) $(OP_CFLAGS) $(CPPFLAGS) -c -o $@ $<
+
+# HELPER_CFLAGS is used for all the code compiled with static register
+# variables
+ifeq ($(TARGET_BASE_ARCH), i386)
+# XXX: rename helper.c to op_helper.c
 helper.o: helper.c
-       $(CC) $(HELPER_CFLAGS) $(DEFINES) -c -o $@ $<
+       $(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
+else
+op_helper.o: op_helper.c
+       $(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
+endif
+
+cpu-exec.o: cpu-exec.c
+       $(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
+
+# Note: this is a workaround. The real fix is to avoid compiling
+# cpu_signal_handler() in cpu-exec.c.
+signal.o: signal.c
+       $(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
 
 ifeq ($(TARGET_BASE_ARCH), i386)
 op.o: op.c opreg_template.h ops_template.h ops_template_mem.h ops_mem.h 
ops_sse.h
@@ -529,18 +581,11 @@ endif
 endif
 
 ifeq ($(TARGET_ARCH), mips)
-op.o: op.c op_template.c op_mem.c
+op.o: op.c op_template.c fop_template.c op_mem.c
 op_helper.o: op_helper_mem.c
 endif
 
 loader.o: loader.c elf_ops.h
-
-acpi.o: acpi.c acpi-dsdt.hex
-
-ifdef BUILD_ACPI_TABLES
-$(SRC_PATH)/hw/acpi-dsdt.hex: acpi-dsdt.dsl
-       iasl -tc -p $@ $<
-endif
 
 ifeq ($(TARGET_ARCH), sh4)
 op.o: op.c op_mem.c cpu.h
@@ -555,10 +600,10 @@ endif
 $(OBJS) $(LIBOBJS) $(VL_OBJS): config.h ../config-host.h
 
 %.o: %.c
-       $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
+       $(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
 
 %.o: %.S
-       $(CC) $(DEFINES) -c -o $@ $<
+       $(CC) $(CPPFLAGS) -c -o $@ $<
 
 clean:
        rm -f *.o  *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o slirp/*.o 
fpu/*.o
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/README.distrib
--- a/tools/ioemu/README.distrib        Tue May 08 10:38:06 2007 +0100
+++ /dev/null   Thu Jan 01 00:00:00 1970 +0000
@@ -1,16 +0,0 @@
-Information about the various packages used to build the current qemu
-x86 binary distribution:
-
-* gcc 2.95.2 was used for the build. A glibc 2.1.3 Debian distribution
-  was used to get most of the binary packages.
-
-* wine-20020411 tarball
-
-  ./configure --prefix=/usr/local/wine-i386
-  
-  All exe and libs were stripped. Some compile time tools and the
-  includes were deleted.
-
-* ldconfig was launched to build the library links:
-
-  qemu-i386 /usr/gnemul/qemu-i386/bin/ldconfig-i386 -C 
/usr/gnemul/qemu-i386/etc/ld.so.cache
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/VERSION
--- a/tools/ioemu/VERSION       Tue May 08 10:38:06 2007 +0100
+++ b/tools/ioemu/VERSION       Wed May 09 14:17:15 2007 +0100
@@ -1,1 +1,1 @@ 0.8.2
-0.8.2
\ No newline at end of file
+0.9.0
\ No newline at end of file
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/audio/.CVS/Entries
--- a/tools/ioemu/audio/.CVS/Entries    Tue May 08 10:38:06 2007 +0100
+++ b/tools/ioemu/audio/.CVS/Entries    Wed May 09 14:17:15 2007 +0100
@@ -1,20 +1,20 @@
-/alsaaudio.c/1.7/Sun Aug  6 01:03:49 2006//Trelease_0_8_2
-/audio.c/1.14/Sun Aug  6 01:03:50 2006//Trelease_0_8_2
-/audio.h/1.8/Sun Aug  6 01:03:50 2006//Trelease_0_8_2
-/audio_int.h/1.10/Sun Aug  6 01:03:50 2006//Trelease_0_8_2
-/audio_template.h/1.8/Sun Aug  6 01:03:50 2006//Trelease_0_8_2
-/coreaudio.c/1.7/Sun Aug  6 01:03:50 2006//Trelease_0_8_2
-/dsound_template.h/1.4/Sun Aug  6 01:03:50 2006//Trelease_0_8_2
-/dsoundaudio.c/1.3/Sun Aug  6 01:03:50 2006//Trelease_0_8_2
-/fmodaudio.c/1.7/Sun Aug  6 01:03:50 2006//Trelease_0_8_2
-/mixeng.c/1.4/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
-/mixeng.h/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
-/mixeng_template.h/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
-/noaudio.c/1.7/Sun Aug  6 01:03:50 2006//Trelease_0_8_2
-/ossaudio.c/1.11/Sun Aug  6 01:03:50 2006//Trelease_0_8_2
-/rate_template.h/1.3/Sun Aug  6 01:03:50 2006//Trelease_0_8_2
-/sdlaudio.c/1.8/Sun Aug  6 01:03:50 2006//Trelease_0_8_2
-/sys-queue.h/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
-/wavaudio.c/1.8/Sun Aug  6 01:03:50 2006//Trelease_0_8_2
-/wavcapture.c/1.5/Sat Jul 22 17:06:44 2006//Trelease_0_8_2
+/alsaaudio.c/1.7/Fri Jan  5 14:34:35 2007//Trelease_0_9_0
+/audio.c/1.15/Thu May  3 17:17:59 2007//Trelease_0_9_0
+/audio.h/1.8/Fri Jan  5 14:34:35 2007//Trelease_0_9_0
+/audio_int.h/1.10/Fri Jan  5 14:34:35 2007//Trelease_0_9_0
+/audio_template.h/1.8/Fri Jan  5 14:34:35 2007//Trelease_0_9_0
+/coreaudio.c/1.7/Fri Jan  5 14:34:35 2007//Trelease_0_9_0
+/dsound_template.h/1.4/Fri Jan  5 14:34:35 2007//Trelease_0_9_0
+/dsoundaudio.c/1.3/Fri Jan  5 14:34:35 2007//Trelease_0_9_0
+/fmodaudio.c/1.7/Fri Jan  5 14:34:35 2007//Trelease_0_9_0
+/mixeng.c/1.4/Wed Oct 18 10:11:20 2006//Trelease_0_9_0
+/mixeng.h/1.2/Wed Oct 18 10:11:20 2006//Trelease_0_9_0
+/mixeng_template.h/1.2/Wed Oct 18 10:11:20 2006//Trelease_0_9_0
+/noaudio.c/1.7/Fri Jan  5 14:34:35 2007//Trelease_0_9_0
+/ossaudio.c/1.11/Fri Jan  5 14:34:35 2007//Trelease_0_9_0
+/rate_template.h/1.3/Fri Jan  5 14:34:35 2007//Trelease_0_9_0
+/sdlaudio.c/1.8/Fri Jan  5 14:34:35 2007//Trelease_0_9_0
+/sys-queue.h/1.1/Wed Oct 18 10:11:20 2006//Trelease_0_9_0
+/wavaudio.c/1.9/Thu May  3 17:17:59 2007//Trelease_0_9_0
+/wavcapture.c/1.7/Thu May  3 17:17:59 2007//Trelease_0_9_0
 D
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/audio/.CVS/Tag
--- a/tools/ioemu/audio/.CVS/Tag        Tue May 08 10:38:06 2007 +0100
+++ b/tools/ioemu/audio/.CVS/Tag        Wed May 09 14:17:15 2007 +0100
@@ -1,1 +1,1 @@ Nrelease_0_8_2
-Nrelease_0_8_2
+Nrelease_0_9_0
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/audio/wavaudio.c
--- a/tools/ioemu/audio/wavaudio.c      Tue May 08 10:38:06 2007 +0100
+++ b/tools/ioemu/audio/wavaudio.c      Wed May 09 14:17:15 2007 +0100
@@ -151,7 +151,7 @@ static int wav_init_out (HWVoiceOut *hw,
     le_store (hdr + 28, hw->info.freq << (bits16 + stereo), 4);
     le_store (hdr + 32, 1 << (bits16 + stereo), 2);
 
-    wav->f = fopen (conf.wav_path, "wb");
+    wav->f = qemu_fopen (conf.wav_path, "wb");
     if (!wav->f) {
         dolog ("Failed to open wave file `%s'\nReason: %s\n",
                conf.wav_path, strerror (errno));
@@ -185,7 +185,7 @@ static void wav_fini_out (HWVoiceOut *hw
     qemu_fseek (wav->f, 32, SEEK_CUR);
     qemu_put_buffer (wav->f, dlen, 4);
 
-    fclose (wav->f);
+    qemu_fclose (wav->f);
     wav->f = NULL;
 
     qemu_free (wav->pcm_buf);
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/audio/wavcapture.c
--- a/tools/ioemu/audio/wavcapture.c    Tue May 08 10:38:06 2007 +0100
+++ b/tools/ioemu/audio/wavcapture.c    Wed May 09 14:17:15 2007 +0100
@@ -34,22 +34,19 @@ static void wav_destroy (void *opaque)
     uint32_t datalen = wav->bytes;
     uint32_t rifflen = datalen + 36;
 
-    if (!wav->f) {
-        return;
+    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);
     }
-
-    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);
-    fclose (wav->f);
-    if (wav->path) {
-        qemu_free (wav->path);
-    }
+    
+    qemu_free (wav->path);
 }
 
 static void wav_capture (void *opaque, void *buf, int size)
@@ -135,7 +132,7 @@ int wav_start_capture (CaptureState *s, 
     le_store (hdr + 28, freq << shift, 4);
     le_store (hdr + 32, 1 << shift, 2);
 
-    wav->f = fopen (path, "wb");
+    wav->f = qemu_fopen (path, "wb");
     if (!wav->f) {
         term_printf ("Failed to open wave file `%s'\nReason: %s\n",
                      path, strerror (errno));
@@ -153,6 +150,8 @@ int wav_start_capture (CaptureState *s, 
     cap = AUD_add_capture (NULL, &as, &ops, wav);
     if (!cap) {
         term_printf ("Failed to add audio capture\n");
+        qemu_free (wav->path);
+        qemu_fclose (wav->f);
         qemu_free (wav);
         return -1;
     }
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/block-bochs.c
--- a/tools/ioemu/block-bochs.c Tue May 08 10:38:06 2007 +0100
+++ b/tools/ioemu/block-bochs.c Wed May 09 14:17:15 2007 +0100
@@ -28,7 +28,8 @@
 /**************************************************************/
 
 #define HEADER_MAGIC "Bochs Virtual HD Image"
-#define HEADER_VERSION 0x00010000
+#define HEADER_VERSION 0x00020000
+#define HEADER_V1 0x00010000
 #define HEADER_SIZE 512
 
 #define REDOLOG_TYPE "Redolog"
@@ -37,7 +38,7 @@
 // not allocated: 0xffffffff
 
 // always little-endian
-struct bochs_header {
+struct bochs_header_v1 {
     char magic[32]; // "Bochs Virtual HD Image"
     char type[16]; // "Redolog"
     char subtype[16]; // "Undoable" / "Volatile" / "Growing"
@@ -56,6 +57,27 @@ struct bochs_header {
     } extra;
 };
 
+// always little-endian
+struct bochs_header {
+    char magic[32]; // "Bochs Virtual HD Image"
+    char type[16]; // "Redolog"
+    char subtype[16]; // "Undoable" / "Volatile" / "Growing"
+    uint32_t version;
+    uint32_t header; // size of header
+    
+    union {
+       struct {
+           uint32_t catalog; // num of entries
+           uint32_t bitmap; // bitmap size
+           uint32_t extent; // extent size
+           uint32_t reserved; // for ???
+           uint64_t disk; // disk size
+           char padding[HEADER_SIZE - 64 - 8 - 24];
+       } redolog;
+       char padding[HEADER_SIZE - 64 - 8];
+    } extra;
+};
+
 typedef struct BDRVBochsState {
     int fd;
 
@@ -79,21 +101,23 @@ static int bochs_probe(const uint8_t *bu
     if (!strcmp(bochs->magic, HEADER_MAGIC) &&
        !strcmp(bochs->type, REDOLOG_TYPE) &&
        !strcmp(bochs->subtype, GROWING_TYPE) &&
-       (le32_to_cpu(bochs->version) == HEADER_VERSION))
+       ((le32_to_cpu(bochs->version) == HEADER_VERSION) ||
+       (le32_to_cpu(bochs->version) == HEADER_V1)))
        return 100;
 
     return 0;
 }
 
-static int bochs_open(BlockDriverState *bs, const char *filename)
+static int bochs_open(BlockDriverState *bs, const char *filename, int flags)
 {
     BDRVBochsState *s = bs->opaque;
     int fd, i;
     struct bochs_header bochs;
-
-    fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
+    struct bochs_header_v1 header_v1;
+
+    fd = open(filename, O_RDWR | O_BINARY);
     if (fd < 0) {
-        fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
+        fd = open(filename, O_RDONLY | O_BINARY);
         if (fd < 0)
             return -1;
     }
@@ -109,11 +133,17 @@ static int bochs_open(BlockDriverState *
     if (strcmp(bochs.magic, HEADER_MAGIC) ||
         strcmp(bochs.type, REDOLOG_TYPE) ||
         strcmp(bochs.subtype, GROWING_TYPE) ||
-       (le32_to_cpu(bochs.version) != HEADER_VERSION)) {
+       ((le32_to_cpu(bochs.version) != HEADER_VERSION) &&
+       (le32_to_cpu(bochs.version) != HEADER_V1))) {
         goto fail;
     }
 
-    bs->total_sectors = le64_to_cpu(bochs.extra.redolog.disk) / 512;
+    if (le32_to_cpu(bochs.version) == HEADER_V1) {
+      memcpy(&header_v1, &bochs, sizeof(bochs));
+      bs->total_sectors = le64_to_cpu(header_v1.extra.redolog.disk) / 512;
+    } else {
+      bs->total_sectors = le64_to_cpu(bochs.extra.redolog.disk) / 512;
+    }
 
     lseek(s->fd, le32_to_cpu(bochs.header), SEEK_SET);
 
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/block-cloop.c
--- a/tools/ioemu/block-cloop.c Tue May 08 10:38:06 2007 +0100
+++ b/tools/ioemu/block-cloop.c Wed May 09 14:17:15 2007 +0100
@@ -50,14 +50,14 @@ static int cloop_probe(const uint8_t *bu
     return 0;
 }
 
-static int cloop_open(BlockDriverState *bs, const char *filename)
+static int cloop_open(BlockDriverState *bs, const char *filename, int flags)
 {
     BDRVCloopState *s = bs->opaque;
     uint32_t offsets_size,max_compressed_block_size=1,i;
 
-    s->fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
+    s->fd = open(filename, O_RDONLY | O_BINARY);
     if (s->fd < 0)
-        return -1;
+        return -errno;
     bs->read_only = 1;
 
     /* read header */
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/block-cow.c
--- a/tools/ioemu/block-cow.c   Tue May 08 10:38:06 2007 +0100
+++ b/tools/ioemu/block-cow.c   Wed May 09 14:17:15 2007 +0100
@@ -62,7 +62,7 @@ static int cow_probe(const uint8_t *buf,
         return 0;
 }
 
-static int cow_open(BlockDriverState *bs, const char *filename)
+static int cow_open(BlockDriverState *bs, const char *filename, int flags)
 {
     BDRVCowState *s = bs->opaque;
     int fd;
@@ -93,22 +93,6 @@ static int cow_open(BlockDriverState *bs
     pstrcpy(bs->backing_file, sizeof(bs->backing_file), 
             cow_header.backing_file);
     
-#if 0
-    if (cow_header.backing_file[0] != '\0') {
-        if (stat(cow_header.backing_file, &st) != 0) {
-            fprintf(stderr, "%s: could not find original disk image '%s'\n", 
filename, cow_header.backing_file);
-            goto fail;
-        }
-        if (st.st_mtime != be32_to_cpu(cow_header.mtime)) {
-            fprintf(stderr, "%s: original raw disk image '%s' does not match 
saved timestamp\n", filename, cow_header.backing_file);
-            goto fail;
-            }
-        fd = open(cow_header.backing_file, O_RDONLY | O_LARGEFILE);
-        if (fd < 0)
-            goto fail;
-        bs->fd = fd;
-    }
-#endif
     /* mmap the bitmap */
     s->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
     s->cow_bitmap_addr = mmap(get_mmap_addr(s->cow_bitmap_size), 
@@ -179,7 +163,14 @@ static int cow_read(BlockDriverState *bs
             if (ret != n * 512) 
                 return -1;
         } else {
+            if (bs->backing_hd) {
+                /* read from the base image */
+                ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
+                if (ret < 0)
+                    return -1;
+            } else {
             memset(buf, 0, n * 512);
+        }
         }
         nb_sectors -= n;
         sector_num += n;
@@ -220,7 +211,7 @@ static int cow_create(const char *filena
     if (flags)
         return -ENOTSUP;
 
-    cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | 
O_LARGEFILE, 
+    cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 
               0644);
     if (cow_fd < 0)
         return -1;
@@ -228,18 +219,23 @@ static int cow_create(const char *filena
     cow_header.magic = cpu_to_be32(COW_MAGIC);
     cow_header.version = cpu_to_be32(COW_VERSION);
     if (image_filename) {
+        /* Note: if no file, we put a dummy mtime */
+        cow_header.mtime = cpu_to_be32(0);
+
         fd = open(image_filename, O_RDONLY | O_BINARY);
         if (fd < 0) {
             close(cow_fd);
-            return -1;
+            goto mtime_fail;
         }
         if (fstat(fd, &st) != 0) {
             close(fd);
-            return -1;
+            goto mtime_fail;
         }
         close(fd);
         cow_header.mtime = cpu_to_be32(st.st_mtime);
-        realpath(image_filename, cow_header.backing_file);
+    mtime_fail:
+        pstrcpy(cow_header.backing_file, sizeof(cow_header.backing_file),
+                image_filename);
     }
     cow_header.sectorsize = cpu_to_be32(512);
     cow_header.size = cpu_to_be64(image_sectors * 512);
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/block-dmg.c
--- a/tools/ioemu/block-dmg.c   Tue May 08 10:38:06 2007 +0100
+++ b/tools/ioemu/block-dmg.c   Wed May 09 14:17:15 2007 +0100
@@ -73,16 +73,16 @@ static off_t read_uint32(int fd)
        return be32_to_cpu(buffer);
 }
 
-static int dmg_open(BlockDriverState *bs, const char *filename)
+static int dmg_open(BlockDriverState *bs, const char *filename, int flags)
 {
     BDRVDMGState *s = bs->opaque;
     off_t info_begin,info_end,last_in_offset,last_out_offset;
     uint32_t count;
     uint32_t max_compressed_size=1,max_sectors_per_chunk=1,i;
 
-    s->fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
+    s->fd = open(filename, O_RDONLY | O_BINARY);
     if (s->fd < 0)
-        return -1;
+        return -errno;
     bs->read_only = 1;
     s->n_chunks = 0;
     s->offsets = s->lengths = s->sectors = s->sectorcounts = 0;
@@ -93,7 +93,7 @@ dmg_close:
        close(s->fd);
        /* open raw instead */
        bs->drv=&bdrv_raw;
-       return bs->drv->bdrv_open(bs,filename);
+       return bs->drv->bdrv_open(bs, filename, flags);
     }
     info_begin=read_off(s->fd);
     if(info_begin==0)
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/block-qcow.c
--- a/tools/ioemu/block-qcow.c  Tue May 08 10:38:06 2007 +0100
+++ b/tools/ioemu/block-qcow.c  Wed May 09 14:17:15 2007 +0100
@@ -1,7 +1,7 @@
 /*
  * Block driver for the QCOW format
  * 
- * Copyright (c) 2004 Fabrice Bellard
+ * Copyright (c) 2004-2006 Fabrice Bellard
  * 
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to 
deal
@@ -53,7 +53,7 @@ typedef struct QCowHeader {
 #define L2_CACHE_SIZE 16
 
 typedef struct BDRVQcowState {
-    int fd;
+    BlockDriverState *hd;
     int cluster_bits;
     int cluster_size;
     int cluster_sectors;
@@ -89,20 +89,16 @@ static int qcow_probe(const uint8_t *buf
         return 0;
 }
 
-static int qcow_open(BlockDriverState *bs, const char *filename)
-{
-    BDRVQcowState *s = bs->opaque;
-    int fd, len, i, shift;
+static int qcow_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    BDRVQcowState *s = bs->opaque;
+    int len, i, shift, ret;
     QCowHeader header;
-    
-    fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
-    if (fd < 0) {
-        fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
-        if (fd < 0)
-            return -1;
-    }
-    s->fd = fd;
-    if (read(fd, &header, sizeof(header)) != sizeof(header))
+
+    ret = bdrv_file_open(&s->hd, filename, flags);
+    if (ret < 0)
+        return ret;
+    if (bdrv_pread(s->hd, 0, &header, sizeof(header)) != sizeof(header))
         goto fail;
     be32_to_cpus(&header.magic);
     be32_to_cpus(&header.version);
@@ -138,8 +134,7 @@ static int qcow_open(BlockDriverState *b
     s->l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
     if (!s->l1_table)
         goto fail;
-    lseek(fd, s->l1_table_offset, SEEK_SET);
-    if (read(fd, s->l1_table, s->l1_size * sizeof(uint64_t)) != 
+    if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, s->l1_size * 
sizeof(uint64_t)) != 
         s->l1_size * sizeof(uint64_t))
         goto fail;
     for(i = 0;i < s->l1_size; i++) {
@@ -162,8 +157,7 @@ static int qcow_open(BlockDriverState *b
         len = header.backing_file_size;
         if (len > 1023)
             len = 1023;
-        lseek(fd, header.backing_file_offset, SEEK_SET);
-        if (read(fd, bs->backing_file, len) != len)
+        if (bdrv_pread(s->hd, header.backing_file_offset, bs->backing_file, 
len) != len)
             goto fail;
         bs->backing_file[len] = '\0';
     }
@@ -174,7 +168,7 @@ static int qcow_open(BlockDriverState *b
     qemu_free(s->l2_cache);
     qemu_free(s->cluster_cache);
     qemu_free(s->cluster_data);
-    close(fd);
+    bdrv_delete(s->hd);
     return -1;
 }
 
@@ -276,14 +270,14 @@ static uint64_t get_cluster_offset(Block
         if (!allocate)
             return 0;
         /* allocate a new l2 entry */
-        l2_offset = lseek(s->fd, 0, SEEK_END);
+        l2_offset = bdrv_getlength(s->hd);
         /* round to cluster size */
         l2_offset = (l2_offset + s->cluster_size - 1) & ~(s->cluster_size - 1);
         /* update the L1 entry */
         s->l1_table[l1_index] = l2_offset;
         tmp = cpu_to_be64(l2_offset);
-        lseek(s->fd, s->l1_table_offset + l1_index * sizeof(tmp), SEEK_SET);
-        if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
+        if (bdrv_pwrite(s->hd, s->l1_table_offset + l1_index * sizeof(tmp), 
+                        &tmp, sizeof(tmp)) != sizeof(tmp))
             return 0;
         new_l2_table = 1;
     }
@@ -309,14 +303,13 @@ static uint64_t get_cluster_offset(Block
         }
     }
     l2_table = s->l2_cache + (min_index << s->l2_bits);
-    lseek(s->fd, l2_offset, SEEK_SET);
     if (new_l2_table) {
         memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
-        if (write(s->fd, l2_table, s->l2_size * sizeof(uint64_t)) !=
+        if (bdrv_pwrite(s->hd, l2_offset, l2_table, s->l2_size * 
sizeof(uint64_t)) !=
             s->l2_size * sizeof(uint64_t))
             return 0;
     } else {
-        if (read(s->fd, l2_table, s->l2_size * sizeof(uint64_t)) != 
+        if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * 
sizeof(uint64_t)) != 
             s->l2_size * sizeof(uint64_t))
             return 0;
     }
@@ -337,36 +330,35 @@ static uint64_t get_cluster_offset(Block
                overwritten */
             if (decompress_cluster(s, cluster_offset) < 0)
                 return 0;
-            cluster_offset = lseek(s->fd, 0, SEEK_END);
+            cluster_offset = bdrv_getlength(s->hd);
             cluster_offset = (cluster_offset + s->cluster_size - 1) & 
                 ~(s->cluster_size - 1);
             /* write the cluster content */
-            lseek(s->fd, cluster_offset, SEEK_SET);
-            if (write(s->fd, s->cluster_cache, s->cluster_size) != 
+            if (bdrv_pwrite(s->hd, cluster_offset, s->cluster_cache, 
s->cluster_size) != 
                 s->cluster_size)
                 return -1;
         } else {
-            cluster_offset = lseek(s->fd, 0, SEEK_END);
+            cluster_offset = bdrv_getlength(s->hd);
             if (allocate == 1) {
                 /* round to cluster size */
                 cluster_offset = (cluster_offset + s->cluster_size - 1) & 
                     ~(s->cluster_size - 1);
-                ftruncate(s->fd, cluster_offset + s->cluster_size);
+                bdrv_truncate(s->hd, cluster_offset + s->cluster_size);
                 /* if encrypted, we must initialize the cluster
                    content which won't be written */
                 if (s->crypt_method && 
                     (n_end - n_start) < s->cluster_sectors) {
                     uint64_t start_sect;
                     start_sect = (offset & ~(s->cluster_size - 1)) >> 9;
-                    memset(s->cluster_data + 512, 0xaa, 512);
+                    memset(s->cluster_data + 512, 0x00, 512);
                     for(i = 0; i < s->cluster_sectors; i++) {
                         if (i < n_start || i >= n_end) {
                             encrypt_sectors(s, start_sect + i, 
                                             s->cluster_data, 
                                             s->cluster_data + 512, 1, 1,
                                             &s->aes_encrypt_key);
-                            lseek(s->fd, cluster_offset + i * 512, SEEK_SET);
-                            if (write(s->fd, s->cluster_data, 512) != 512)
+                            if (bdrv_pwrite(s->hd, cluster_offset + i * 512, 
+                                            s->cluster_data, 512) != 512)
                                 return -1;
                         }
                     }
@@ -379,8 +371,8 @@ static uint64_t get_cluster_offset(Block
         /* update L2 table */
         tmp = cpu_to_be64(cluster_offset);
         l2_table[l2_index] = tmp;
-        lseek(s->fd, l2_offset + l2_index * sizeof(tmp), SEEK_SET);
-        if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
+        if (bdrv_pwrite(s->hd, 
+                        l2_offset + l2_index * sizeof(tmp), &tmp, sizeof(tmp)) 
!= sizeof(tmp))
             return 0;
     }
     return cluster_offset;
@@ -438,8 +430,7 @@ static int decompress_cluster(BDRVQcowSt
     if (s->cluster_cache_offset != coffset) {
         csize = cluster_offset >> (63 - s->cluster_bits);
         csize &= (s->cluster_size - 1);
-        lseek(s->fd, coffset, SEEK_SET);
-        ret = read(s->fd, s->cluster_data, csize);
+        ret = bdrv_pread(s->hd, coffset, s->cluster_data, csize);
         if (ret != csize) 
             return -1;
         if (decompress_buffer(s->cluster_cache, s->cluster_size,
@@ -450,6 +441,8 @@ static int decompress_cluster(BDRVQcowSt
     }
     return 0;
 }
+
+#if 0
 
 static int qcow_read(BlockDriverState *bs, int64_t sector_num, 
                      uint8_t *buf, int nb_sectors)
@@ -465,14 +458,20 @@ static int qcow_read(BlockDriverState *b
         if (n > nb_sectors)
             n = nb_sectors;
         if (!cluster_offset) {
-            memset(buf, 0, 512 * n);
+            if (bs->backing_hd) {
+                /* read from the base image */
+                ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
+                if (ret < 0)
+                    return -1;
+            } else {
+                memset(buf, 0, 512 * n);
+            }
         } else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
             if (decompress_cluster(s, cluster_offset) < 0)
                 return -1;
             memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n);
         } else {
-            lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
-            ret = read(s->fd, buf, n * 512);
+            ret = bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, 
buf, n * 512);
             if (ret != n * 512) 
                 return -1;
             if (s->crypt_method) {
@@ -486,6 +485,7 @@ static int qcow_read(BlockDriverState *b
     }
     return 0;
 }
+#endif
 
 static int qcow_write(BlockDriverState *bs, int64_t sector_num, 
                      const uint8_t *buf, int nb_sectors)
@@ -504,13 +504,13 @@ static int qcow_write(BlockDriverState *
                                             index_in_cluster + n);
         if (!cluster_offset)
             return -1;
-        lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
         if (s->crypt_method) {
             encrypt_sectors(s, sector_num, s->cluster_data, buf, n, 1,
                             &s->aes_encrypt_key);
-            ret = write(s->fd, s->cluster_data, n * 512);
+            ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, 
+                              s->cluster_data, n * 512);
         } else {
-            ret = write(s->fd, buf, n * 512);
+            ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, 
buf, n * 512);
         }
         if (ret != n * 512) 
             return -1;
@@ -522,6 +522,209 @@ static int qcow_write(BlockDriverState *
     return 0;
 }
 
+typedef struct QCowAIOCB {
+    BlockDriverAIOCB common;
+    int64_t sector_num;
+    uint8_t *buf;
+    int nb_sectors;
+    int n;
+    uint64_t cluster_offset;
+    uint8_t *cluster_data; 
+    BlockDriverAIOCB *hd_aiocb;
+} QCowAIOCB;
+
+static void qcow_aio_read_cb(void *opaque, int ret)
+{
+    QCowAIOCB *acb = opaque;
+    BlockDriverState *bs = acb->common.bs;
+    BDRVQcowState *s = bs->opaque;
+    int index_in_cluster;
+
+    acb->hd_aiocb = NULL;
+    if (ret < 0) {
+    fail:
+        acb->common.cb(acb->common.opaque, ret);
+        qemu_aio_release(acb);
+        return;
+    }
+
+ redo:
+    /* post process the read buffer */
+    if (!acb->cluster_offset) {
+        /* nothing to do */
+    } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
+        /* nothing to do */
+    } else {
+        if (s->crypt_method) {
+            encrypt_sectors(s, acb->sector_num, acb->buf, acb->buf, 
+                            acb->n, 0, 
+                            &s->aes_decrypt_key);
+        }
+    }
+
+    acb->nb_sectors -= acb->n;
+    acb->sector_num += acb->n;
+    acb->buf += acb->n * 512;
+
+    if (acb->nb_sectors == 0) {
+        /* request completed */
+        acb->common.cb(acb->common.opaque, 0);
+        qemu_aio_release(acb);
+        return;
+    }
+    
+    /* prepare next AIO request */
+    acb->cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, 
+                                             0, 0, 0, 0);
+    index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
+    acb->n = s->cluster_sectors - index_in_cluster;
+    if (acb->n > acb->nb_sectors)
+        acb->n = acb->nb_sectors;
+
+    if (!acb->cluster_offset) {
+        if (bs->backing_hd) {
+            /* read from the base image */
+            acb->hd_aiocb = bdrv_aio_read(bs->backing_hd,
+                acb->sector_num, acb->buf, acb->n, qcow_aio_read_cb, acb);
+            if (acb->hd_aiocb == NULL)
+                goto fail;
+        } else {
+            /* Note: in this case, no need to wait */
+            memset(acb->buf, 0, 512 * acb->n);
+            goto redo;
+        }
+    } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
+        /* add AIO support for compressed blocks ? */
+        if (decompress_cluster(s, acb->cluster_offset) < 0)
+            goto fail;
+        memcpy(acb->buf, 
+               s->cluster_cache + index_in_cluster * 512, 512 * acb->n);
+        goto redo;
+    } else {
+        if ((acb->cluster_offset & 511) != 0) {
+            ret = -EIO;
+            goto fail;
+        }
+        acb->hd_aiocb = bdrv_aio_read(s->hd,
+                            (acb->cluster_offset >> 9) + index_in_cluster, 
+                            acb->buf, acb->n, qcow_aio_read_cb, acb);
+        if (acb->hd_aiocb == NULL)
+            goto fail;
+    }
+}
+
+static BlockDriverAIOCB *qcow_aio_read(BlockDriverState *bs,
+        int64_t sector_num, uint8_t *buf, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    QCowAIOCB *acb;
+
+    acb = qemu_aio_get(bs, cb, opaque);
+    if (!acb)
+        return NULL;
+    acb->hd_aiocb = NULL;
+    acb->sector_num = sector_num;
+    acb->buf = buf;
+    acb->nb_sectors = nb_sectors;
+    acb->n = 0;
+    acb->cluster_offset = 0;    
+
+    qcow_aio_read_cb(acb, 0);
+    return &acb->common;
+}
+
+static void qcow_aio_write_cb(void *opaque, int ret)
+{
+    QCowAIOCB *acb = opaque;
+    BlockDriverState *bs = acb->common.bs;
+    BDRVQcowState *s = bs->opaque;
+    int index_in_cluster;
+    uint64_t cluster_offset;
+    const uint8_t *src_buf;
+
+    acb->hd_aiocb = NULL;
+
+    if (ret < 0) {
+    fail:
+        acb->common.cb(acb->common.opaque, ret);
+        qemu_aio_release(acb);
+        return;
+    }
+
+    acb->nb_sectors -= acb->n;
+    acb->sector_num += acb->n;
+    acb->buf += acb->n * 512;
+
+    if (acb->nb_sectors == 0) {
+        /* request completed */
+        acb->common.cb(acb->common.opaque, 0);
+        qemu_aio_release(acb);
+        return;
+    }
+    
+    index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
+    acb->n = s->cluster_sectors - index_in_cluster;
+    if (acb->n > acb->nb_sectors)
+        acb->n = acb->nb_sectors;
+    cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, 1, 0, 
+                                        index_in_cluster, 
+                                        index_in_cluster + acb->n);
+    if (!cluster_offset || (cluster_offset & 511) != 0) {
+        ret = -EIO;
+        goto fail;
+    }
+    if (s->crypt_method) {
+        if (!acb->cluster_data) {
+            acb->cluster_data = qemu_mallocz(s->cluster_size);
+            if (!acb->cluster_data) {
+                ret = -ENOMEM;
+                goto fail;
+            }
+        }
+        encrypt_sectors(s, acb->sector_num, acb->cluster_data, acb->buf, 
+                        acb->n, 1, &s->aes_encrypt_key);
+        src_buf = acb->cluster_data;
+    } else {
+        src_buf = acb->buf;
+    }
+    acb->hd_aiocb = bdrv_aio_write(s->hd,
+                                   (cluster_offset >> 9) + index_in_cluster, 
+                                   src_buf, acb->n, 
+                                   qcow_aio_write_cb, acb);
+    if (acb->hd_aiocb == NULL)
+        goto fail;
+}
+
+static BlockDriverAIOCB *qcow_aio_write(BlockDriverState *bs,
+        int64_t sector_num, const uint8_t *buf, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BDRVQcowState *s = bs->opaque;
+    QCowAIOCB *acb;
+    
+    s->cluster_cache_offset = -1; /* disable compressed cache */
+
+    acb = qemu_aio_get(bs, cb, opaque);
+    if (!acb)
+        return NULL;
+    acb->hd_aiocb = NULL;
+    acb->sector_num = sector_num;
+    acb->buf = (uint8_t *)buf;
+    acb->nb_sectors = nb_sectors;
+    acb->n = 0;
+    
+    qcow_aio_write_cb(acb, 0);
+    return &acb->common;
+}
+
+static void qcow_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+    QCowAIOCB *acb = (QCowAIOCB *)blockacb;
+    if (acb->hd_aiocb)
+        bdrv_aio_cancel(acb->hd_aiocb);
+    qemu_aio_release(acb);
+}
+
 static void qcow_close(BlockDriverState *bs)
 {
     BDRVQcowState *s = bs->opaque;
@@ -529,7 +732,7 @@ static void qcow_close(BlockDriverState 
     qemu_free(s->l2_cache);
     qemu_free(s->cluster_cache);
     qemu_free(s->cluster_data);
-    close(s->fd);
+    bdrv_delete(s->hd);
 }
 
 static int qcow_create(const char *filename, int64_t total_size,
@@ -537,12 +740,9 @@ static int qcow_create(const char *filen
 {
     int fd, header_size, backing_filename_len, l1_size, i, shift;
     QCowHeader header;
-    char backing_filename[1024];
     uint64_t tmp;
-    struct stat st;
-
-    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 
-              0644);
+
+    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
     if (fd < 0)
         return -1;
     memset(&header, 0, sizeof(header));
@@ -552,28 +752,11 @@ static int qcow_create(const char *filen
     header_size = sizeof(header);
     backing_filename_len = 0;
     if (backing_file) {
-       if (strcmp(backing_file, "fat:")) {
-           const char *p;
-           /* XXX: this is a hack: we do not attempt to check for URL
-              like syntax */
-           p = strchr(backing_file, ':');
-           if (p && (p - backing_file) >= 2) {
-               /* URL like but exclude "c:" like filenames */
-               pstrcpy(backing_filename, sizeof(backing_filename),
-                       backing_file);
-           } else {
-               realpath(backing_file, backing_filename);
-               if (stat(backing_filename, &st) != 0) {
-                   return -1;
-               }
-           }
-           header.backing_file_offset = cpu_to_be64(header_size);
-           backing_filename_len = strlen(backing_filename);
-           header.backing_file_size = cpu_to_be32(backing_filename_len);
-           header_size += backing_filename_len;
-       } else
-           backing_file = NULL;
-        header.mtime = cpu_to_be32(st.st_mtime);
+        header.backing_file_offset = cpu_to_be64(header_size);
+        backing_filename_len = strlen(backing_file);
+        header.backing_file_size = cpu_to_be32(backing_filename_len);
+        header_size += backing_filename_len;
+        header.mtime = cpu_to_be32(0);
         header.cluster_bits = 9; /* 512 byte cluster to avoid copying
                                     unmodifyed sectors */
         header.l2_bits = 12; /* 32 KB L2 tables */
@@ -595,7 +778,7 @@ static int qcow_create(const char *filen
     /* write all the data */
     write(fd, &header, sizeof(header));
     if (backing_file) {
-        write(fd, backing_filename, backing_filename_len);
+        write(fd, backing_file, backing_filename_len);
     }
     lseek(fd, header_size, SEEK_SET);
     tmp = 0;
@@ -606,16 +789,18 @@ static int qcow_create(const char *filen
     return 0;
 }
 
-int qcow_make_empty(BlockDriverState *bs)
+static int qcow_make_empty(BlockDriverState *bs)
 {
     BDRVQcowState *s = bs->opaque;
     uint32_t l1_length = s->l1_size * sizeof(uint64_t);
+    int ret;
 
     memset(s->l1_table, 0, l1_length);
-    lseek(s->fd, s->l1_table_offset, SEEK_SET);
-    if (write(s->fd, s->l1_table, l1_length) < 0)
+    if (bdrv_pwrite(s->hd, s->l1_table_offset, s->l1_table, l1_length) < 0)
        return -1;
-    ftruncate(s->fd, s->l1_table_offset + l1_length);
+    ret = bdrv_truncate(s->hd, s->l1_table_offset + l1_length);
+    if (ret < 0)
+        return ret;
 
     memset(s->l2_cache, 0, s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
     memset(s->l2_cache_offsets, 0, L2_CACHE_SIZE * sizeof(uint64_t));
@@ -624,18 +809,10 @@ int qcow_make_empty(BlockDriverState *bs
     return 0;
 }
 
-int qcow_get_cluster_size(BlockDriverState *bs)
-{
-    BDRVQcowState *s = bs->opaque;
-    if (bs->drv != &bdrv_qcow)
-        return -1;
-    return s->cluster_size;
-}
-
 /* XXX: put compressed sectors first, then all the cluster aligned
    tables to avoid losing bytes in alignment */
-int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num, 
-                          const uint8_t *buf)
+static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, 
+                                 const uint8_t *buf, int nb_sectors)
 {
     BDRVQcowState *s = bs->opaque;
     z_stream strm;
@@ -643,8 +820,8 @@ int qcow_compress_cluster(BlockDriverSta
     uint8_t *out_buf;
     uint64_t cluster_offset;
 
-    if (bs->drv != &bdrv_qcow)
-        return -1;
+    if (nb_sectors != s->cluster_sectors)
+        return -EINVAL;
 
     out_buf = qemu_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);
     if (!out_buf)
@@ -682,8 +859,7 @@ int qcow_compress_cluster(BlockDriverSta
         cluster_offset = get_cluster_offset(bs, sector_num << 9, 2, 
                                             out_len, 0, 0);
         cluster_offset &= s->cluster_offset_mask;
-        lseek(s->fd, cluster_offset, SEEK_SET);
-        if (write(s->fd, out_buf, out_len) != out_len) {
+        if (bdrv_pwrite(s->hd, cluster_offset, out_buf, out_len) != out_len) {
             qemu_free(out_buf);
             return -1;
         }
@@ -696,7 +872,14 @@ static void qcow_flush(BlockDriverState 
 static void qcow_flush(BlockDriverState *bs)
 {
     BDRVQcowState *s = bs->opaque;
-    fsync(s->fd);
+    bdrv_flush(s->hd);
+}
+
+static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
+{
+    BDRVQcowState *s = bs->opaque;
+    bdi->cluster_size = s->cluster_size;
+    return 0;
 }
 
 BlockDriver bdrv_qcow = {
@@ -704,14 +887,19 @@ BlockDriver bdrv_qcow = {
     sizeof(BDRVQcowState),
     qcow_probe,
     qcow_open,
-    qcow_read,
-    qcow_write,
+    NULL,
+    NULL,
     qcow_close,
     qcow_create,
     qcow_flush,
     qcow_is_allocated,
     qcow_set_key,
-    qcow_make_empty
+    qcow_make_empty,
+
+    .bdrv_aio_read = qcow_aio_read,
+    .bdrv_aio_write = qcow_aio_write,
+    .bdrv_aio_cancel = qcow_aio_cancel,
+    .aiocb_size = sizeof(QCowAIOCB),
+    .bdrv_write_compressed = qcow_write_compressed,
+    .bdrv_get_info = qcow_get_info,
 };
-
-
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/block-qcow2.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ioemu/block-qcow2.c Wed May 09 14:17:15 2007 +0100
@@ -0,0 +1,2246 @@
+/*
+ * Block driver for the QCOW version 2 format
+ * 
+ * Copyright (c) 2004-2006 Fabrice Bellard
+ * 
+ * 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 "vl.h"
+#include "block_int.h"
+#include <zlib.h>
+#include "aes.h"
+#include <assert.h>
+
+/*
+  Differences with QCOW:
+
+  - Support for multiple incremental snapshots.
+  - Memory management by reference counts.
+  - Clusters which have a reference count of one have the bit
+    QCOW_OFLAG_COPIED to optimize write performance.
+  - Size of compressed clusters is stored in sectors to reduce bit usage 
+    in the cluster offsets.
+  - Support for storing additional data (such as the VM state) in the
+    snapshots.  
+  - If a backing store is used, the cluster size is not constrained
+    (could be backported to QCOW).
+  - L2 tables have always a size of one cluster.
+*/
+
+//#define DEBUG_ALLOC
+//#define DEBUG_ALLOC2
+ 
+#define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb)
+#define QCOW_VERSION 2
+
+#define QCOW_CRYPT_NONE 0
+#define QCOW_CRYPT_AES  1
+
+/* indicate that the refcount of the referenced cluster is exactly one. */
+#define QCOW_OFLAG_COPIED     (1LL << 63)
+/* indicate that the cluster is compressed (they never have the copied flag) */
+#define QCOW_OFLAG_COMPRESSED (1LL << 62)
+
+#define REFCOUNT_SHIFT 1 /* refcount size is 2 bytes */
+
+#ifndef offsetof
+#define offsetof(type, field) ((size_t) &((type *)0)->field)
+#endif
+
+typedef struct QCowHeader {
+    uint32_t magic;
+    uint32_t version;
+    uint64_t backing_file_offset;
+    uint32_t backing_file_size;
+    uint32_t cluster_bits;
+    uint64_t size; /* in bytes */
+    uint32_t crypt_method;
+    uint32_t l1_size; /* XXX: save number of clusters instead ? */
+    uint64_t l1_table_offset;
+    uint64_t refcount_table_offset;
+    uint32_t refcount_table_clusters;
+    uint32_t nb_snapshots;
+    uint64_t snapshots_offset;
+} QCowHeader;
+
+typedef struct __attribute__((packed)) QCowSnapshotHeader {
+    /* header is 8 byte aligned */
+    uint64_t l1_table_offset;
+
+    uint32_t l1_size;
+    uint16_t id_str_size;
+    uint16_t name_size;
+
+    uint32_t date_sec;
+    uint32_t date_nsec;
+
+    uint64_t vm_clock_nsec;
+
+    uint32_t vm_state_size;
+    uint32_t extra_data_size; /* for extension */
+    /* extra data follows */
+    /* id_str follows */
+    /* name follows  */
+} QCowSnapshotHeader;
+
+#define L2_CACHE_SIZE 16
+
+typedef struct QCowSnapshot {
+    uint64_t l1_table_offset;
+    uint32_t l1_size;
+    char *id_str;
+    char *name;
+    uint32_t vm_state_size;
+    uint32_t date_sec;
+    uint32_t date_nsec;
+    uint64_t vm_clock_nsec;
+} QCowSnapshot;
+
+typedef struct BDRVQcowState {
+    BlockDriverState *hd;
+    int cluster_bits;
+    int cluster_size;
+    int cluster_sectors;
+    int l2_bits;
+    int l2_size;
+    int l1_size;
+    int l1_vm_state_index;
+    int csize_shift;
+    int csize_mask;
+    uint64_t cluster_offset_mask;
+    uint64_t l1_table_offset;
+    uint64_t *l1_table;
+    uint64_t *l2_cache;
+    uint64_t l2_cache_offsets[L2_CACHE_SIZE];
+    uint32_t l2_cache_counts[L2_CACHE_SIZE];
+    uint8_t *cluster_cache;
+    uint8_t *cluster_data;
+    uint64_t cluster_cache_offset;
+
+    uint64_t *refcount_table;
+    uint64_t refcount_table_offset;
+    uint32_t refcount_table_size;
+    uint64_t refcount_block_cache_offset;
+    uint16_t *refcount_block_cache;
+    int64_t free_cluster_index;
+    int64_t free_byte_offset;
+
+    uint32_t crypt_method; /* current crypt method, 0 if no key yet */
+    uint32_t crypt_method_header;
+    AES_KEY aes_encrypt_key;
+    AES_KEY aes_decrypt_key;
+    uint64_t snapshots_offset;
+    int snapshots_size;
+    int nb_snapshots;
+    QCowSnapshot *snapshots;
+} BDRVQcowState;
+
+static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset);
+static int qcow_read(BlockDriverState *bs, int64_t sector_num, 
+                     uint8_t *buf, int nb_sectors);
+static int qcow_read_snapshots(BlockDriverState *bs);
+static void qcow_free_snapshots(BlockDriverState *bs);
+static int refcount_init(BlockDriverState *bs);
+static void refcount_close(BlockDriverState *bs);
+static int get_refcount(BlockDriverState *bs, int64_t cluster_index);
+static int update_cluster_refcount(BlockDriverState *bs, 
+                                   int64_t cluster_index,
+                                   int addend);
+static void update_refcount(BlockDriverState *bs, 
+                            int64_t offset, int64_t length, 
+                            int addend);
+static int64_t alloc_clusters(BlockDriverState *bs, int64_t size);
+static int64_t alloc_bytes(BlockDriverState *bs, int size);
+static void free_clusters(BlockDriverState *bs, 
+                          int64_t offset, int64_t size);
+#ifdef DEBUG_ALLOC
+static void check_refcounts(BlockDriverState *bs);
+#endif
+
+static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
+{
+    const QCowHeader *cow_header = (const void *)buf;
+    
+    if (buf_size >= sizeof(QCowHeader) &&
+        be32_to_cpu(cow_header->magic) == QCOW_MAGIC &&
+        be32_to_cpu(cow_header->version) == QCOW_VERSION) 
+        return 100;
+    else
+        return 0;
+}
+
+static int qcow_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    BDRVQcowState *s = bs->opaque;
+    int len, i, shift, ret;
+    QCowHeader header;
+
+    ret = bdrv_file_open(&s->hd, filename, flags);
+    if (ret < 0)
+        return ret;
+    if (bdrv_pread(s->hd, 0, &header, sizeof(header)) != sizeof(header))
+        goto fail;
+    be32_to_cpus(&header.magic);
+    be32_to_cpus(&header.version);
+    be64_to_cpus(&header.backing_file_offset);
+    be32_to_cpus(&header.backing_file_size);
+    be64_to_cpus(&header.size);
+    be32_to_cpus(&header.cluster_bits);
+    be32_to_cpus(&header.crypt_method);
+    be64_to_cpus(&header.l1_table_offset);
+    be32_to_cpus(&header.l1_size);
+    be64_to_cpus(&header.refcount_table_offset);
+    be32_to_cpus(&header.refcount_table_clusters);
+    be64_to_cpus(&header.snapshots_offset);
+    be32_to_cpus(&header.nb_snapshots);
+    
+    if (header.magic != QCOW_MAGIC || header.version != QCOW_VERSION)
+        goto fail;
+    if (header.size <= 1 || 
+        header.cluster_bits < 9 || 
+        header.cluster_bits > 16)
+        goto fail;
+    if (header.crypt_method > QCOW_CRYPT_AES)
+        goto fail;
+    s->crypt_method_header = header.crypt_method;
+    if (s->crypt_method_header)
+        bs->encrypted = 1;
+    s->cluster_bits = header.cluster_bits;
+    s->cluster_size = 1 << s->cluster_bits;
+    s->cluster_sectors = 1 << (s->cluster_bits - 9);
+    s->l2_bits = s->cluster_bits - 3; /* L2 is always one cluster */
+    s->l2_size = 1 << s->l2_bits;
+    bs->total_sectors = header.size / 512;
+    s->csize_shift = (62 - (s->cluster_bits - 8));
+    s->csize_mask = (1 << (s->cluster_bits - 8)) - 1;
+    s->cluster_offset_mask = (1LL << s->csize_shift) - 1;
+    s->refcount_table_offset = header.refcount_table_offset;
+    s->refcount_table_size = 
+        header.refcount_table_clusters << (s->cluster_bits - 3);
+
+    s->snapshots_offset = header.snapshots_offset;
+    s->nb_snapshots = header.nb_snapshots;
+
+    /* read the level 1 table */
+    s->l1_size = header.l1_size;
+    shift = s->cluster_bits + s->l2_bits;
+    s->l1_vm_state_index = (header.size + (1LL << shift) - 1) >> shift;
+    /* the L1 table must contain at least enough entries to put
+       header.size bytes */
+    if (s->l1_size < s->l1_vm_state_index)
+        goto fail;
+    s->l1_table_offset = header.l1_table_offset;
+    s->l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
+    if (!s->l1_table)
+        goto fail;
+    if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, s->l1_size * 
sizeof(uint64_t)) != 
+        s->l1_size * sizeof(uint64_t))
+        goto fail;
+    for(i = 0;i < s->l1_size; i++) {
+        be64_to_cpus(&s->l1_table[i]);
+    }
+    /* alloc L2 cache */
+    s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
+    if (!s->l2_cache)
+        goto fail;
+    s->cluster_cache = qemu_malloc(s->cluster_size);
+    if (!s->cluster_cache)
+        goto fail;
+    /* one more sector for decompressed data alignment */
+    s->cluster_data = qemu_malloc(s->cluster_size + 512);
+    if (!s->cluster_data)
+        goto fail;
+    s->cluster_cache_offset = -1;
+    
+    if (refcount_init(bs) < 0)
+        goto fail;
+
+    /* read the backing file name */
+    if (header.backing_file_offset != 0) {
+        len = header.backing_file_size;
+        if (len > 1023)
+            len = 1023;
+        if (bdrv_pread(s->hd, header.backing_file_offset, bs->backing_file, 
len) != len)
+            goto fail;
+        bs->backing_file[len] = '\0';
+    }
+    if (qcow_read_snapshots(bs) < 0)
+        goto fail;
+
+#ifdef DEBUG_ALLOC
+    check_refcounts(bs);
+#endif
+    return 0;
+
+ fail:
+    qcow_free_snapshots(bs);
+    refcount_close(bs);
+    qemu_free(s->l1_table);
+    qemu_free(s->l2_cache);
+    qemu_free(s->cluster_cache);
+    qemu_free(s->cluster_data);
+    bdrv_delete(s->hd);
+    return -1;
+}
+
+static int qcow_set_key(BlockDriverState *bs, const char *key)
+{
+    BDRVQcowState *s = bs->opaque;
+    uint8_t keybuf[16];
+    int len, i;
+    
+    memset(keybuf, 0, 16);
+    len = strlen(key);
+    if (len > 16)
+        len = 16;
+    /* XXX: we could compress the chars to 7 bits to increase
+       entropy */
+    for(i = 0;i < len;i++) {
+        keybuf[i] = key[i];
+    }
+    s->crypt_method = s->crypt_method_header;
+
+    if (AES_set_encrypt_key(keybuf, 128, &s->aes_encrypt_key) != 0)
+        return -1;
+    if (AES_set_decrypt_key(keybuf, 128, &s->aes_decrypt_key) != 0)
+        return -1;
+#if 0
+    /* test */
+    {
+        uint8_t in[16];
+        uint8_t out[16];
+        uint8_t tmp[16];
+        for(i=0;i<16;i++)
+            in[i] = i;
+        AES_encrypt(in, tmp, &s->aes_encrypt_key);
+        AES_decrypt(tmp, out, &s->aes_decrypt_key);
+        for(i = 0; i < 16; i++)
+            printf(" %02x", tmp[i]);
+        printf("\n");
+        for(i = 0; i < 16; i++)
+            printf(" %02x", out[i]);
+        printf("\n");
+    }
+#endif
+    return 0;
+}
+
+/* The crypt function is compatible with the linux cryptoloop
+   algorithm for < 4 GB images. NOTE: out_buf == in_buf is
+   supported */
+static void encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
+                            uint8_t *out_buf, const uint8_t *in_buf,
+                            int nb_sectors, int enc,
+                            const AES_KEY *key)
+{
+    union {
+        uint64_t ll[2];
+        uint8_t b[16];
+    } ivec;
+    int i;
+
+    for(i = 0; i < nb_sectors; i++) {
+        ivec.ll[0] = cpu_to_le64(sector_num);
+        ivec.ll[1] = 0;
+        AES_cbc_encrypt(in_buf, out_buf, 512, key, 
+                        ivec.b, enc);
+        sector_num++;
+        in_buf += 512;
+        out_buf += 512;
+    }
+}
+
+static int copy_sectors(BlockDriverState *bs, uint64_t start_sect,
+                        uint64_t cluster_offset, int n_start, int n_end)
+{
+    BDRVQcowState *s = bs->opaque;
+    int n, ret;
+
+    n = n_end - n_start;
+    if (n <= 0)
+        return 0;
+    ret = qcow_read(bs, start_sect + n_start, s->cluster_data, n);
+    if (ret < 0)
+        return ret;
+    if (s->crypt_method) {
+        encrypt_sectors(s, start_sect + n_start, 
+                        s->cluster_data, 
+                        s->cluster_data, n, 1,
+                        &s->aes_encrypt_key);
+    }
+    ret = bdrv_write(s->hd, (cluster_offset >> 9) + n_start, 
+                     s->cluster_data, n);
+    if (ret < 0)
+        return ret;
+    return 0;
+}
+
+static void l2_cache_reset(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+
+    memset(s->l2_cache, 0, s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
+    memset(s->l2_cache_offsets, 0, L2_CACHE_SIZE * sizeof(uint64_t));
+    memset(s->l2_cache_counts, 0, L2_CACHE_SIZE * sizeof(uint32_t));
+}
+
+static inline int l2_cache_new_entry(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    uint32_t min_count;
+    int min_index, i;
+
+    /* find a new entry in the least used one */
+    min_index = 0;
+    min_count = 0xffffffff;
+    for(i = 0; i < L2_CACHE_SIZE; i++) {
+        if (s->l2_cache_counts[i] < min_count) {
+            min_count = s->l2_cache_counts[i];
+            min_index = i;
+        }
+    }
+    return min_index;
+}
+
+static int64_t align_offset(int64_t offset, int n)
+{
+    offset = (offset + n - 1) & ~(n - 1);
+    return offset;
+}
+
+static int grow_l1_table(BlockDriverState *bs, int min_size)
+{
+    BDRVQcowState *s = bs->opaque;
+    int new_l1_size, new_l1_size2, ret, i;
+    uint64_t *new_l1_table;
+    uint64_t new_l1_table_offset;
+    uint64_t data64;
+    uint32_t data32;
+
+    new_l1_size = s->l1_size;
+    if (min_size <= new_l1_size)
+        return 0;
+    while (min_size > new_l1_size) {
+        new_l1_size = (new_l1_size * 3 + 1) / 2;
+    }
+#ifdef DEBUG_ALLOC2
+    printf("grow l1_table from %d to %d\n", s->l1_size, new_l1_size);
+#endif
+
+    new_l1_size2 = sizeof(uint64_t) * new_l1_size;
+    new_l1_table = qemu_mallocz(new_l1_size2);
+    if (!new_l1_table)
+        return -ENOMEM;
+    memcpy(new_l1_table, s->l1_table, s->l1_size * sizeof(uint64_t));
+
+    /* write new table (align to cluster) */
+    new_l1_table_offset = alloc_clusters(bs, new_l1_size2);
+    
+    for(i = 0; i < s->l1_size; i++)
+        new_l1_table[i] = cpu_to_be64(new_l1_table[i]);
+    ret = bdrv_pwrite(s->hd, new_l1_table_offset, new_l1_table, new_l1_size2);
+    if (ret != new_l1_size2)
+        goto fail;
+    for(i = 0; i < s->l1_size; i++)
+        new_l1_table[i] = be64_to_cpu(new_l1_table[i]);
+    
+    /* set new table */
+    data64 = cpu_to_be64(new_l1_table_offset);
+    if (bdrv_pwrite(s->hd, offsetof(QCowHeader, l1_table_offset),
+                    &data64, sizeof(data64)) != sizeof(data64))
+        goto fail;
+    data32 = cpu_to_be32(new_l1_size);
+    if (bdrv_pwrite(s->hd, offsetof(QCowHeader, l1_size),
+                    &data32, sizeof(data32)) != sizeof(data32))
+        goto fail;
+    qemu_free(s->l1_table);
+    free_clusters(bs, s->l1_table_offset, s->l1_size * sizeof(uint64_t));
+    s->l1_table_offset = new_l1_table_offset;
+    s->l1_table = new_l1_table;
+    s->l1_size = new_l1_size;
+    return 0;
+ fail:
+    qemu_free(s->l1_table);
+    return -EIO;
+}
+
+/* 'allocate' is:
+ *
+ * 0 not to allocate.
+ *
+ * 1 to allocate a normal cluster (for sector indexes 'n_start' to
+ * 'n_end')
+ *
+ * 2 to allocate a compressed cluster of size
+ * 'compressed_size'. 'compressed_size' must be > 0 and <
+ * cluster_size 
+ *
+ * return 0 if not allocated.
+ */
+static uint64_t get_cluster_offset(BlockDriverState *bs,
+                                   uint64_t offset, int allocate,
+                                   int compressed_size,
+                                   int n_start, int n_end)
+{
+    BDRVQcowState *s = bs->opaque;
+    int min_index, i, j, l1_index, l2_index, ret;
+    uint64_t l2_offset, *l2_table, cluster_offset, tmp, old_l2_offset;
+    
+    l1_index = offset >> (s->l2_bits + s->cluster_bits);
+    if (l1_index >= s->l1_size) {
+        /* outside l1 table is allowed: we grow the table if needed */
+        if (!allocate)
+            return 0;
+        if (grow_l1_table(bs, l1_index + 1) < 0)
+            return 0;
+    }
+    l2_offset = s->l1_table[l1_index];
+    if (!l2_offset) {
+        if (!allocate)
+            return 0;
+    l2_allocate:
+        old_l2_offset = l2_offset;
+        /* allocate a new l2 entry */
+        l2_offset = alloc_clusters(bs, s->l2_size * sizeof(uint64_t));
+        /* update the L1 entry */
+        s->l1_table[l1_index] = l2_offset | QCOW_OFLAG_COPIED;
+        tmp = cpu_to_be64(l2_offset | QCOW_OFLAG_COPIED);
+        if (bdrv_pwrite(s->hd, s->l1_table_offset + l1_index * sizeof(tmp), 
+                        &tmp, sizeof(tmp)) != sizeof(tmp))
+            return 0;
+        min_index = l2_cache_new_entry(bs);
+        l2_table = s->l2_cache + (min_index << s->l2_bits);
+
+        if (old_l2_offset == 0) {
+            memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
+        } else {
+            if (bdrv_pread(s->hd, old_l2_offset, 
+                           l2_table, s->l2_size * sizeof(uint64_t)) !=
+                s->l2_size * sizeof(uint64_t))
+                return 0;
+        }
+        if (bdrv_pwrite(s->hd, l2_offset, 
+                        l2_table, s->l2_size * sizeof(uint64_t)) !=
+            s->l2_size * sizeof(uint64_t))
+            return 0;
+    } else {
+        if (!(l2_offset & QCOW_OFLAG_COPIED)) {
+            if (allocate) {
+                free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t));
+                goto l2_allocate;
+            }
+        } else {
+            l2_offset &= ~QCOW_OFLAG_COPIED;
+        }
+        for(i = 0; i < L2_CACHE_SIZE; i++) {
+            if (l2_offset == s->l2_cache_offsets[i]) {
+                /* increment the hit count */
+                if (++s->l2_cache_counts[i] == 0xffffffff) {
+                    for(j = 0; j < L2_CACHE_SIZE; j++) {
+                        s->l2_cache_counts[j] >>= 1;
+                    }
+                }
+                l2_table = s->l2_cache + (i << s->l2_bits);
+                goto found;
+            }
+        }
+        /* not found: load a new entry in the least used one */
+        min_index = l2_cache_new_entry(bs);
+        l2_table = s->l2_cache + (min_index << s->l2_bits);
+        if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * 
sizeof(uint64_t)) != 
+            s->l2_size * sizeof(uint64_t))
+            return 0;
+    }
+    s->l2_cache_offsets[min_index] = l2_offset;
+    s->l2_cache_counts[min_index] = 1;
+ found:
+    l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);
+    cluster_offset = be64_to_cpu(l2_table[l2_index]);
+    if (!cluster_offset) {
+        if (!allocate)
+            return cluster_offset;
+    } else if (!(cluster_offset & QCOW_OFLAG_COPIED)) {
+        if (!allocate)
+            return cluster_offset;
+        /* free the cluster */
+        if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
+            int nb_csectors;
+            nb_csectors = ((cluster_offset >> s->csize_shift) & 
+                           s->csize_mask) + 1;
+            free_clusters(bs, (cluster_offset & s->cluster_offset_mask) & ~511,
+                          nb_csectors * 512);
+        } else {
+            free_clusters(bs, cluster_offset, s->cluster_size);
+        }
+    } else {
+        cluster_offset &= ~QCOW_OFLAG_COPIED;
+        return cluster_offset;
+    }
+    if (allocate == 1) {
+        /* allocate a new cluster */
+        cluster_offset = alloc_clusters(bs, s->cluster_size);
+
+        /* we must initialize the cluster content which won't be
+           written */
+        if ((n_end - n_start) < s->cluster_sectors) {
+            uint64_t start_sect;
+            
+            start_sect = (offset & ~(s->cluster_size - 1)) >> 9;
+            ret = copy_sectors(bs, start_sect,
+                               cluster_offset, 0, n_start);
+            if (ret < 0)
+                return 0;
+            ret = copy_sectors(bs, start_sect,
+                               cluster_offset, n_end, s->cluster_sectors);
+            if (ret < 0)
+                return 0;
+        }
+        tmp = cpu_to_be64(cluster_offset | QCOW_OFLAG_COPIED);
+    } else {
+        int nb_csectors;
+        cluster_offset = alloc_bytes(bs, compressed_size);
+        nb_csectors = ((cluster_offset + compressed_size - 1) >> 9) - 
+            (cluster_offset >> 9);
+        cluster_offset |= QCOW_OFLAG_COMPRESSED | 
+            ((uint64_t)nb_csectors << s->csize_shift);
+        /* compressed clusters never have the copied flag */
+        tmp = cpu_to_be64(cluster_offset);
+    }
+    /* update L2 table */
+    l2_table[l2_index] = tmp;
+    if (bdrv_pwrite(s->hd, 
+                    l2_offset + l2_index * sizeof(tmp), &tmp, sizeof(tmp)) != 
sizeof(tmp))
+        return 0;
+    return cluster_offset;
+}
+
+static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num, 
+                             int nb_sectors, int *pnum)
+{
+    BDRVQcowState *s = bs->opaque;
+    int index_in_cluster, n;
+    uint64_t cluster_offset;
+
+    cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0);
+    index_in_cluster = sector_num & (s->cluster_sectors - 1);
+    n = s->cluster_sectors - index_in_cluster;
+    if (n > nb_sectors)
+        n = nb_sectors;
+    *pnum = n;
+    return (cluster_offset != 0);
+}
+
+static int decompress_buffer(uint8_t *out_buf, int out_buf_size,
+                             const uint8_t *buf, int buf_size)
+{
+    z_stream strm1, *strm = &strm1;
+    int ret, out_len;
+
+    memset(strm, 0, sizeof(*strm));
+
+    strm->next_in = (uint8_t *)buf;
+    strm->avail_in = buf_size;
+    strm->next_out = out_buf;
+    strm->avail_out = out_buf_size;
+
+    ret = inflateInit2(strm, -12);
+    if (ret != Z_OK)
+        return -1;
+    ret = inflate(strm, Z_FINISH);
+    out_len = strm->next_out - out_buf;
+    if ((ret != Z_STREAM_END && ret != Z_BUF_ERROR) ||
+        out_len != out_buf_size) {
+        inflateEnd(strm);
+        return -1;
+    }
+    inflateEnd(strm);
+    return 0;
+}
+                              
+static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset)
+{
+    int ret, csize, nb_csectors, sector_offset;
+    uint64_t coffset;
+
+    coffset = cluster_offset & s->cluster_offset_mask;
+    if (s->cluster_cache_offset != coffset) {
+        nb_csectors = ((cluster_offset >> s->csize_shift) & s->csize_mask) + 1;
+        sector_offset = coffset & 511;
+        csize = nb_csectors * 512 - sector_offset;
+        ret = bdrv_read(s->hd, coffset >> 9, s->cluster_data, nb_csectors);
+        if (ret < 0) {
+            return -1;
+        }
+        if (decompress_buffer(s->cluster_cache, s->cluster_size,
+                              s->cluster_data + sector_offset, csize) < 0) {
+            return -1;
+        }
+        s->cluster_cache_offset = coffset;
+    }
+    return 0;
+}
+
+/* handle reading after the end of the backing file */
+static int backing_read1(BlockDriverState *bs, 
+                         int64_t sector_num, uint8_t *buf, int nb_sectors)
+{
+    int n1;
+    if ((sector_num + nb_sectors) <= bs->total_sectors)
+        return nb_sectors;
+    if (sector_num >= bs->total_sectors)
+        n1 = 0;
+    else
+        n1 = bs->total_sectors - sector_num;
+    memset(buf + n1 * 512, 0, 512 * (nb_sectors - n1));
+    return n1;
+}
+
+static int qcow_read(BlockDriverState *bs, int64_t sector_num, 
+                     uint8_t *buf, int nb_sectors)
+{
+    BDRVQcowState *s = bs->opaque;
+    int ret, index_in_cluster, n, n1;
+    uint64_t cluster_offset;
+    
+    while (nb_sectors > 0) {
+        cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0);
+        index_in_cluster = sector_num & (s->cluster_sectors - 1);
+        n = s->cluster_sectors - index_in_cluster;
+        if (n > nb_sectors)
+            n = nb_sectors;
+        if (!cluster_offset) {
+            if (bs->backing_hd) {
+                /* read from the base image */
+                n1 = backing_read1(bs->backing_hd, sector_num, buf, n);
+                if (n1 > 0) {
+                    ret = bdrv_read(bs->backing_hd, sector_num, buf, n1);
+                    if (ret < 0)
+                        return -1;
+                }
+            } else {
+                memset(buf, 0, 512 * n);
+            }
+        } else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
+            if (decompress_cluster(s, cluster_offset) < 0)
+                return -1;
+            memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n);
+        } else {
+            ret = bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, 
buf, n * 512);
+            if (ret != n * 512) 
+                return -1;
+            if (s->crypt_method) {
+                encrypt_sectors(s, sector_num, buf, buf, n, 0, 
+                                &s->aes_decrypt_key);
+            }
+        }
+        nb_sectors -= n;
+        sector_num += n;
+        buf += n * 512;
+    }
+    return 0;
+}
+
+static int qcow_write(BlockDriverState *bs, int64_t sector_num, 
+                     const uint8_t *buf, int nb_sectors)
+{
+    BDRVQcowState *s = bs->opaque;
+    int ret, index_in_cluster, n;
+    uint64_t cluster_offset;
+    
+    while (nb_sectors > 0) {
+        index_in_cluster = sector_num & (s->cluster_sectors - 1);
+        n = s->cluster_sectors - index_in_cluster;
+        if (n > nb_sectors)
+            n = nb_sectors;
+        cluster_offset = get_cluster_offset(bs, sector_num << 9, 1, 0, 
+                                            index_in_cluster, 
+                                            index_in_cluster + n);
+        if (!cluster_offset)
+            return -1;
+        if (s->crypt_method) {
+            encrypt_sectors(s, sector_num, s->cluster_data, buf, n, 1,
+                            &s->aes_encrypt_key);
+            ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, 
+                              s->cluster_data, n * 512);
+        } else {
+            ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, 
buf, n * 512);
+        }
+        if (ret != n * 512) 
+            return -1;
+        nb_sectors -= n;
+        sector_num += n;
+        buf += n * 512;
+    }
+    s->cluster_cache_offset = -1; /* disable compressed cache */
+    return 0;
+}
+
+typedef struct QCowAIOCB {
+    BlockDriverAIOCB common;
+    int64_t sector_num;
+    uint8_t *buf;
+    int nb_sectors;
+    int n;
+    uint64_t cluster_offset;
+    uint8_t *cluster_data; 
+    BlockDriverAIOCB *hd_aiocb;
+} QCowAIOCB;
+
+static void qcow_aio_read_cb(void *opaque, int ret)
+{
+    QCowAIOCB *acb = opaque;
+    BlockDriverState *bs = acb->common.bs;
+    BDRVQcowState *s = bs->opaque;
+    int index_in_cluster, n1;
+
+    acb->hd_aiocb = NULL;
+    if (ret < 0) {
+    fail:
+        acb->common.cb(acb->common.opaque, ret);
+        qemu_aio_release(acb);
+        return;
+    }
+
+ redo:
+    /* post process the read buffer */
+    if (!acb->cluster_offset) {
+        /* nothing to do */
+    } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
+        /* nothing to do */
+    } else {
+        if (s->crypt_method) {
+            encrypt_sectors(s, acb->sector_num, acb->buf, acb->buf, 
+                            acb->n, 0, 
+                            &s->aes_decrypt_key);
+        }
+    }
+
+    acb->nb_sectors -= acb->n;
+    acb->sector_num += acb->n;
+    acb->buf += acb->n * 512;
+
+    if (acb->nb_sectors == 0) {
+        /* request completed */
+        acb->common.cb(acb->common.opaque, 0);
+        qemu_aio_release(acb);
+        return;
+    }
+    
+    /* prepare next AIO request */
+    acb->cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, 
+                                             0, 0, 0, 0);
+    index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
+    acb->n = s->cluster_sectors - index_in_cluster;
+    if (acb->n > acb->nb_sectors)
+        acb->n = acb->nb_sectors;
+
+    if (!acb->cluster_offset) {
+        if (bs->backing_hd) {
+            /* read from the base image */
+            n1 = backing_read1(bs->backing_hd, acb->sector_num, 
+                               acb->buf, acb->n);
+            if (n1 > 0) {
+                acb->hd_aiocb = bdrv_aio_read(bs->backing_hd, acb->sector_num, 
+                                    acb->buf, acb->n, qcow_aio_read_cb, acb);
+                if (acb->hd_aiocb == NULL)
+                    goto fail;
+            } else {
+                goto redo;
+            }
+        } else {
+            /* Note: in this case, no need to wait */
+            memset(acb->buf, 0, 512 * acb->n);
+            goto redo;
+        }
+    } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
+        /* add AIO support for compressed blocks ? */
+        if (decompress_cluster(s, acb->cluster_offset) < 0)
+            goto fail;
+        memcpy(acb->buf, 
+               s->cluster_cache + index_in_cluster * 512, 512 * acb->n);
+        goto redo;
+    } else {
+        if ((acb->cluster_offset & 511) != 0) {
+            ret = -EIO;
+            goto fail;
+        }
+        acb->hd_aiocb = bdrv_aio_read(s->hd,
+                            (acb->cluster_offset >> 9) + index_in_cluster, 
+                            acb->buf, acb->n, qcow_aio_read_cb, acb);
+        if (acb->hd_aiocb == NULL)
+            goto fail;
+    }
+}
+
+static QCowAIOCB *qcow_aio_setup(BlockDriverState *bs,
+        int64_t sector_num, uint8_t *buf, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    QCowAIOCB *acb;
+
+    acb = qemu_aio_get(bs, cb, opaque);
+    if (!acb)
+        return NULL;
+    acb->hd_aiocb = NULL;
+    acb->sector_num = sector_num;
+    acb->buf = buf;
+    acb->nb_sectors = nb_sectors;
+    acb->n = 0;
+    acb->cluster_offset = 0;
+    return acb;
+}
+
+static BlockDriverAIOCB *qcow_aio_read(BlockDriverState *bs,
+        int64_t sector_num, uint8_t *buf, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    QCowAIOCB *acb;
+
+    acb = qcow_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
+    if (!acb)
+        return NULL;
+
+    qcow_aio_read_cb(acb, 0);
+    return &acb->common;
+}
+
+static void qcow_aio_write_cb(void *opaque, int ret)
+{
+    QCowAIOCB *acb = opaque;
+    BlockDriverState *bs = acb->common.bs;
+    BDRVQcowState *s = bs->opaque;
+    int index_in_cluster;
+    uint64_t cluster_offset;
+    const uint8_t *src_buf;
+
+    acb->hd_aiocb = NULL;
+
+    if (ret < 0) {
+    fail:
+        acb->common.cb(acb->common.opaque, ret);
+        qemu_aio_release(acb);
+        return;
+    }
+
+    acb->nb_sectors -= acb->n;
+    acb->sector_num += acb->n;
+    acb->buf += acb->n * 512;
+
+    if (acb->nb_sectors == 0) {
+        /* request completed */
+        acb->common.cb(acb->common.opaque, 0);
+        qemu_aio_release(acb);
+        return;
+    }
+    
+    index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
+    acb->n = s->cluster_sectors - index_in_cluster;
+    if (acb->n > acb->nb_sectors)
+        acb->n = acb->nb_sectors;
+    cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, 1, 0, 
+                                        index_in_cluster, 
+                                        index_in_cluster + acb->n);
+    if (!cluster_offset || (cluster_offset & 511) != 0) {
+        ret = -EIO;
+        goto fail;
+    }
+    if (s->crypt_method) {
+        if (!acb->cluster_data) {
+            acb->cluster_data = qemu_mallocz(s->cluster_size);
+            if (!acb->cluster_data) {
+                ret = -ENOMEM;
+                goto fail;
+            }
+        }
+        encrypt_sectors(s, acb->sector_num, acb->cluster_data, acb->buf, 
+                        acb->n, 1, &s->aes_encrypt_key);
+        src_buf = acb->cluster_data;
+    } else {
+        src_buf = acb->buf;
+    }
+    acb->hd_aiocb = bdrv_aio_write(s->hd,
+                                   (cluster_offset >> 9) + index_in_cluster, 
+                                   src_buf, acb->n, 
+                                   qcow_aio_write_cb, acb);
+    if (acb->hd_aiocb == NULL)
+        goto fail;
+}
+
+static BlockDriverAIOCB *qcow_aio_write(BlockDriverState *bs,
+        int64_t sector_num, const uint8_t *buf, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BDRVQcowState *s = bs->opaque;
+    QCowAIOCB *acb;
+    
+    s->cluster_cache_offset = -1; /* disable compressed cache */
+
+    acb = qcow_aio_setup(bs, sector_num, (uint8_t*)buf, nb_sectors, cb, 
opaque);
+    if (!acb)
+        return NULL;
+    
+    qcow_aio_write_cb(acb, 0);
+    return &acb->common;
+}
+
+static void qcow_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+    QCowAIOCB *acb = (QCowAIOCB *)blockacb;
+    if (acb->hd_aiocb)
+        bdrv_aio_cancel(acb->hd_aiocb);
+    qemu_aio_release(acb);
+}
+
+static void qcow_close(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    qemu_free(s->l1_table);
+    qemu_free(s->l2_cache);
+    qemu_free(s->cluster_cache);
+    qemu_free(s->cluster_data);
+    refcount_close(bs);
+    bdrv_delete(s->hd);
+}
+
+/* XXX: use std qcow open function ? */
+typedef struct QCowCreateState {
+    int cluster_size;
+    int cluster_bits;
+    uint16_t *refcount_block;
+    uint64_t *refcount_table;
+    int64_t l1_table_offset;
+    int64_t refcount_table_offset;
+    int64_t refcount_block_offset;
+} QCowCreateState;
+
+static void create_refcount_update(QCowCreateState *s,
+                                   int64_t offset, int64_t size)
+{
+    int refcount;
+    int64_t start, last, cluster_offset;
+    uint16_t *p;
+
+    start = offset & ~(s->cluster_size - 1);
+    last = (offset + size - 1)  & ~(s->cluster_size - 1);
+    for(cluster_offset = start; cluster_offset <= last; 
+        cluster_offset += s->cluster_size) {
+        p = &s->refcount_block[cluster_offset >> s->cluster_bits];
+        refcount = be16_to_cpu(*p);
+        refcount++;
+        *p = cpu_to_be16(refcount);
+    }
+}
+
+static int qcow_create(const char *filename, int64_t total_size,
+                      const char *backing_file, int flags)
+{
+    int fd, header_size, backing_filename_len, l1_size, i, shift, l2_bits;
+    QCowHeader header;
+    uint64_t tmp, offset;
+    QCowCreateState s1, *s = &s1;
+    
+    memset(s, 0, sizeof(*s));
+
+    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
+    if (fd < 0)
+        return -1;
+    memset(&header, 0, sizeof(header));
+    header.magic = cpu_to_be32(QCOW_MAGIC);
+    header.version = cpu_to_be32(QCOW_VERSION);
+    header.size = cpu_to_be64(total_size * 512);
+    header_size = sizeof(header);
+    backing_filename_len = 0;
+    if (backing_file) {
+        header.backing_file_offset = cpu_to_be64(header_size);
+        backing_filename_len = strlen(backing_file);
+        header.backing_file_size = cpu_to_be32(backing_filename_len);
+        header_size += backing_filename_len;
+    }
+    s->cluster_bits = 12;  /* 4 KB clusters */
+    s->cluster_size = 1 << s->cluster_bits;
+    header.cluster_bits = cpu_to_be32(s->cluster_bits);
+    header_size = (header_size + 7) & ~7;
+    if (flags) {
+        header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES);
+    } else {
+        header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
+    }
+    l2_bits = s->cluster_bits - 3;
+    shift = s->cluster_bits + l2_bits;
+    l1_size = (((total_size * 512) + (1LL << shift) - 1) >> shift);
+    offset = align_offset(header_size, s->cluster_size);
+    s->l1_table_offset = offset;
+    header.l1_table_offset = cpu_to_be64(s->l1_table_offset);
+    header.l1_size = cpu_to_be32(l1_size);
+    offset += align_offset(l1_size * sizeof(uint64_t), s->cluster_size);
+
+    s->refcount_table = qemu_mallocz(s->cluster_size);
+    if (!s->refcount_table)
+        goto fail;
+    s->refcount_block = qemu_mallocz(s->cluster_size);
+    if (!s->refcount_block)
+        goto fail;
+    
+    s->refcount_table_offset = offset;
+    header.refcount_table_offset = cpu_to_be64(offset);
+    header.refcount_table_clusters = cpu_to_be32(1);
+    offset += s->cluster_size;
+
+    s->refcount_table[0] = cpu_to_be64(offset);
+    s->refcount_block_offset = offset;
+    offset += s->cluster_size;
+
+    /* update refcounts */
+    create_refcount_update(s, 0, header_size);
+    create_refcount_update(s, s->l1_table_offset, l1_size * sizeof(uint64_t));
+    create_refcount_update(s, s->refcount_table_offset, s->cluster_size);
+    create_refcount_update(s, s->refcount_block_offset, s->cluster_size);
+    
+    /* write all the data */
+    write(fd, &header, sizeof(header));
+    if (backing_file) {
+        write(fd, backing_file, backing_filename_len);
+    }
+    lseek(fd, s->l1_table_offset, SEEK_SET);
+    tmp = 0;
+    for(i = 0;i < l1_size; i++) {
+        write(fd, &tmp, sizeof(tmp));
+    }
+    lseek(fd, s->refcount_table_offset, SEEK_SET);
+    write(fd, s->refcount_table, s->cluster_size);
+    
+    lseek(fd, s->refcount_block_offset, SEEK_SET);
+    write(fd, s->refcount_block, s->cluster_size);
+
+    qemu_free(s->refcount_table);
+    qemu_free(s->refcount_block);
+    close(fd);
+    return 0;
+ fail:
+    qemu_free(s->refcount_table);
+    qemu_free(s->refcount_block);
+    close(fd);
+    return -ENOMEM;
+}
+
+static int qcow_make_empty(BlockDriverState *bs)
+{
+#if 0
+    /* XXX: not correct */
+    BDRVQcowState *s = bs->opaque;
+    uint32_t l1_length = s->l1_size * sizeof(uint64_t);
+    int ret;
+
+    memset(s->l1_table, 0, l1_length);
+    if (bdrv_pwrite(s->hd, s->l1_table_offset, s->l1_table, l1_length) < 0)
+       return -1;
+    ret = bdrv_truncate(s->hd, s->l1_table_offset + l1_length);
+    if (ret < 0)
+        return ret;
+    
+    l2_cache_reset(bs);
+#endif
+    return 0;
+}
+
+/* XXX: put compressed sectors first, then all the cluster aligned
+   tables to avoid losing bytes in alignment */
+static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, 
+                                 const uint8_t *buf, int nb_sectors)
+{
+    BDRVQcowState *s = bs->opaque;
+    z_stream strm;
+    int ret, out_len;
+    uint8_t *out_buf;
+    uint64_t cluster_offset;
+
+    if (nb_sectors == 0) {
+        /* align end of file to a sector boundary to ease reading with
+           sector based I/Os */
+        cluster_offset = bdrv_getlength(s->hd);
+        cluster_offset = (cluster_offset + 511) & ~511;
+        bdrv_truncate(s->hd, cluster_offset);
+        return 0;
+    }
+
+    if (nb_sectors != s->cluster_sectors)
+        return -EINVAL;
+
+    out_buf = qemu_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);
+    if (!out_buf)
+        return -ENOMEM;
+
+    /* best compression, small window, no zlib header */
+    memset(&strm, 0, sizeof(strm));
+    ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION,
+                       Z_DEFLATED, -12, 
+                       9, Z_DEFAULT_STRATEGY);
+    if (ret != 0) {
+        qemu_free(out_buf);
+        return -1;
+    }
+
+    strm.avail_in = s->cluster_size;
+    strm.next_in = (uint8_t *)buf;
+    strm.avail_out = s->cluster_size;
+    strm.next_out = out_buf;
+
+    ret = deflate(&strm, Z_FINISH);
+    if (ret != Z_STREAM_END && ret != Z_OK) {
+        qemu_free(out_buf);
+        deflateEnd(&strm);
+        return -1;
+    }
+    out_len = strm.next_out - out_buf;
+
+    deflateEnd(&strm);
+
+    if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
+        /* could not compress: write normal cluster */
+        qcow_write(bs, sector_num, buf, s->cluster_sectors);
+    } else {
+        cluster_offset = get_cluster_offset(bs, sector_num << 9, 2, 
+                                            out_len, 0, 0);
+        cluster_offset &= s->cluster_offset_mask;
+        if (bdrv_pwrite(s->hd, cluster_offset, out_buf, out_len) != out_len) {
+            qemu_free(out_buf);
+            return -1;
+        }
+    }
+    
+    qemu_free(out_buf);
+    return 0;
+}
+
+static void qcow_flush(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    bdrv_flush(s->hd);
+}
+
+static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
+{
+    BDRVQcowState *s = bs->opaque;
+    bdi->cluster_size = s->cluster_size;
+    bdi->vm_state_offset = (int64_t)s->l1_vm_state_index << 
+        (s->cluster_bits + s->l2_bits);
+    return 0;
+}
+
+/*********************************************************/
+/* snapshot support */
+
+/* update the refcounts of snapshots and the copied flag */
+static int update_snapshot_refcount(BlockDriverState *bs, 
+                                    int64_t l1_table_offset,
+                                    int l1_size,
+                                    int addend)
+{
+    BDRVQcowState *s = bs->opaque;
+    uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2, l1_allocated;
+    int64_t old_offset, old_l2_offset;
+    int l2_size, i, j, l1_modified, l2_modified, nb_csectors, refcount;
+    
+    l2_cache_reset(bs);
+
+    l2_table = NULL;
+    l1_table = NULL;
+    l1_size2 = l1_size * sizeof(uint64_t);
+    l1_allocated = 0;
+    if (l1_table_offset != s->l1_table_offset) {
+        l1_table = qemu_malloc(l1_size2);
+        if (!l1_table)
+            goto fail;
+        l1_allocated = 1;
+        if (bdrv_pread(s->hd, l1_table_offset, 
+                       l1_table, l1_size2) != l1_size2)
+            goto fail;
+        for(i = 0;i < l1_size; i++)
+            be64_to_cpus(&l1_table[i]);
+    } else {
+        assert(l1_size == s->l1_size);
+        l1_table = s->l1_table;
+        l1_allocated = 0;
+    }
+    
+    l2_size = s->l2_size * sizeof(uint64_t);
+    l2_table = qemu_malloc(l2_size);
+    if (!l2_table)
+        goto fail;
+    l1_modified = 0;
+    for(i = 0; i < l1_size; i++) {
+        l2_offset = l1_table[i];
+        if (l2_offset) {
+            old_l2_offset = l2_offset;
+            l2_offset &= ~QCOW_OFLAG_COPIED;
+            l2_modified = 0;
+            if (bdrv_pread(s->hd, l2_offset, l2_table, l2_size) != l2_size)
+                goto fail;
+            for(j = 0; j < s->l2_size; j++) {
+                offset = be64_to_cpu(l2_table[j]);
+                if (offset != 0) {
+                    old_offset = offset;
+                    offset &= ~QCOW_OFLAG_COPIED;
+                    if (offset & QCOW_OFLAG_COMPRESSED) {
+                        nb_csectors = ((offset >> s->csize_shift) & 
+                                       s->csize_mask) + 1;
+                        if (addend != 0)
+                            update_refcount(bs, (offset & 
s->cluster_offset_mask) & ~511,
+                                            nb_csectors * 512, addend);
+                        /* compressed clusters are never modified */
+                        refcount = 2; 
+                    } else {
+                        if (addend != 0) {
+                            refcount = update_cluster_refcount(bs, offset >> 
s->cluster_bits, addend);
+                        } else {
+                            refcount = get_refcount(bs, offset >> 
s->cluster_bits);
+                        }
+                    }
+
+                    if (refcount == 1) {
+                        offset |= QCOW_OFLAG_COPIED;
+                    }
+                    if (offset != old_offset) {
+                        l2_table[j] = cpu_to_be64(offset);
+                        l2_modified = 1;
+                    }
+                }
+            }
+            if (l2_modified) {
+                if (bdrv_pwrite(s->hd, 
+                                l2_offset, l2_table, l2_size) != l2_size)
+                    goto fail;
+            }
+
+            if (addend != 0) {
+                refcount = update_cluster_refcount(bs, l2_offset >> 
s->cluster_bits, addend);
+            } else {
+                refcount = get_refcount(bs, l2_offset >> s->cluster_bits);
+            }
+            if (refcount == 1) {
+                l2_offset |= QCOW_OFLAG_COPIED;
+            }
+            if (l2_offset != old_l2_offset) {
+                l1_table[i] = l2_offset;
+                l1_modified = 1;
+            }
+        }
+    }
+    if (l1_modified) {
+        for(i = 0; i < l1_size; i++)
+            cpu_to_be64s(&l1_table[i]);
+        if (bdrv_pwrite(s->hd, l1_table_offset, l1_table, 
+                        l1_size2) != l1_size2)
+            goto fail;
+        for(i = 0; i < l1_size; i++)
+            be64_to_cpus(&l1_table[i]);
+    }
+    if (l1_allocated)
+        qemu_free(l1_table);
+    qemu_free(l2_table);
+    return 0;
+ fail:
+    if (l1_allocated)
+        qemu_free(l1_table);
+    qemu_free(l2_table);
+    return -EIO;
+}
+
+static void qcow_free_snapshots(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    int i;
+
+    for(i = 0; i < s->nb_snapshots; i++) {
+        qemu_free(s->snapshots[i].name);
+        qemu_free(s->snapshots[i].id_str);
+    }
+    qemu_free(s->snapshots);
+    s->snapshots = NULL;
+    s->nb_snapshots = 0;
+}
+
+static int qcow_read_snapshots(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    QCowSnapshotHeader h;
+    QCowSnapshot *sn;
+    int i, id_str_size, name_size;
+    int64_t offset;
+    uint32_t extra_data_size;
+
+    offset = s->snapshots_offset;
+    s->snapshots = qemu_mallocz(s->nb_snapshots * sizeof(QCowSnapshot));
+    if (!s->snapshots)
+        goto fail;
+    for(i = 0; i < s->nb_snapshots; i++) {
+        offset = align_offset(offset, 8);
+        if (bdrv_pread(s->hd, offset, &h, sizeof(h)) != sizeof(h))
+            goto fail;
+        offset += sizeof(h);
+        sn = s->snapshots + i;
+        sn->l1_table_offset = be64_to_cpu(h.l1_table_offset);
+        sn->l1_size = be32_to_cpu(h.l1_size);
+        sn->vm_state_size = be32_to_cpu(h.vm_state_size);
+        sn->date_sec = be32_to_cpu(h.date_sec);
+        sn->date_nsec = be32_to_cpu(h.date_nsec);
+        sn->vm_clock_nsec = be64_to_cpu(h.vm_clock_nsec);
+        extra_data_size = be32_to_cpu(h.extra_data_size);
+
+        id_str_size = be16_to_cpu(h.id_str_size);
+        name_size = be16_to_cpu(h.name_size);
+
+        offset += extra_data_size;
+
+        sn->id_str = qemu_malloc(id_str_size + 1);
+        if (!sn->id_str)
+            goto fail;
+        if (bdrv_pread(s->hd, offset, sn->id_str, id_str_size) != id_str_size)
+            goto fail;
+        offset += id_str_size;
+        sn->id_str[id_str_size] = '\0';
+
+        sn->name = qemu_malloc(name_size + 1);
+        if (!sn->name)
+            goto fail;
+        if (bdrv_pread(s->hd, offset, sn->name, name_size) != name_size)
+            goto fail;
+        offset += name_size;
+        sn->name[name_size] = '\0';
+    }
+    s->snapshots_size = offset - s->snapshots_offset;
+    return 0;
+ fail:
+    qcow_free_snapshots(bs);
+    return -1;
+}
+
+/* add at the end of the file a new list of snapshots */
+static int qcow_write_snapshots(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    QCowSnapshot *sn;
+    QCowSnapshotHeader h;
+    int i, name_size, id_str_size, snapshots_size;
+    uint64_t data64;
+    uint32_t data32;
+    int64_t offset, snapshots_offset;
+
+    /* compute the size of the snapshots */
+    offset = 0;
+    for(i = 0; i < s->nb_snapshots; i++) {
+        sn = s->snapshots + i;
+        offset = align_offset(offset, 8);
+        offset += sizeof(h);
+        offset += strlen(sn->id_str);
+        offset += strlen(sn->name);
+    }
+    snapshots_size = offset;
+
+    snapshots_offset = alloc_clusters(bs, snapshots_size);
+    offset = snapshots_offset;
+    
+    for(i = 0; i < s->nb_snapshots; i++) {
+        sn = s->snapshots + i;
+        memset(&h, 0, sizeof(h));
+        h.l1_table_offset = cpu_to_be64(sn->l1_table_offset);
+        h.l1_size = cpu_to_be32(sn->l1_size);
+        h.vm_state_size = cpu_to_be32(sn->vm_state_size);
+        h.date_sec = cpu_to_be32(sn->date_sec);
+        h.date_nsec = cpu_to_be32(sn->date_nsec);
+        h.vm_clock_nsec = cpu_to_be64(sn->vm_clock_nsec);
+        
+        id_str_size = strlen(sn->id_str);
+        name_size = strlen(sn->name);
+        h.id_str_size = cpu_to_be16(id_str_size);
+        h.name_size = cpu_to_be16(name_size);
+        offset = align_offset(offset, 8);
+        if (bdrv_pwrite(s->hd, offset, &h, sizeof(h)) != sizeof(h))
+            goto fail;
+        offset += sizeof(h);
+        if (bdrv_pwrite(s->hd, offset, sn->id_str, id_str_size) != id_str_size)
+            goto fail;
+        offset += id_str_size;
+        if (bdrv_pwrite(s->hd, offset, sn->name, name_size) != name_size)
+            goto fail;
+        offset += name_size;
+    }
+
+    /* update the various header fields */
+    data64 = cpu_to_be64(snapshots_offset);
+    if (bdrv_pwrite(s->hd, offsetof(QCowHeader, snapshots_offset),
+                    &data64, sizeof(data64)) != sizeof(data64))
+        goto fail;
+    data32 = cpu_to_be32(s->nb_snapshots);
+    if (bdrv_pwrite(s->hd, offsetof(QCowHeader, nb_snapshots),
+                    &data32, sizeof(data32)) != sizeof(data32))
+        goto fail;
+
+    /* free the old snapshot table */
+    free_clusters(bs, s->snapshots_offset, s->snapshots_size);
+    s->snapshots_offset = snapshots_offset;
+    s->snapshots_size = snapshots_size;
+    return 0;
+ fail:
+    return -1;
+}
+
+static void find_new_snapshot_id(BlockDriverState *bs,
+                                 char *id_str, int id_str_size)
+{
+    BDRVQcowState *s = bs->opaque;
+    QCowSnapshot *sn;
+    int i, id, id_max = 0;
+
+    for(i = 0; i < s->nb_snapshots; i++) {
+        sn = s->snapshots + i;
+        id = strtoul(sn->id_str, NULL, 10);
+        if (id > id_max)
+            id_max = id;
+    }
+    snprintf(id_str, id_str_size, "%d", id_max + 1);
+}
+
+static int find_snapshot_by_id(BlockDriverState *bs, const char *id_str)
+{
+    BDRVQcowState *s = bs->opaque;
+    int i;
+
+    for(i = 0; i < s->nb_snapshots; i++) {
+        if (!strcmp(s->snapshots[i].id_str, id_str))
+            return i;
+    }
+    return -1;
+}
+
+static int find_snapshot_by_id_or_name(BlockDriverState *bs, const char *name)
+{
+    BDRVQcowState *s = bs->opaque;
+    int i, ret;
+    
+    ret = find_snapshot_by_id(bs, name);
+    if (ret >= 0)
+        return ret;
+    for(i = 0; i < s->nb_snapshots; i++) {
+        if (!strcmp(s->snapshots[i].name, name))
+            return i;
+    }
+    return -1;
+}
+
+/* if no id is provided, a new one is constructed */
+static int qcow_snapshot_create(BlockDriverState *bs, 
+                                QEMUSnapshotInfo *sn_info)
+{
+    BDRVQcowState *s = bs->opaque;
+    QCowSnapshot *snapshots1, sn1, *sn = &sn1;
+    int i, ret;
+    uint64_t *l1_table = NULL;
+    
+    memset(sn, 0, sizeof(*sn));
+
+    if (sn_info->id_str[0] == '\0') {
+        /* compute a new id */
+        find_new_snapshot_id(bs, sn_info->id_str, sizeof(sn_info->id_str));
+    }
+
+    /* check that the ID is unique */
+    if (find_snapshot_by_id(bs, sn_info->id_str) >= 0)
+        return -ENOENT;
+
+    sn->id_str = qemu_strdup(sn_info->id_str);
+    if (!sn->id_str)
+        goto fail;
+    sn->name = qemu_strdup(sn_info->name);
+    if (!sn->name)
+        goto fail;
+    sn->vm_state_size = sn_info->vm_state_size;
+    sn->date_sec = sn_info->date_sec;
+    sn->date_nsec = sn_info->date_nsec;
+    sn->vm_clock_nsec = sn_info->vm_clock_nsec;
+
+    ret = update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1);
+    if (ret < 0)
+        goto fail;
+
+    /* create the L1 table of the snapshot */
+    sn->l1_table_offset = alloc_clusters(bs, s->l1_size * sizeof(uint64_t));
+    sn->l1_size = s->l1_size;
+
+    l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
+    if (!l1_table)
+        goto fail;
+    for(i = 0; i < s->l1_size; i++) {
+        l1_table[i] = cpu_to_be64(s->l1_table[i]);
+    }
+    if (bdrv_pwrite(s->hd, sn->l1_table_offset,
+                    l1_table, s->l1_size * sizeof(uint64_t)) != 
+        (s->l1_size * sizeof(uint64_t)))
+        goto fail;
+    qemu_free(l1_table);
+    l1_table = NULL;
+
+    snapshots1 = qemu_malloc((s->nb_snapshots + 1) * sizeof(QCowSnapshot));
+    if (!snapshots1)
+        goto fail;
+    memcpy(snapshots1, s->snapshots, s->nb_snapshots * sizeof(QCowSnapshot));
+    s->snapshots = snapshots1;
+    s->snapshots[s->nb_snapshots++] = *sn;
+
+    if (qcow_write_snapshots(bs) < 0)
+        goto fail;
+#ifdef DEBUG_ALLOC
+    check_refcounts(bs);
+#endif
+    return 0;
+ fail:
+    qemu_free(sn->name);
+    qemu_free(l1_table);
+    return -1;
+}
+
+/* copy the snapshot 'snapshot_name' into the current disk image */
+static int qcow_snapshot_goto(BlockDriverState *bs, 
+                              const char *snapshot_id)
+{
+    BDRVQcowState *s = bs->opaque;
+    QCowSnapshot *sn;
+    int i, snapshot_index, l1_size2;
+
+    snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
+    if (snapshot_index < 0)
+        return -ENOENT;
+    sn = &s->snapshots[snapshot_index];
+
+    if (update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, -1) < 0)
+        goto fail;
+
+    if (grow_l1_table(bs, sn->l1_size) < 0)
+        goto fail;
+
+    s->l1_size = sn->l1_size;
+    l1_size2 = s->l1_size * sizeof(uint64_t);
+    /* copy the snapshot l1 table to the current l1 table */
+    if (bdrv_pread(s->hd, sn->l1_table_offset, 
+                   s->l1_table, l1_size2) != l1_size2)
+        goto fail;
+    if (bdrv_pwrite(s->hd, s->l1_table_offset,
+                    s->l1_table, l1_size2) != l1_size2)
+        goto fail;
+    for(i = 0;i < s->l1_size; i++) {
+        be64_to_cpus(&s->l1_table[i]);
+    }
+
+    if (update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1) < 0)
+        goto fail;
+
+#ifdef DEBUG_ALLOC
+    check_refcounts(bs);
+#endif
+    return 0;
+ fail:
+    return -EIO;
+}
+
+static int qcow_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
+{
+    BDRVQcowState *s = bs->opaque;
+    QCowSnapshot *sn;
+    int snapshot_index, ret;
+    
+    snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
+    if (snapshot_index < 0)
+        return -ENOENT;
+    sn = &s->snapshots[snapshot_index];
+
+    ret = update_snapshot_refcount(bs, sn->l1_table_offset, sn->l1_size, -1);
+    if (ret < 0)
+        return ret;
+    /* must update the copied flag on the current cluster offsets */
+    ret = update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 0);
+    if (ret < 0)
+        return ret;
+    free_clusters(bs, sn->l1_table_offset, sn->l1_size * sizeof(uint64_t));
+
+    qemu_free(sn->id_str);
+    qemu_free(sn->name);
+    memmove(sn, sn + 1, (s->nb_snapshots - snapshot_index - 1) * sizeof(*sn));
+    s->nb_snapshots--;
+    ret = qcow_write_snapshots(bs);
+    if (ret < 0) {
+        /* XXX: restore snapshot if error ? */
+        return ret;
+    }
+#ifdef DEBUG_ALLOC
+    check_refcounts(bs);
+#endif
+    return 0;
+}
+
+static int qcow_snapshot_list(BlockDriverState *bs, 
+                              QEMUSnapshotInfo **psn_tab)
+{
+    BDRVQcowState *s = bs->opaque;
+    QEMUSnapshotInfo *sn_tab, *sn_info;
+    QCowSnapshot *sn;
+    int i;
+
+    sn_tab = qemu_mallocz(s->nb_snapshots * sizeof(QEMUSnapshotInfo));
+    if (!sn_tab)
+        goto fail;
+    for(i = 0; i < s->nb_snapshots; i++) {
+        sn_info = sn_tab + i;
+        sn = s->snapshots + i;
+        pstrcpy(sn_info->id_str, sizeof(sn_info->id_str),
+                sn->id_str);
+        pstrcpy(sn_info->name, sizeof(sn_info->name),
+                sn->name);
+        sn_info->vm_state_size = sn->vm_state_size;
+        sn_info->date_sec = sn->date_sec;
+        sn_info->date_nsec = sn->date_nsec;
+        sn_info->vm_clock_nsec = sn->vm_clock_nsec;
+    }
+    *psn_tab = sn_tab;
+    return s->nb_snapshots;
+ fail:
+    qemu_free(sn_tab);
+    *psn_tab = NULL;
+    return -ENOMEM;
+}
+
+/*********************************************************/
+/* refcount handling */
+
+static int refcount_init(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    int ret, refcount_table_size2, i;
+    
+    s->refcount_block_cache = qemu_malloc(s->cluster_size);
+    if (!s->refcount_block_cache)
+        goto fail;
+    refcount_table_size2 = s->refcount_table_size * sizeof(uint64_t);
+    s->refcount_table = qemu_malloc(refcount_table_size2);
+    if (!s->refcount_table)
+        goto fail;
+    if (s->refcount_table_size > 0) {
+        ret = bdrv_pread(s->hd, s->refcount_table_offset,
+                         s->refcount_table, refcount_table_size2);
+        if (ret != refcount_table_size2)
+            goto fail;
+        for(i = 0; i < s->refcount_table_size; i++)
+            be64_to_cpus(&s->refcount_table[i]);
+    }
+    return 0;
+ fail:
+    return -ENOMEM;
+}
+
+static void refcount_close(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    qemu_free(s->refcount_block_cache);
+    qemu_free(s->refcount_table);
+}
+
+
+static int load_refcount_block(BlockDriverState *bs, 
+                               int64_t refcount_block_offset)
+{
+    BDRVQcowState *s = bs->opaque;
+    int ret;
+    ret = bdrv_pread(s->hd, refcount_block_offset, s->refcount_block_cache, 
+                     s->cluster_size);
+    if (ret != s->cluster_size)
+        return -EIO;
+    s->refcount_block_cache_offset = refcount_block_offset;
+    return 0;
+}
+
+static int get_refcount(BlockDriverState *bs, int64_t cluster_index)
+{
+    BDRVQcowState *s = bs->opaque;
+    int refcount_table_index, block_index;
+    int64_t refcount_block_offset;
+
+    refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
+    if (refcount_table_index >= s->refcount_table_size)
+        return 0;
+    refcount_block_offset = s->refcount_table[refcount_table_index];
+    if (!refcount_block_offset)
+        return 0;
+    if (refcount_block_offset != s->refcount_block_cache_offset) {
+        /* better than nothing: return allocated if read error */
+        if (load_refcount_block(bs, refcount_block_offset) < 0)
+            return 1;
+    }
+    block_index = cluster_index & 
+        ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
+    return be16_to_cpu(s->refcount_block_cache[block_index]);
+}
+
+/* return < 0 if error */
+static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size)
+{
+    BDRVQcowState *s = bs->opaque;
+    int i, nb_clusters;
+
+    nb_clusters = (size + s->cluster_size - 1) >> s->cluster_bits;
+    for(;;) {
+        if (get_refcount(bs, s->free_cluster_index) == 0) {
+            s->free_cluster_index++;
+            for(i = 1; i < nb_clusters; i++) {
+                if (get_refcount(bs, s->free_cluster_index) != 0)
+                    goto not_found;
+                s->free_cluster_index++;
+            }
+#ifdef DEBUG_ALLOC2
+            printf("alloc_clusters: size=%lld -> %lld\n",
+                   size, 
+                   (s->free_cluster_index - nb_clusters) << s->cluster_bits);
+#endif
+            return (s->free_cluster_index - nb_clusters) << s->cluster_bits;
+        } else {
+        not_found:
+            s->free_cluster_index++;
+        }
+    }
+}
+
+static int64_t alloc_clusters(BlockDriverState *bs, int64_t size)
+{
+    int64_t offset;
+
+    offset = alloc_clusters_noref(bs, size);
+    update_refcount(bs, offset, size, 1);
+    return offset;
+}
+
+/* only used to allocate compressed sectors. We try to allocate
+   contiguous sectors. size must be <= cluster_size */
+static int64_t alloc_bytes(BlockDriverState *bs, int size)
+{
+    BDRVQcowState *s = bs->opaque;
+    int64_t offset, cluster_offset;
+    int free_in_cluster;
+    
+    assert(size > 0 && size <= s->cluster_size);
+    if (s->free_byte_offset == 0) {
+        s->free_byte_offset = alloc_clusters(bs, s->cluster_size);
+    }
+ redo:
+    free_in_cluster = s->cluster_size - 
+        (s->free_byte_offset & (s->cluster_size - 1));
+    if (size <= free_in_cluster) {
+        /* enough space in current cluster */
+        offset = s->free_byte_offset;
+        s->free_byte_offset += size;
+        free_in_cluster -= size;
+        if (free_in_cluster == 0)
+            s->free_byte_offset = 0;
+        if ((offset & (s->cluster_size - 1)) != 0)
+            update_cluster_refcount(bs, offset >> s->cluster_bits, 1);
+    } else {
+        offset = alloc_clusters(bs, s->cluster_size);
+        cluster_offset = s->free_byte_offset & ~(s->cluster_size - 1);
+        if ((cluster_offset + s->cluster_size) == offset) {
+            /* we are lucky: contiguous data */
+            offset = s->free_byte_offset;
+            update_cluster_refcount(bs, offset >> s->cluster_bits, 1);
+            s->free_byte_offset += size;
+        } else {
+            s->free_byte_offset = offset;
+            goto redo;
+        }
+    }
+    return offset;
+}
+
+static void free_clusters(BlockDriverState *bs, 
+                          int64_t offset, int64_t size)
+{
+    update_refcount(bs, offset, size, -1);
+}
+
+static int grow_refcount_table(BlockDriverState *bs, int min_size)
+{
+    BDRVQcowState *s = bs->opaque;
+    int new_table_size, new_table_size2, refcount_table_clusters, i, ret;
+    uint64_t *new_table;
+    int64_t table_offset;
+    uint64_t data64;
+    uint32_t data32;
+
+    if (min_size <= s->refcount_table_size)
+        return 0;
+    /* compute new table size */
+    refcount_table_clusters = s->refcount_table_size >> (s->cluster_bits - 3);
+    for(;;) {
+        if (refcount_table_clusters == 0) {
+            refcount_table_clusters = 1;
+        } else {
+            refcount_table_clusters = (refcount_table_clusters * 3 + 1) / 2;
+        }
+        new_table_size = refcount_table_clusters << (s->cluster_bits - 3);
+        if (min_size <= new_table_size)
+            break;
+    }
+#ifdef DEBUG_ALLOC2
+    printf("grow_refcount_table from %d to %d\n",
+           s->refcount_table_size,
+           new_table_size);
+#endif
+    new_table_size2 = new_table_size * sizeof(uint64_t);
+    new_table = qemu_mallocz(new_table_size2);
+    if (!new_table)
+        return -ENOMEM;
+    memcpy(new_table, s->refcount_table, 
+           s->refcount_table_size * sizeof(uint64_t));
+    for(i = 0; i < s->refcount_table_size; i++)
+        cpu_to_be64s(&new_table[i]);
+    /* Note: we cannot update the refcount now to avoid recursion */
+    table_offset = alloc_clusters_noref(bs, new_table_size2);
+    ret = bdrv_pwrite(s->hd, table_offset, new_table, new_table_size2);
+    if (ret != new_table_size2) 
+        goto fail;
+    for(i = 0; i < s->refcount_table_size; i++)
+        be64_to_cpus(&new_table[i]);
+
+    data64 = cpu_to_be64(table_offset);
+    if (bdrv_pwrite(s->hd, offsetof(QCowHeader, refcount_table_offset),
+                    &data64, sizeof(data64)) != sizeof(data64))
+        goto fail;
+    data32 = cpu_to_be32(refcount_table_clusters);
+    if (bdrv_pwrite(s->hd, offsetof(QCowHeader, refcount_table_clusters),
+                    &data32, sizeof(data32)) != sizeof(data32))
+        goto fail;
+    qemu_free(s->refcount_table);
+    s->refcount_table = new_table;
+    s->refcount_table_size = new_table_size;
+
+    update_refcount(bs, table_offset, new_table_size2, 1);
+    return 0;
+ fail:
+    free_clusters(bs, table_offset, new_table_size2);
+    qemu_free(new_table);
+    return -EIO;
+}
+
+/* addend must be 1 or -1 */
+/* XXX: cache several refcount block clusters ? */
+static int update_cluster_refcount(BlockDriverState *bs, 
+                                   int64_t cluster_index,
+                                   int addend)
+{
+    BDRVQcowState *s = bs->opaque;
+    int64_t offset, refcount_block_offset;
+    int ret, refcount_table_index, block_index, refcount;
+    uint64_t data64;
+
+    refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
+    if (refcount_table_index >= s->refcount_table_size) {
+        if (addend < 0)
+            return -EINVAL;
+        ret = grow_refcount_table(bs, refcount_table_index + 1);
+        if (ret < 0)
+            return ret;
+    }
+    refcount_block_offset = s->refcount_table[refcount_table_index];
+    if (!refcount_block_offset) {
+        if (addend < 0)
+            return -EINVAL;
+        /* create a new refcount block */
+        /* Note: we cannot update the refcount now to avoid recursion */
+        offset = alloc_clusters_noref(bs, s->cluster_size);
+        memset(s->refcount_block_cache, 0, s->cluster_size);
+        ret = bdrv_pwrite(s->hd, offset, s->refcount_block_cache, 
s->cluster_size);
+        if (ret != s->cluster_size)
+            return -EINVAL;
+        s->refcount_table[refcount_table_index] = offset;
+        data64 = cpu_to_be64(offset);
+        ret = bdrv_pwrite(s->hd, s->refcount_table_offset + 
+                          refcount_table_index * sizeof(uint64_t), 
+                          &data64, sizeof(data64));
+        if (ret != sizeof(data64))
+            return -EINVAL;
+
+        refcount_block_offset = offset;
+        s->refcount_block_cache_offset = offset;
+        update_refcount(bs, offset, s->cluster_size, 1);
+    } else {
+        if (refcount_block_offset != s->refcount_block_cache_offset) {
+            if (load_refcount_block(bs, refcount_block_offset) < 0)
+                return -EIO;
+        }
+    }
+    /* we can update the count and save it */
+    block_index = cluster_index & 
+        ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
+    refcount = be16_to_cpu(s->refcount_block_cache[block_index]);
+    refcount += addend;
+    if (refcount < 0 || refcount > 0xffff)
+        return -EINVAL;
+    if (refcount == 0 && cluster_index < s->free_cluster_index) {
+        s->free_cluster_index = cluster_index;
+    }
+    s->refcount_block_cache[block_index] = cpu_to_be16(refcount);
+    if (bdrv_pwrite(s->hd, 
+                    refcount_block_offset + (block_index << REFCOUNT_SHIFT), 
+                    &s->refcount_block_cache[block_index], 2) != 2)
+        return -EIO;
+    return refcount;
+}
+
+static void update_refcount(BlockDriverState *bs, 
+                            int64_t offset, int64_t length, 
+                            int addend)
+{
+    BDRVQcowState *s = bs->opaque;
+    int64_t start, last, cluster_offset;
+
+#ifdef DEBUG_ALLOC2
+    printf("update_refcount: offset=%lld size=%lld addend=%d\n", 
+           offset, length, addend);
+#endif
+    if (length <= 0)
+        return;
+    start = offset & ~(s->cluster_size - 1);
+    last = (offset + length - 1) & ~(s->cluster_size - 1);
+    for(cluster_offset = start; cluster_offset <= last; 
+        cluster_offset += s->cluster_size) {
+        update_cluster_refcount(bs, cluster_offset >> s->cluster_bits, addend);
+    }
+}
+
+#ifdef DEBUG_ALLOC
+static void inc_refcounts(BlockDriverState *bs, 
+                          uint16_t *refcount_table, 
+                          int refcount_table_size,
+                          int64_t offset, int64_t size)
+{
+    BDRVQcowState *s = bs->opaque;
+    int64_t start, last, cluster_offset;
+    int k;
+    
+    if (size <= 0)
+        return;
+
+    start = offset & ~(s->cluster_size - 1);
+    last = (offset + size - 1) & ~(s->cluster_size - 1);
+    for(cluster_offset = start; cluster_offset <= last; 
+        cluster_offset += s->cluster_size) {
+        k = cluster_offset >> s->cluster_bits;
+        if (k < 0 || k >= refcount_table_size) {
+            printf("ERROR: invalid cluster offset=0x%llx\n", cluster_offset);
+        } else {
+            if (++refcount_table[k] == 0) {
+                printf("ERROR: overflow cluster offset=0x%llx\n", 
cluster_offset);
+            }
+        }
+    }
+}
+
+static int check_refcounts_l1(BlockDriverState *bs, 
+                              uint16_t *refcount_table, 
+                              int refcount_table_size,
+                              int64_t l1_table_offset, int l1_size,
+                              int check_copied)
+{
+    BDRVQcowState *s = bs->opaque;
+    uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2;
+    int l2_size, i, j, nb_csectors, refcount;
+
+    l2_table = NULL;
+    l1_size2 = l1_size * sizeof(uint64_t);
+
+    inc_refcounts(bs, refcount_table, refcount_table_size,
+                  l1_table_offset, l1_size2);
+
+    l1_table = qemu_malloc(l1_size2);
+    if (!l1_table)
+        goto fail;
+    if (bdrv_pread(s->hd, l1_table_offset, 
+                   l1_table, l1_size2) != l1_size2)
+        goto fail;
+    for(i = 0;i < l1_size; i++)
+        be64_to_cpus(&l1_table[i]);
+    
+    l2_size = s->l2_size * sizeof(uint64_t);
+    l2_table = qemu_malloc(l2_size);
+    if (!l2_table)
+        goto fail;
+    for(i = 0; i < l1_size; i++) {
+        l2_offset = l1_table[i];
+        if (l2_offset) {
+            if (check_copied) {
+                refcount = get_refcount(bs, (l2_offset & ~QCOW_OFLAG_COPIED) 
>> s->cluster_bits);
+                if ((refcount == 1) != ((l2_offset & QCOW_OFLAG_COPIED) != 0)) 
{
+                    printf("ERROR OFLAG_COPIED: l2_offset=%llx refcount=%d\n",
+                           l2_offset, refcount);
+                }
+            }
+            l2_offset &= ~QCOW_OFLAG_COPIED;
+            if (bdrv_pread(s->hd, l2_offset, l2_table, l2_size) != l2_size)
+                goto fail;
+            for(j = 0; j < s->l2_size; j++) {
+                offset = be64_to_cpu(l2_table[j]);
+                if (offset != 0) {
+                    if (offset & QCOW_OFLAG_COMPRESSED) {
+                        if (offset & QCOW_OFLAG_COPIED) {
+                            printf("ERROR: cluster %lld: copied flag must 
never be set for compressed clusters\n",
+                                   offset >> s->cluster_bits);
+                            offset &= ~QCOW_OFLAG_COPIED;
+                        }
+                        nb_csectors = ((offset >> s->csize_shift) & 
+                                       s->csize_mask) + 1;
+                        offset &= s->cluster_offset_mask;
+                        inc_refcounts(bs, refcount_table, 
+                                      refcount_table_size,
+                                      offset & ~511, nb_csectors * 512);
+                    } else {
+                        if (check_copied) {
+                            refcount = get_refcount(bs, (offset & 
~QCOW_OFLAG_COPIED) >> s->cluster_bits);
+                            if ((refcount == 1) != ((offset & 
QCOW_OFLAG_COPIED) != 0)) {
+                                printf("ERROR OFLAG_COPIED: offset=%llx 
refcount=%d\n",
+                                       offset, refcount);
+                            }
+                        }
+                        offset &= ~QCOW_OFLAG_COPIED;
+                        inc_refcounts(bs, refcount_table, 
+                                      refcount_table_size,
+                                      offset, s->cluster_size);
+                    }
+                }
+            }
+            inc_refcounts(bs, refcount_table, 
+                          refcount_table_size,
+                          l2_offset,
+                          s->cluster_size);
+        }
+    }
+    qemu_free(l1_table);
+    qemu_free(l2_table);
+    return 0;
+ fail:
+    printf("ERROR: I/O error in check_refcounts_l1\n");
+    qemu_free(l1_table);
+    qemu_free(l2_table);
+    return -EIO;
+}
+
+static void check_refcounts(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    int64_t size;
+    int nb_clusters, refcount1, refcount2, i;
+    QCowSnapshot *sn;
+    uint16_t *refcount_table;
+
+    size = bdrv_getlength(s->hd);
+    nb_clusters = (size + s->cluster_size - 1) >> s->cluster_bits;
+    refcount_table = qemu_mallocz(nb_clusters * sizeof(uint16_t));
+
+    /* header */
+    inc_refcounts(bs, refcount_table, nb_clusters,
+                  0, s->cluster_size);
+    
+    check_refcounts_l1(bs, refcount_table, nb_clusters,
+                       s->l1_table_offset, s->l1_size, 1);
+
+    /* snapshots */
+    for(i = 0; i < s->nb_snapshots; i++) {
+        sn = s->snapshots + i;
+        check_refcounts_l1(bs, refcount_table, nb_clusters,
+                           sn->l1_table_offset, sn->l1_size, 0);
+    }
+    inc_refcounts(bs, refcount_table, nb_clusters,
+                  s->snapshots_offset, s->snapshots_size);
+
+    /* refcount data */
+    inc_refcounts(bs, refcount_table, nb_clusters,
+                  s->refcount_table_offset, 
+                  s->refcount_table_size * sizeof(uint64_t));
+    for(i = 0; i < s->refcount_table_size; i++) {
+        int64_t offset;
+        offset = s->refcount_table[i];
+        if (offset != 0) {
+            inc_refcounts(bs, refcount_table, nb_clusters,
+                          offset, s->cluster_size);
+        }
+    }
+
+    /* compare ref counts */
+    for(i = 0; i < nb_clusters; i++) {
+        refcount1 = get_refcount(bs, i);
+        refcount2 = refcount_table[i];
+        if (refcount1 != refcount2)
+            printf("ERROR cluster %d refcount=%d reference=%d\n",
+                   i, refcount1, refcount2);
+    }
+
+    qemu_free(refcount_table);
+}
+
+#if 0
+static void dump_refcounts(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    int64_t nb_clusters, k, k1, size;
+    int refcount;
+
+    size = bdrv_getlength(s->hd);
+    nb_clusters = (size + s->cluster_size - 1) >> s->cluster_bits;
+    for(k = 0; k < nb_clusters;) {
+        k1 = k;
+        refcount = get_refcount(bs, k);
+        k++;
+        while (k < nb_clusters && get_refcount(bs, k) == refcount)
+            k++;
+        printf("%lld: refcount=%d nb=%lld\n", k, refcount, k - k1);
+    }
+}
+#endif
+#endif
+
+BlockDriver bdrv_qcow2 = {
+    "qcow2",
+    sizeof(BDRVQcowState),
+    qcow_probe,
+    qcow_open,
+    NULL,
+    NULL,
+    qcow_close,
+    qcow_create,
+    qcow_flush,
+    qcow_is_allocated,
+    qcow_set_key,
+    qcow_make_empty,
+
+    .bdrv_aio_read = qcow_aio_read,
+    .bdrv_aio_write = qcow_aio_write,
+    .bdrv_aio_cancel = qcow_aio_cancel,
+    .aiocb_size = sizeof(QCowAIOCB),
+    .bdrv_write_compressed = qcow_write_compressed,
+
+    .bdrv_snapshot_create = qcow_snapshot_create,
+    .bdrv_snapshot_goto = qcow_snapshot_goto,
+    .bdrv_snapshot_delete = qcow_snapshot_delete,
+    .bdrv_snapshot_list = qcow_snapshot_list,
+    .bdrv_get_info = qcow_get_info,
+};
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/block-raw.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ioemu/block-raw.c   Wed May 09 14:17:15 2007 +0100
@@ -0,0 +1,1353 @@
+/*
+ * Block driver for RAW files
+ * 
+ * Copyright (c) 2006 Fabrice Bellard
+ * 
+ * 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 "vl.h"
+#include "block_int.h"
+#include <assert.h>
+#ifndef _WIN32
+#include <aio.h>
+
+#ifndef QEMU_TOOL
+#include "exec-all.h"
+#endif
+
+#ifdef CONFIG_COCOA
+#include <paths.h>
+#include <sys/param.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOBSD.h>
+#include <IOKit/storage/IOMediaBSDClient.h>
+#include <IOKit/storage/IOMedia.h>
+#include <IOKit/storage/IOCDMedia.h>
+//#include <IOKit/storage/IOCDTypes.h>
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
+#ifdef __sun__
+#define _POSIX_PTHREAD_SEMANTICS 1
+#include <signal.h>
+#include <sys/dkio.h>
+#endif
+#ifdef __linux__
+#include <sys/ioctl.h>
+#include <linux/cdrom.h>
+#include <linux/fd.h>
+#endif
+#ifdef __FreeBSD__
+#include <sys/disk.h>
+#endif
+
+//#define DEBUG_FLOPPY
+
+#define FTYPE_FILE   0
+#define FTYPE_CD     1
+#define FTYPE_FD     2
+
+/* if the FD is not accessed during that time (in ms), we try to
+   reopen it to see if the disk has been changed */
+#define FD_OPEN_TIMEOUT 1000
+
+typedef struct BDRVRawState {
+    int fd;
+    int type;
+#if defined(__linux__)
+    /* linux floppy specific */
+    int fd_open_flags;
+    int64_t fd_open_time;
+    int64_t fd_error_time;
+    int fd_got_error;
+    int fd_media_changed;
+#endif
+} BDRVRawState;
+
+static int fd_open(BlockDriverState *bs);
+
+static int raw_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    BDRVRawState *s = bs->opaque;
+    int fd, open_flags, ret;
+
+    open_flags = O_BINARY;
+    if ((flags & BDRV_O_ACCESS) == O_RDWR) {
+        open_flags |= O_RDWR;
+    } else {
+        open_flags |= O_RDONLY;
+        bs->read_only = 1;
+    }
+    if (flags & BDRV_O_CREAT)
+        open_flags |= O_CREAT | O_TRUNC;
+
+    s->type = FTYPE_FILE;
+
+    fd = open(filename, open_flags, 0644);
+    if (fd < 0) {
+        ret = -errno;
+        if (ret == -EROFS)
+            ret = -EACCES;
+        return ret;
+    }
+    s->fd = fd;
+    return 0;
+}
+
+/* XXX: use host sector size if necessary with:
+#ifdef DIOCGSECTORSIZE
+        {
+            unsigned int sectorsize = 512;
+            if (!ioctl(fd, DIOCGSECTORSIZE, &sectorsize) &&
+                sectorsize > bufsize)
+                bufsize = sectorsize;
+        }
+#endif
+#ifdef CONFIG_COCOA
+        u_int32_t   blockSize = 512;
+        if ( !ioctl( fd, DKIOCGETBLOCKSIZE, &blockSize ) && blockSize > 
bufsize) {
+            bufsize = blockSize;
+        }
+#endif
+*/
+
+static int raw_pread(BlockDriverState *bs, int64_t offset, 
+                     uint8_t *buf, int count)
+{
+    BDRVRawState *s = bs->opaque;
+    int ret;
+    
+    ret = fd_open(bs);
+    if (ret < 0)
+        return ret;
+
+    lseek(s->fd, offset, SEEK_SET);
+    ret = read(s->fd, buf, count);
+    return ret;
+}
+
+static int raw_pwrite(BlockDriverState *bs, int64_t offset, 
+                      const uint8_t *buf, int count)
+{
+    BDRVRawState *s = bs->opaque;
+    int ret;
+    
+    ret = fd_open(bs);
+    if (ret < 0)
+        return ret;
+
+    lseek(s->fd, offset, SEEK_SET);
+    ret = write(s->fd, buf, count);
+    return ret;
+}
+
+/***********************************************************/
+/* Unix AIO using POSIX AIO */
+
+typedef struct RawAIOCB {
+    BlockDriverAIOCB common;
+    struct aiocb aiocb;
+    struct RawAIOCB *next;
+} RawAIOCB;
+
+static int aio_sig_num = SIGUSR2;
+static RawAIOCB *first_aio; /* AIO issued */
+static int aio_initialized = 0;
+
+static void aio_signal_handler(int signum)
+{
+#ifndef QEMU_TOOL
+    CPUState *env = cpu_single_env;
+    if (env) {
+        /* stop the currently executing cpu because a timer occured */
+        cpu_interrupt(env, CPU_INTERRUPT_EXIT);
+#ifdef USE_KQEMU
+        if (env->kqemu_enabled) {
+            kqemu_cpu_interrupt(env);
+        }
+#endif
+    }
+#endif
+}
+
+void qemu_aio_init(void)
+{
+    struct sigaction act;
+
+    aio_initialized = 1;
+    
+    sigfillset(&act.sa_mask);
+    act.sa_flags = 0; /* do not restart syscalls to interrupt select() */
+    act.sa_handler = aio_signal_handler;
+    sigaction(aio_sig_num, &act, NULL);
+
+#if defined(__GLIBC__) && defined(__linux__)
+    {
+        /* XXX: aio thread exit seems to hang on RedHat 9 and this init
+           seems to fix the problem. */
+        struct aioinit ai;
+        memset(&ai, 0, sizeof(ai));
+        ai.aio_threads = 1;
+        ai.aio_num = 1;
+        ai.aio_idle_time = 365 * 100000;
+        aio_init(&ai);
+    }
+#endif
+}
+
+void qemu_aio_poll(void)
+{
+    RawAIOCB *acb, **pacb;
+    int ret;
+
+    for(;;) {
+        pacb = &first_aio;
+        for(;;) {
+            acb = *pacb;
+            if (!acb)
+                goto the_end;
+            ret = aio_error(&acb->aiocb);
+            if (ret == ECANCELED) {
+                /* remove the request */
+                *pacb = acb->next;
+                qemu_aio_release(acb);
+            } else if (ret != EINPROGRESS) {
+                /* end of aio */
+                if (ret == 0) {
+                    ret = aio_return(&acb->aiocb);
+                    if (ret == acb->aiocb.aio_nbytes)
+                        ret = 0;
+                    else
+                        ret = -EINVAL;
+                } else {
+                    ret = -ret;
+                }
+                /* remove the request */
+                *pacb = acb->next;
+                /* call the callback */
+                acb->common.cb(acb->common.opaque, ret);
+                qemu_aio_release(acb);
+                break;
+            } else {
+                pacb = &acb->next;
+            }
+        }
+    }
+ the_end: ;
+}
+
+/* Wait for all IO requests to complete.  */
+void qemu_aio_flush(void)
+{
+    qemu_aio_wait_start();
+    qemu_aio_poll();
+    while (first_aio) {
+        qemu_aio_wait();
+    }
+    qemu_aio_wait_end();
+}
+
+/* wait until at least one AIO was handled */
+static sigset_t wait_oset;
+
+void qemu_aio_wait_start(void)
+{
+    sigset_t set;
+
+    if (!aio_initialized)
+        qemu_aio_init();
+    sigemptyset(&set);
+    sigaddset(&set, aio_sig_num);
+    sigprocmask(SIG_BLOCK, &set, &wait_oset);
+}
+
+void qemu_aio_wait(void)
+{
+    sigset_t set;
+    int nb_sigs;
+
+#ifndef QEMU_TOOL
+    if (qemu_bh_poll())
+        return;
+#endif
+    sigemptyset(&set);
+    sigaddset(&set, aio_sig_num);
+    sigwait(&set, &nb_sigs);
+    qemu_aio_poll();
+}
+
+void qemu_aio_wait_end(void)
+{
+    sigprocmask(SIG_SETMASK, &wait_oset, NULL);
+}
+
+static RawAIOCB *raw_aio_setup(BlockDriverState *bs,
+        int64_t sector_num, uint8_t *buf, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BDRVRawState *s = bs->opaque;
+    RawAIOCB *acb;
+
+    if (fd_open(bs) < 0)
+        return NULL;
+
+    acb = qemu_aio_get(bs, cb, opaque);
+    if (!acb)
+        return NULL;
+    acb->aiocb.aio_fildes = s->fd;
+    acb->aiocb.aio_sigevent.sigev_signo = aio_sig_num;
+    acb->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
+    acb->aiocb.aio_buf = buf;
+    acb->aiocb.aio_nbytes = nb_sectors * 512;
+    acb->aiocb.aio_offset = sector_num * 512;
+    acb->next = first_aio;
+    first_aio = acb;
+    return acb;
+}
+
+static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs,
+        int64_t sector_num, uint8_t *buf, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    RawAIOCB *acb;
+
+    acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
+    if (!acb)
+        return NULL;
+    if (aio_read(&acb->aiocb) < 0) {
+        qemu_aio_release(acb);
+        return NULL;
+    } 
+    return &acb->common;
+}
+
+static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs,
+        int64_t sector_num, const uint8_t *buf, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    RawAIOCB *acb;
+
+    acb = raw_aio_setup(bs, sector_num, (uint8_t*)buf, nb_sectors, cb, opaque);
+    if (!acb)
+        return NULL;
+    if (aio_write(&acb->aiocb) < 0) {
+        qemu_aio_release(acb);
+        return NULL;
+    } 
+    return &acb->common;
+}
+
+static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+    int ret;
+    RawAIOCB *acb = (RawAIOCB *)blockacb;
+    RawAIOCB **pacb;
+
+    ret = aio_cancel(acb->aiocb.aio_fildes, &acb->aiocb);
+    if (ret == AIO_NOTCANCELED) {
+        /* fail safe: if the aio could not be canceled, we wait for
+           it */
+        while (aio_error(&acb->aiocb) == EINPROGRESS);
+    }
+
+    /* remove the callback from the queue */
+    pacb = &first_aio;
+    for(;;) {
+        if (*pacb == NULL) {
+            break;
+        } else if (*pacb == acb) {
+            *pacb = acb->next;
+            qemu_aio_release(acb);
+            break;
+        }
+        pacb = &acb->next;
+    }
+}
+
+static void raw_close(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+    bs->total_sectors = 0;
+    if (s->fd >= 0) {
+        close(s->fd);
+        s->fd = -1;
+    }
+}
+
+static int raw_truncate(BlockDriverState *bs, int64_t offset)
+{
+    BDRVRawState *s = bs->opaque;
+    if (s->type != FTYPE_FILE)
+        return -ENOTSUP;
+    if (ftruncate(s->fd, offset) < 0)
+        return -errno;
+    return 0;
+}
+
+static int64_t  raw_getlength(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+    int fd = s->fd;
+    int64_t size;
+#ifdef _BSD
+    struct stat sb;
+#endif
+#ifdef __sun__
+    struct dk_minfo minfo;
+    int rv;
+#endif
+    int ret;
+
+    ret = fd_open(bs);
+    if (ret < 0)
+        return ret;
+
+#ifdef _BSD
+    if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) {
+#ifdef DIOCGMEDIASIZE
+       if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size))
+#endif
+#ifdef CONFIG_COCOA
+        size = LONG_LONG_MAX;
+#else
+        size = lseek(fd, 0LL, SEEK_END);
+#endif
+    } else
+#endif
+#ifdef __sun__
+    /*
+     * use the DKIOCGMEDIAINFO ioctl to read the size.
+     */
+    rv = ioctl ( fd, DKIOCGMEDIAINFO, &minfo );
+    if ( rv != -1 ) {
+        size = minfo.dki_lbsize * minfo.dki_capacity;
+    } else /* there are reports that lseek on some devices
+              fails, but irc discussion said that contingency
+              on contingency was overkill */
+#endif
+    {
+        size = lseek(fd, 0, SEEK_END);
+    }
+    return size;
+}
+
+static int raw_create(const char *filename, int64_t total_size,
+                      const char *backing_file, int flags)
+{
+    int fd;
+
+    if (flags || backing_file)
+        return -ENOTSUP;
+
+    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 
+              0644);
+    if (fd < 0)
+        return -EIO;
+    ftruncate(fd, total_size * 512);
+    close(fd);
+    return 0;
+}
+
+static void raw_flush(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+    fsync(s->fd);
+}
+
+BlockDriver bdrv_raw = {
+    "raw",
+    sizeof(BDRVRawState),
+    NULL, /* no probe for protocols */
+    raw_open,
+    NULL,
+    NULL,
+    raw_close,
+    raw_create,
+    raw_flush,
+    
+    .bdrv_aio_read = raw_aio_read,
+    .bdrv_aio_write = raw_aio_write,
+    .bdrv_aio_cancel = raw_aio_cancel,
+    .aiocb_size = sizeof(RawAIOCB),
+    .protocol_name = "file",
+    .bdrv_pread = raw_pread,
+    .bdrv_pwrite = raw_pwrite,
+    .bdrv_truncate = raw_truncate,
+    .bdrv_getlength = raw_getlength,
+};
+
+/***********************************************/
+/* host device */
+
+#ifdef CONFIG_COCOA
+static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator );
+static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, 
CFIndex maxPathSize );
+
+kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )
+{
+    kern_return_t       kernResult; 
+    mach_port_t     masterPort;
+    CFMutableDictionaryRef  classesToMatch;
+
+    kernResult = IOMasterPort( MACH_PORT_NULL, &masterPort );
+    if ( KERN_SUCCESS != kernResult ) {
+        printf( "IOMasterPort returned %d\n", kernResult );
+    }
+    
+    classesToMatch = IOServiceMatching( kIOCDMediaClass ); 
+    if ( classesToMatch == NULL ) {
+        printf( "IOServiceMatching returned a NULL dictionary.\n" );
+    } else {
+    CFDictionarySetValue( classesToMatch, CFSTR( kIOMediaEjectableKey ), 
kCFBooleanTrue );
+    }
+    kernResult = IOServiceGetMatchingServices( masterPort, classesToMatch, 
mediaIterator );
+    if ( KERN_SUCCESS != kernResult )
+    {
+        printf( "IOServiceGetMatchingServices returned %d\n", kernResult );
+    }
+    
+    return kernResult;
+}
+
+kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex 
maxPathSize )
+{
+    io_object_t     nextMedia;
+    kern_return_t   kernResult = KERN_FAILURE;
+    *bsdPath = '\0';
+    nextMedia = IOIteratorNext( mediaIterator );
+    if ( nextMedia )
+    {
+        CFTypeRef   bsdPathAsCFString;
+    bsdPathAsCFString = IORegistryEntryCreateCFProperty( nextMedia, CFSTR( 
kIOBSDNameKey ), kCFAllocatorDefault, 0 );
+        if ( bsdPathAsCFString ) {
+            size_t devPathLength;
+            strcpy( bsdPath, _PATH_DEV );
+            strcat( bsdPath, "r" );
+            devPathLength = strlen( bsdPath );
+            if ( CFStringGetCString( bsdPathAsCFString, bsdPath + 
devPathLength, maxPathSize - devPathLength, kCFStringEncodingASCII ) ) {
+                kernResult = KERN_SUCCESS;
+            }
+            CFRelease( bsdPathAsCFString );
+        }
+        IOObjectRelease( nextMedia );
+    }
+    
+    return kernResult;
+}
+
+#endif
+
+static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    BDRVRawState *s = bs->opaque;
+    int fd, open_flags, ret;
+
+#ifdef CONFIG_COCOA
+    if (strstart(filename, "/dev/cdrom", NULL)) {
+        kern_return_t kernResult;
+        io_iterator_t mediaIterator;
+        char bsdPath[ MAXPATHLEN ];
+        int fd;
+ 
+        kernResult = FindEjectableCDMedia( &mediaIterator );
+        kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) );
+    
+        if ( bsdPath[ 0 ] != '\0' ) {
+            strcat(bsdPath,"s0");
+            /* some CDs don't have a partition 0 */
+            fd = open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE);
+            if (fd < 0) {
+                bsdPath[strlen(bsdPath)-1] = '1';
+            } else {
+                close(fd);
+            }
+            filename = bsdPath;
+        }
+        
+        if ( mediaIterator )
+            IOObjectRelease( mediaIterator );
+    }
+#endif
+    open_flags = O_BINARY;
+    if ((flags & BDRV_O_ACCESS) == O_RDWR) {
+        open_flags |= O_RDWR;
+    } else {
+        open_flags |= O_RDONLY;
+        bs->read_only = 1;
+    }
+
+    s->type = FTYPE_FILE;
+#if defined(__linux__)
+    if (strstart(filename, "/dev/cd", NULL)) {
+        /* open will not fail even if no CD is inserted */
+        open_flags |= O_NONBLOCK;
+        s->type = FTYPE_CD;
+    } else if (strstart(filename, "/dev/fd", NULL)) {
+        s->type = FTYPE_FD;
+        s->fd_open_flags = open_flags;
+        /* open will not fail even if no floppy is inserted */
+        open_flags |= O_NONBLOCK;
+    }
+#endif
+    fd = open(filename, open_flags, 0644);
+    if (fd < 0) {
+        ret = -errno;
+        if (ret == -EROFS)
+            ret = -EACCES;
+        return ret;
+    }
+    s->fd = fd;
+#if defined(__linux__)
+    /* close fd so that we can reopen it as needed */
+    if (s->type == FTYPE_FD) {
+        close(s->fd);
+        s->fd = -1;
+        s->fd_media_changed = 1;
+    }
+#endif
+    return 0;
+}
+
+#if defined(__linux__) && !defined(QEMU_TOOL)
+
+/* Note: we do not have a reliable method to detect if the floppy is
+   present. The current method is to try to open the floppy at every
+   I/O and to keep it opened during a few hundreds of ms. */
+static int fd_open(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+    int last_media_present;
+
+    if (s->type != FTYPE_FD)
+        return 0;
+    last_media_present = (s->fd >= 0);
+    if (s->fd >= 0 && 
+        (qemu_get_clock(rt_clock) - s->fd_open_time) >= FD_OPEN_TIMEOUT) {
+        close(s->fd);
+        s->fd = -1;
+#ifdef DEBUG_FLOPPY
+        printf("Floppy closed\n");
+#endif
+    }
+    if (s->fd < 0) {
+        if (s->fd_got_error && 
+            (qemu_get_clock(rt_clock) - s->fd_error_time) < FD_OPEN_TIMEOUT) {
+#ifdef DEBUG_FLOPPY
+            printf("No floppy (open delayed)\n");
+#endif
+            return -EIO;
+        }
+        s->fd = open(bs->filename, s->fd_open_flags);
+        if (s->fd < 0) {
+            s->fd_error_time = qemu_get_clock(rt_clock);
+            s->fd_got_error = 1;
+            if (last_media_present)
+                s->fd_media_changed = 1;
+#ifdef DEBUG_FLOPPY
+            printf("No floppy\n");
+#endif
+            return -EIO;
+        }
+#ifdef DEBUG_FLOPPY
+        printf("Floppy opened\n");
+#endif
+    }
+    if (!last_media_present)
+        s->fd_media_changed = 1;
+    s->fd_open_time = qemu_get_clock(rt_clock);
+    s->fd_got_error = 0;
+    return 0;
+}
+#else
+static int fd_open(BlockDriverState *bs)
+{
+    return 0;
+}
+#endif
+
+#if defined(__linux__)
+
+static int raw_is_inserted(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+    int ret;
+
+    switch(s->type) {
+    case FTYPE_CD:
+        ret = ioctl(s->fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
+        if (ret == CDS_DISC_OK)
+            return 1;
+        else
+            return 0;
+        break;
+    case FTYPE_FD:
+        ret = fd_open(bs);
+        return (ret >= 0);
+    default:
+        return 1;
+    }
+}
+
+/* currently only used by fdc.c, but a CD version would be good too */
+static int raw_media_changed(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+
+    switch(s->type) {
+    case FTYPE_FD:
+        {
+            int ret;
+            /* XXX: we do not have a true media changed indication. It
+               does not work if the floppy is changed without trying
+               to read it */
+            fd_open(bs);
+            ret = s->fd_media_changed;
+            s->fd_media_changed = 0;
+#ifdef DEBUG_FLOPPY
+            printf("Floppy changed=%d\n", ret);
+#endif
+            return ret;
+        }
+    default:
+        return -ENOTSUP;
+    }
+}
+
+static int raw_eject(BlockDriverState *bs, int eject_flag)
+{
+    BDRVRawState *s = bs->opaque;
+
+    switch(s->type) {
+    case FTYPE_CD:
+        if (eject_flag) {
+            if (ioctl (s->fd, CDROMEJECT, NULL) < 0)
+                perror("CDROMEJECT");
+        } else {
+            if (ioctl (s->fd, CDROMCLOSETRAY, NULL) < 0)
+                perror("CDROMEJECT");
+        }
+        break;
+    case FTYPE_FD:
+        {
+            int fd;
+            if (s->fd >= 0) {
+                close(s->fd);
+                s->fd = -1;
+            }
+            fd = open(bs->filename, s->fd_open_flags | O_NONBLOCK);
+            if (fd >= 0) {
+                if (ioctl(fd, FDEJECT, 0) < 0)
+                    perror("FDEJECT");
+                close(fd);
+            }
+        }
+        break;
+    default:
+        return -ENOTSUP;
+    }
+    return 0;
+}
+
+static int raw_set_locked(BlockDriverState *bs, int locked)
+{
+    BDRVRawState *s = bs->opaque;
+
+    switch(s->type) {
+    case FTYPE_CD:
+        if (ioctl (s->fd, CDROM_LOCKDOOR, locked) < 0) {
+            /* Note: an error can happen if the distribution automatically
+               mounts the CD-ROM */
+            //        perror("CDROM_LOCKDOOR");
+        }
+        break;
+    default:
+        return -ENOTSUP;
+    }
+    return 0;
+}
+
+#else
+
+static int raw_is_inserted(BlockDriverState *bs)
+{
+    return 1;
+}
+
+static int raw_media_changed(BlockDriverState *bs)
+{
+    return -ENOTSUP;
+}
+
+static int raw_eject(BlockDriverState *bs, int eject_flag)
+{
+    return -ENOTSUP;
+}
+
+static int raw_set_locked(BlockDriverState *bs, int locked)
+{
+    return -ENOTSUP;
+}
+
+#endif /* !linux */
+
+BlockDriver bdrv_host_device = {
+    "host_device",
+    sizeof(BDRVRawState),
+    NULL, /* no probe for protocols */
+    hdev_open,
+    NULL,
+    NULL,
+    raw_close,
+    NULL,
+    raw_flush,
+    
+    .bdrv_aio_read = raw_aio_read,
+    .bdrv_aio_write = raw_aio_write,
+    .bdrv_aio_cancel = raw_aio_cancel,
+    .aiocb_size = sizeof(RawAIOCB),
+    .bdrv_pread = raw_pread,
+    .bdrv_pwrite = raw_pwrite,
+    .bdrv_getlength = raw_getlength,
+
+    /* removable device support */
+    .bdrv_is_inserted = raw_is_inserted,
+    .bdrv_media_changed = raw_media_changed,
+    .bdrv_eject = raw_eject,
+    .bdrv_set_locked = raw_set_locked,
+};
+
+#else /* _WIN32 */
+
+/* XXX: use another file ? */
+#include <winioctl.h>
+
+#define FTYPE_FILE 0
+#define FTYPE_CD     1
+#define FTYPE_HARDDISK 2
+
+typedef struct BDRVRawState {
+    HANDLE hfile;
+    int type;
+    char drive_path[16]; /* format: "d:\" */
+} BDRVRawState;
+
+typedef struct RawAIOCB {
+    BlockDriverAIOCB common;
+    HANDLE hEvent;
+    OVERLAPPED ov;
+    int count;
+} RawAIOCB;
+
+int qemu_ftruncate64(int fd, int64_t length)
+{
+    LARGE_INTEGER li;
+    LONG high;
+    HANDLE h;
+    BOOL res;
+
+    if ((GetVersion() & 0x80000000UL) && (length >> 32) != 0)
+       return -1;
+
+    h = (HANDLE)_get_osfhandle(fd);
+
+    /* get current position, ftruncate do not change position */
+    li.HighPart = 0;
+    li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT);
+    if (li.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
+       return -1;
+
+    high = length >> 32;
+    if (!SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN))
+       return -1;
+    res = SetEndOfFile(h);
+
+    /* back to old position */
+    SetFilePointer(h, li.LowPart, &li.HighPart, FILE_BEGIN);
+    return res ? 0 : -1;
+}
+
+static int set_sparse(int fd)
+{
+    DWORD returned;
+    return (int) DeviceIoControl((HANDLE)_get_osfhandle(fd), FSCTL_SET_SPARSE,
+                                NULL, 0, NULL, 0, &returned, NULL);
+}
+
+static int raw_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    BDRVRawState *s = bs->opaque;
+    int access_flags, create_flags;
+    DWORD overlapped;
+
+    s->type = FTYPE_FILE;
+
+    if ((flags & BDRV_O_ACCESS) == O_RDWR) {
+        access_flags = GENERIC_READ | GENERIC_WRITE;
+    } else {
+        access_flags = GENERIC_READ;
+    }
+    if (flags & BDRV_O_CREAT) {
+        create_flags = CREATE_ALWAYS;
+    } else {
+        create_flags = OPEN_EXISTING;
+    }
+#ifdef QEMU_TOOL
+    overlapped = FILE_ATTRIBUTE_NORMAL;
+#else
+    overlapped = FILE_FLAG_OVERLAPPED;
+#endif
+    s->hfile = CreateFile(filename, access_flags, 
+                          FILE_SHARE_READ, NULL,
+                          create_flags, overlapped, NULL);
+    if (s->hfile == INVALID_HANDLE_VALUE) {
+        int err = GetLastError();
+
+        if (err == ERROR_ACCESS_DENIED)
+            return -EACCES;
+        return -1;
+    }
+    return 0;
+}
+
+static int raw_pread(BlockDriverState *bs, int64_t offset, 
+                     uint8_t *buf, int count)
+{
+    BDRVRawState *s = bs->opaque;
+    OVERLAPPED ov;
+    DWORD ret_count;
+    int ret;
+    
+    memset(&ov, 0, sizeof(ov));
+    ov.Offset = offset;
+    ov.OffsetHigh = offset >> 32;
+    ret = ReadFile(s->hfile, buf, count, &ret_count, &ov);
+    if (!ret) {
+        ret = GetOverlappedResult(s->hfile, &ov, &ret_count, TRUE);
+        if (!ret)
+            return -EIO;
+        else
+            return ret_count;
+    }
+    return ret_count;
+}
+
+static int raw_pwrite(BlockDriverState *bs, int64_t offset, 
+                      const uint8_t *buf, int count)
+{
+    BDRVRawState *s = bs->opaque;
+    OVERLAPPED ov;
+    DWORD ret_count;
+    int ret;
+    
+    memset(&ov, 0, sizeof(ov));
+    ov.Offset = offset;
+    ov.OffsetHigh = offset >> 32;
+    ret = WriteFile(s->hfile, buf, count, &ret_count, &ov);
+    if (!ret) {
+        ret = GetOverlappedResult(s->hfile, &ov, &ret_count, TRUE);
+        if (!ret)
+            return -EIO;
+        else
+            return ret_count;
+    }
+    return ret_count;
+}
+
+#if 0
+#ifndef QEMU_TOOL
+static void raw_aio_cb(void *opaque)
+{
+    RawAIOCB *acb = opaque;
+    BlockDriverState *bs = acb->common.bs;
+    BDRVRawState *s = bs->opaque;
+    DWORD ret_count;
+    int ret;
+
+    ret = GetOverlappedResult(s->hfile, &acb->ov, &ret_count, TRUE);
+    if (!ret || ret_count != acb->count) {
+        acb->common.cb(acb->common.opaque, -EIO);
+    } else {
+        acb->common.cb(acb->common.opaque, 0);
+    }
+}
+#endif
+
+static RawAIOCB *raw_aio_setup(BlockDriverState *bs,
+        int64_t sector_num, uint8_t *buf, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    RawAIOCB *acb;
+    int64_t offset;
+
+    acb = qemu_aio_get(bs, cb, opaque);
+    if (acb->hEvent) {
+        acb->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+        if (!acb->hEvent) {
+            qemu_aio_release(acb);
+            return NULL;
+        }
+    }
+    memset(&acb->ov, 0, sizeof(acb->ov));
+    offset = sector_num * 512;
+    acb->ov.Offset = offset;
+    acb->ov.OffsetHigh = offset >> 32;
+    acb->ov.hEvent = acb->hEvent;
+    acb->count = nb_sectors * 512;
+#ifndef QEMU_TOOL
+    qemu_add_wait_object(acb->ov.hEvent, raw_aio_cb, acb);
+#endif
+    return acb;
+}
+
+static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs,
+        int64_t sector_num, uint8_t *buf, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BDRVRawState *s = bs->opaque;
+    RawAIOCB *acb;
+    int ret;
+
+    acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
+    if (!acb)
+        return NULL;
+    ret = ReadFile(s->hfile, buf, acb->count, NULL, &acb->ov);
+    if (!ret) {
+        qemu_aio_release(acb);
+        return NULL;
+    }
+#ifdef QEMU_TOOL
+    qemu_aio_release(acb);
+#endif
+    return (BlockDriverAIOCB *)acb;
+}
+
+static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs,
+        int64_t sector_num, uint8_t *buf, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BDRVRawState *s = bs->opaque;
+    RawAIOCB *acb;
+    int ret;
+
+    acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
+    if (!acb)
+        return NULL;
+    ret = WriteFile(s->hfile, buf, acb->count, NULL, &acb->ov);
+    if (!ret) {
+        qemu_aio_release(acb);
+        return NULL;
+    }
+#ifdef QEMU_TOOL
+    qemu_aio_release(acb);
+#endif
+    return (BlockDriverAIOCB *)acb;
+}
+
+static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+#ifndef QEMU_TOOL
+    RawAIOCB *acb = (RawAIOCB *)blockacb;
+    BlockDriverState *bs = acb->common.bs;
+    BDRVRawState *s = bs->opaque;
+
+    qemu_del_wait_object(acb->ov.hEvent, raw_aio_cb, acb);
+    /* XXX: if more than one async I/O it is not correct */
+    CancelIo(s->hfile);
+    qemu_aio_release(acb);
+#endif
+}
+#endif /* #if 0 */
+
+static void raw_flush(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+    FlushFileBuffers(s->hfile);
+}
+
+static void raw_close(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+    CloseHandle(s->hfile);
+}
+
+static int raw_truncate(BlockDriverState *bs, int64_t offset)
+{
+    BDRVRawState *s = bs->opaque;
+    DWORD low, high;
+
+    low = offset;
+    high = offset >> 32;
+    if (!SetFilePointer(s->hfile, low, &high, FILE_BEGIN))
+       return -EIO;
+    if (!SetEndOfFile(s->hfile))
+        return -EIO;
+    return 0;
+}
+
+static int64_t raw_getlength(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+    LARGE_INTEGER l;
+    ULARGE_INTEGER available, total, total_free; 
+    DISK_GEOMETRY dg;
+    DWORD count;
+    BOOL status;
+
+    switch(s->type) {
+    case FTYPE_FILE:
+        l.LowPart = GetFileSize(s->hfile, &l.HighPart);
+        if (l.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
+            return -EIO;
+        break;
+    case FTYPE_CD:
+        if (!GetDiskFreeSpaceEx(s->drive_path, &available, &total, 
&total_free))
+            return -EIO;
+        l.QuadPart = total.QuadPart;
+        break;
+    case FTYPE_HARDDISK:
+        status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY,
+                                 NULL, 0, &dg, sizeof(dg), &count, NULL);
+        if (status != FALSE) {
+            l.QuadPart = dg.Cylinders.QuadPart * dg.TracksPerCylinder
+                * dg.SectorsPerTrack * dg.BytesPerSector;
+        }
+        break;
+    default:
+        return -EIO;
+    }
+    return l.QuadPart;
+}
+
+static int raw_create(const char *filename, int64_t total_size,
+                      const char *backing_file, int flags)
+{
+    int fd;
+
+    if (flags || backing_file)
+        return -ENOTSUP;
+
+    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 
+              0644);
+    if (fd < 0)
+        return -EIO;
+    set_sparse(fd);
+    ftruncate(fd, total_size * 512);
+    close(fd);
+    return 0;
+}
+
+void qemu_aio_init(void)
+{
+}
+
+void qemu_aio_poll(void)
+{
+}
+
+void qemu_aio_flush(void)
+{
+}
+
+void qemu_aio_wait_start(void)
+{
+}
+
+void qemu_aio_wait(void)
+{
+#ifndef QEMU_TOOL
+    qemu_bh_poll();
+#endif
+}
+
+void qemu_aio_wait_end(void)
+{
+}
+
+BlockDriver bdrv_raw = {
+    "raw",
+    sizeof(BDRVRawState),
+    NULL, /* no probe for protocols */
+    raw_open,
+    NULL,
+    NULL,
+    raw_close,
+    raw_create,
+    raw_flush,
+    
+#if 0
+    .bdrv_aio_read = raw_aio_read,
+    .bdrv_aio_write = raw_aio_write,
+    .bdrv_aio_cancel = raw_aio_cancel,
+    .aiocb_size = sizeof(RawAIOCB);
+#endif
+    .protocol_name = "file",
+    .bdrv_pread = raw_pread,
+    .bdrv_pwrite = raw_pwrite,
+    .bdrv_truncate = raw_truncate,
+    .bdrv_getlength = raw_getlength,
+};
+
+/***********************************************/
+/* host device */
+
+static int find_cdrom(char *cdrom_name, int cdrom_name_size)
+{
+    char drives[256], *pdrv = drives;
+    UINT type;
+
+    memset(drives, 0, sizeof(drives));
+    GetLogicalDriveStrings(sizeof(drives), drives);
+    while(pdrv[0] != '\0') {
+        type = GetDriveType(pdrv);
+        switch(type) {
+        case DRIVE_CDROM:
+            snprintf(cdrom_name, cdrom_name_size, "\\\\.\\%c:", pdrv[0]);
+            return 0;
+            break;
+        }
+        pdrv += lstrlen(pdrv) + 1;
+    }
+    return -1;
+}
+
+static int find_device_type(BlockDriverState *bs, const char *filename)
+{
+    BDRVRawState *s = bs->opaque;
+    UINT type;
+    const char *p;
+
+    if (strstart(filename, "\\\\.\\", &p) ||
+        strstart(filename, "//./", &p)) {
+        if (stristart(p, "PhysicalDrive", NULL))
+            return FTYPE_HARDDISK;
+        snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", p[0]);
+        type = GetDriveType(s->drive_path);
+        if (type == DRIVE_CDROM)
+            return FTYPE_CD;
+        else
+            return FTYPE_FILE;
+    } else {
+        return FTYPE_FILE;
+    }
+}
+
+static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    BDRVRawState *s = bs->opaque;
+    int access_flags, create_flags;
+    DWORD overlapped;
+    char device_name[64];
+
+    if (strstart(filename, "/dev/cdrom", NULL)) {
+        if (find_cdrom(device_name, sizeof(device_name)) < 0)
+            return -ENOENT;
+        filename = device_name;
+    } else {
+        /* transform drive letters into device name */
+        if (((filename[0] >= 'a' && filename[0] <= 'z') ||
+             (filename[0] >= 'A' && filename[0] <= 'Z')) &&
+            filename[1] == ':' && filename[2] == '\0') {
+            snprintf(device_name, sizeof(device_name), "\\\\.\\%c:", 
filename[0]);
+            filename = device_name;
+        }
+    }
+    s->type = find_device_type(bs, filename);
+    
+    if ((flags & BDRV_O_ACCESS) == O_RDWR) {
+        access_flags = GENERIC_READ | GENERIC_WRITE;
+    } else {
+        access_flags = GENERIC_READ;
+    }
+    create_flags = OPEN_EXISTING;
+
+#ifdef QEMU_TOOL
+    overlapped = FILE_ATTRIBUTE_NORMAL;
+#else
+    overlapped = FILE_FLAG_OVERLAPPED;
+#endif
+    s->hfile = CreateFile(filename, access_flags, 
+                          FILE_SHARE_READ, NULL,
+                          create_flags, overlapped, NULL);
+    if (s->hfile == INVALID_HANDLE_VALUE) {
+        int err = GetLastError();
+
+        if (err == ERROR_ACCESS_DENIED)
+            return -EACCES;
+        return -1;
+    }
+    return 0;
+}
+
+#if 0
+/***********************************************/
+/* removable device additionnal commands */
+
+static int raw_is_inserted(BlockDriverState *bs)
+{
+    return 1;
+}
+
+static int raw_media_changed(BlockDriverState *bs)
+{
+    return -ENOTSUP;
+}
+
+static int raw_eject(BlockDriverState *bs, int eject_flag)
+{
+    DWORD ret_count;
+
+    if (s->type == FTYPE_FILE)
+        return -ENOTSUP;
+    if (eject_flag) {
+        DeviceIoControl(s->hfile, IOCTL_STORAGE_EJECT_MEDIA, 
+                        NULL, 0, NULL, 0, &lpBytesReturned, NULL);
+    } else {
+        DeviceIoControl(s->hfile, IOCTL_STORAGE_LOAD_MEDIA, 
+                        NULL, 0, NULL, 0, &lpBytesReturned, NULL);
+    }
+}
+
+static int raw_set_locked(BlockDriverState *bs, int locked)
+{
+    return -ENOTSUP;
+}
+#endif
+
+BlockDriver bdrv_host_device = {
+    "host_device",
+    sizeof(BDRVRawState),
+    NULL, /* no probe for protocols */
+    hdev_open,
+    NULL,
+    NULL,
+    raw_close,
+    NULL,
+    raw_flush,
+    
+#if 0
+    .bdrv_aio_read = raw_aio_read,
+    .bdrv_aio_write = raw_aio_write,
+    .bdrv_aio_cancel = raw_aio_cancel,
+    .aiocb_size = sizeof(RawAIOCB);
+#endif
+    .bdrv_pread = raw_pread,
+    .bdrv_pwrite = raw_pwrite,
+    .bdrv_getlength = raw_getlength,
+};
+#endif /* _WIN32 */
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/block-vmdk.c
--- a/tools/ioemu/block-vmdk.c  Tue May 08 10:38:06 2007 +0100
+++ b/tools/ioemu/block-vmdk.c  Wed May 09 14:17:15 2007 +0100
@@ -22,6 +22,7 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
+
 #include "vl.h"
 #include "block_int.h"
 
@@ -59,7 +60,7 @@ typedef struct {
 #define L2_CACHE_SIZE 16
 
 typedef struct BDRVVmdkState {
-    int fd;
+    BlockDriverState *hd;
     int64_t l1_table_offset;
     int64_t l1_backup_table_offset;
     uint32_t *l1_table;
@@ -73,6 +74,7 @@ typedef struct BDRVVmdkState {
     uint32_t l2_cache_counts[L2_CACHE_SIZE];
 
     unsigned int cluster_sectors;
+    uint32_t parent_cid;
 } BDRVVmdkState;
 
 static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
@@ -89,27 +91,278 @@ static int vmdk_probe(const uint8_t *buf
         return 0;
 }
 
-static int vmdk_open(BlockDriverState *bs, const char *filename)
-{
-    BDRVVmdkState *s = bs->opaque;
-    int fd, i;
+#define CHECK_CID 1
+
+#define SECTOR_SIZE 512                                
+#define DESC_SIZE 20*SECTOR_SIZE       // 20 sectors of 512 bytes each
+#define HEADER_SIZE 512                        // first sector of 512 bytes 
+
+static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
+{
+    BDRVVmdkState *s = bs->opaque;
+    char desc[DESC_SIZE];
+    uint32_t cid;
+    char *p_name, *cid_str; 
+    size_t cid_str_size;
+
+    /* the descriptor offset = 0x200 */
+    if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
+        return 0;
+
+    if (parent) {
+        cid_str = "parentCID";
+        cid_str_size = sizeof("parentCID");
+    } else {
+        cid_str = "CID";
+        cid_str_size = sizeof("CID");
+    }
+
+    if ((p_name = strstr(desc,cid_str)) != 0) {
+        p_name += cid_str_size;
+        sscanf(p_name,"%x",&cid);
+    }
+
+    return cid;
+}
+
+static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
+{
+    BDRVVmdkState *s = bs->opaque;
+    char desc[DESC_SIZE], tmp_desc[DESC_SIZE];
+    char *p_name, *tmp_str;
+
+    /* the descriptor offset = 0x200 */
+    if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
+        return -1;
+
+    tmp_str = strstr(desc,"parentCID");
+    strcpy(tmp_desc, tmp_str);
+    if ((p_name = strstr(desc,"CID")) != 0) {
+        p_name += sizeof("CID");
+        sprintf(p_name,"%x\n",cid);
+        strcat(desc,tmp_desc);
+    }
+
+    if (bdrv_pwrite(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
+        return -1;
+    return 0;
+}
+
+static int vmdk_is_cid_valid(BlockDriverState *bs)
+{
+#ifdef CHECK_CID
+    BDRVVmdkState *s = bs->opaque;
+    BlockDriverState *p_bs = s->hd->backing_hd;
+    uint32_t cur_pcid;
+
+    if (p_bs) {
+        cur_pcid = vmdk_read_cid(p_bs,0);
+        if (s->parent_cid != cur_pcid)
+            // CID not valid
+            return 0;
+    }
+#endif
+    // CID valid
+    return 1;
+}
+
+static int vmdk_snapshot_create(const char *filename, const char *backing_file)
+{
+    int snp_fd, p_fd;
+    uint32_t p_cid;
+    char *p_name, *gd_buf, *rgd_buf; 
+    const char *real_filename, *temp_str;
+    VMDK4Header header;
+    uint32_t gde_entries, gd_size;
+    int64_t gd_offset, rgd_offset, capacity, gt_size;
+    char p_desc[DESC_SIZE], s_desc[DESC_SIZE], hdr[HEADER_SIZE];
+    char *desc_template =
+    "# Disk DescriptorFile\n"
+    "version=1\n"
+    "CID=%x\n"
+    "parentCID=%x\n"
+    "createType=\"monolithicSparse\"\n"
+    "parentFileNameHint=\"%s\"\n"
+    "\n"
+    "# Extent description\n"
+    "RW %lu SPARSE \"%s\"\n"
+    "\n"
+    "# The Disk Data Base \n"
+    "#DDB\n"
+    "\n";
+
+    snp_fd = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY | 
O_LARGEFILE, 0644);
+    if (snp_fd < 0)
+        return -1;
+    p_fd = open(backing_file, O_RDONLY | O_BINARY | O_LARGEFILE);
+    if (p_fd < 0) {
+        close(snp_fd);
+        return -1;
+    }
+
+    /* read the header */
+    if (lseek(p_fd, 0x0, SEEK_SET) == -1)
+        goto fail;
+    if (read(p_fd, hdr, HEADER_SIZE) != HEADER_SIZE)
+        goto fail;
+
+    /* write the header */
+    if (lseek(snp_fd, 0x0, SEEK_SET) == -1)
+        goto fail;
+    if (write(snp_fd, hdr, HEADER_SIZE) == -1)
+        goto fail;
+
+    memset(&header, 0, sizeof(header));
+    memcpy(&header,&hdr[4], sizeof(header)); // skip the VMDK4_MAGIC
+
+    ftruncate(snp_fd, header.grain_offset << 9);
+    /* the descriptor offset = 0x200 */
+    if (lseek(p_fd, 0x200, SEEK_SET) == -1)
+        goto fail;
+    if (read(p_fd, p_desc, DESC_SIZE) != DESC_SIZE)
+        goto fail;
+
+    if ((p_name = strstr(p_desc,"CID")) != 0) {
+        p_name += sizeof("CID");
+        sscanf(p_name,"%x",&p_cid);
+    }
+
+    real_filename = filename;
+    if ((temp_str = strrchr(real_filename, '\\')) != NULL)
+        real_filename = temp_str + 1;
+    if ((temp_str = strrchr(real_filename, '/')) != NULL)
+        real_filename = temp_str + 1;
+    if ((temp_str = strrchr(real_filename, ':')) != NULL)
+        real_filename = temp_str + 1;
+
+    sprintf(s_desc, desc_template, p_cid, p_cid, backing_file
+            , (uint32_t)header.capacity, real_filename);
+
+    /* write the descriptor */
+    if (lseek(snp_fd, 0x200, SEEK_SET) == -1)
+        goto fail;
+    if (write(snp_fd, s_desc, strlen(s_desc)) == -1)
+        goto fail;
+
+    gd_offset = header.gd_offset * SECTOR_SIZE;     // offset of GD table
+    rgd_offset = header.rgd_offset * SECTOR_SIZE;   // offset of RGD table
+    capacity = header.capacity * SECTOR_SIZE;       // Extent size
+    /*
+     * Each GDE span 32M disk, means:
+     * 512 GTE per GT, each GTE points to grain
+     */
+    gt_size = (int64_t)header.num_gtes_per_gte * header.granularity * 
SECTOR_SIZE;
+    if (!gt_size)
+        goto fail;
+    gde_entries = (uint32_t)(capacity / gt_size);  // number of gde/rgde 
+    gd_size = gde_entries * sizeof(uint32_t);
+
+    /* write RGD */
+    rgd_buf = qemu_malloc(gd_size);
+    if (!rgd_buf)
+        goto fail;
+    if (lseek(p_fd, rgd_offset, SEEK_SET) == -1)
+        goto fail_rgd;
+    if (read(p_fd, rgd_buf, gd_size) != gd_size)
+        goto fail_rgd;
+    if (lseek(snp_fd, rgd_offset, SEEK_SET) == -1)
+        goto fail_rgd;
+    if (write(snp_fd, rgd_buf, gd_size) == -1)
+        goto fail_rgd;
+    qemu_free(rgd_buf);
+
+    /* write GD */
+    gd_buf = qemu_malloc(gd_size);
+    if (!gd_buf)
+        goto fail_rgd;
+    if (lseek(p_fd, gd_offset, SEEK_SET) == -1)
+        goto fail_gd;
+    if (read(p_fd, gd_buf, gd_size) != gd_size)
+        goto fail_gd;
+    if (lseek(snp_fd, gd_offset, SEEK_SET) == -1)
+        goto fail_gd;
+    if (write(snp_fd, gd_buf, gd_size) == -1)
+        goto fail_gd;
+    qemu_free(gd_buf);
+
+    close(p_fd);
+    close(snp_fd);
+    return 0;
+
+    fail_gd:
+    qemu_free(gd_buf);
+    fail_rgd:   
+    qemu_free(rgd_buf);
+    fail:
+    close(p_fd);
+    close(snp_fd);
+    return -1;
+}
+
+static void vmdk_parent_close(BlockDriverState *bs)
+{
+    if (bs->backing_hd)
+        bdrv_close(bs->backing_hd);
+}
+
+
+static int vmdk_parent_open(BlockDriverState *bs, const char * filename)
+{
+    BDRVVmdkState *s = bs->opaque;
+    char *p_name; 
+    char desc[DESC_SIZE];
+    char parent_img_name[1024];
+
+    /* the descriptor offset = 0x200 */
+    if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
+        return -1;
+
+    if ((p_name = strstr(desc,"parentFileNameHint")) != 0) {
+        char *end_name;
+        struct stat file_buf;
+
+        p_name += sizeof("parentFileNameHint") + 1;
+        if ((end_name = strchr(p_name,'\"')) == 0)
+            return -1;
+                
+        strncpy(s->hd->backing_file, p_name, end_name - p_name);
+        if (stat(s->hd->backing_file, &file_buf) != 0) {
+            path_combine(parent_img_name, sizeof(parent_img_name),
+                         filename, s->hd->backing_file);
+        } else {
+            strcpy(parent_img_name, s->hd->backing_file);
+        }
+
+        s->hd->backing_hd = bdrv_new("");
+        if (!s->hd->backing_hd) {
+            failure:
+            bdrv_close(s->hd);
+            return -1;
+        }
+        if (bdrv_open(s->hd->backing_hd, parent_img_name, 0) < 0)
+            goto failure;
+    }
+
+    return 0;
+}
+
+static int vmdk_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    BDRVVmdkState *s = bs->opaque;
     uint32_t magic;
-    int l1_size;
-
-    fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
-    if (fd < 0) {
-        fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
-        if (fd < 0)
-            return -1;
-        bs->read_only = 1;
-    }
-    if (read(fd, &magic, sizeof(magic)) != sizeof(magic))
-        goto fail;
+    int l1_size, i, ret;
+
+    ret = bdrv_file_open(&s->hd, filename, flags);
+    if (ret < 0)
+        return ret;
+    if (bdrv_pread(s->hd, 0, &magic, sizeof(magic)) != sizeof(magic))
+        goto fail;
+
     magic = be32_to_cpu(magic);
     if (magic == VMDK3_MAGIC) {
         VMDK3Header header;
-        if (read(fd, &header, sizeof(header)) != 
-            sizeof(header))
+
+        if (bdrv_pread(s->hd, sizeof(magic), &header, sizeof(header)) != 
sizeof(header))
             goto fail;
         s->cluster_sectors = le32_to_cpu(header.granularity);
         s->l2_size = 1 << 9;
@@ -120,8 +373,8 @@ static int vmdk_open(BlockDriverState *b
         s->l1_entry_sectors = s->l2_size * s->cluster_sectors;
     } else if (magic == VMDK4_MAGIC) {
         VMDK4Header header;
-        
-        if (read(fd, &header, sizeof(header)) != sizeof(header))
+
+        if (bdrv_pread(s->hd, sizeof(magic), &header, sizeof(header)) != 
sizeof(header))
             goto fail;
         bs->total_sectors = le64_to_cpu(header.capacity);
         s->cluster_sectors = le64_to_cpu(header.granularity);
@@ -133,17 +386,22 @@ static int vmdk_open(BlockDriverState *b
             / s->l1_entry_sectors;
         s->l1_table_offset = le64_to_cpu(header.rgd_offset) << 9;
         s->l1_backup_table_offset = le64_to_cpu(header.gd_offset) << 9;
+
+        // try to open parent images, if exist
+        if (vmdk_parent_open(bs, filename) != 0)
+            goto fail;
+        // write the CID once after the image creation
+        s->parent_cid = vmdk_read_cid(bs,1);
     } else {
         goto fail;
     }
+
     /* read the L1 table */
     l1_size = s->l1_size * sizeof(uint32_t);
     s->l1_table = qemu_malloc(l1_size);
     if (!s->l1_table)
         goto fail;
-    if (lseek(fd, s->l1_table_offset, SEEK_SET) == -1)
-        goto fail;
-    if (read(fd, s->l1_table, l1_size) != l1_size)
+    if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, l1_size) != l1_size)
         goto fail;
     for(i = 0; i < s->l1_size; i++) {
         le32_to_cpus(&s->l1_table[i]);
@@ -153,9 +411,7 @@ static int vmdk_open(BlockDriverState *b
         s->l1_backup_table = qemu_malloc(l1_size);
         if (!s->l1_backup_table)
             goto fail;
-        if (lseek(fd, s->l1_backup_table_offset, SEEK_SET) == -1)
-            goto fail;
-        if (read(fd, s->l1_backup_table, l1_size) != l1_size)
+        if (bdrv_pread(s->hd, s->l1_backup_table_offset, s->l1_backup_table, 
l1_size) != l1_size)
             goto fail;
         for(i = 0; i < s->l1_size; i++) {
             le32_to_cpus(&s->l1_backup_table[i]);
@@ -165,14 +421,41 @@ static int vmdk_open(BlockDriverState *b
     s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint32_t));
     if (!s->l2_cache)
         goto fail;
-    s->fd = fd;
     return 0;
  fail:
     qemu_free(s->l1_backup_table);
     qemu_free(s->l1_table);
     qemu_free(s->l2_cache);
-    close(fd);
+    bdrv_delete(s->hd);
     return -1;
+}
+
+static uint64_t get_cluster_offset(BlockDriverState *bs, uint64_t offset, int 
allocate);
+
+static int get_whole_cluster(BlockDriverState *bs, uint64_t cluster_offset,
+                             uint64_t offset, int allocate)
+{
+    uint64_t parent_cluster_offset;
+    BDRVVmdkState *s = bs->opaque;
+    uint8_t  whole_grain[s->cluster_sectors*512];        // 128 sectors * 512 
bytes each = grain size 64KB
+
+    // we will be here if it's first write on non-exist grain(cluster).
+    // try to read from parent image, if exist
+    if (s->hd->backing_hd) {
+        BDRVVmdkState *ps = s->hd->backing_hd->opaque;
+
+        if (!vmdk_is_cid_valid(bs))
+            return -1;
+        parent_cluster_offset = get_cluster_offset(s->hd->backing_hd, offset, 
allocate);
+        if (bdrv_pread(ps->hd, parent_cluster_offset, whole_grain, 
ps->cluster_sectors*512) != 
+                                                                            
ps->cluster_sectors*512)
+            return -1;
+
+        if (bdrv_pwrite(s->hd, cluster_offset << 9, whole_grain, 
sizeof(whole_grain)) != 
+                                                                            
sizeof(whole_grain))
+            return -1;
+    }
+    return 0;
 }
 
 static uint64_t get_cluster_offset(BlockDriverState *bs,
@@ -212,34 +495,41 @@ static uint64_t get_cluster_offset(Block
         }
     }
     l2_table = s->l2_cache + (min_index * s->l2_size);
-    lseek(s->fd, (int64_t)l2_offset * 512, SEEK_SET);
-    if (read(s->fd, l2_table, s->l2_size * sizeof(uint32_t)) != 
-        s->l2_size * sizeof(uint32_t))
+    if (bdrv_pread(s->hd, (int64_t)l2_offset * 512, l2_table, s->l2_size * 
sizeof(uint32_t)) != 
+                                                                        
s->l2_size * sizeof(uint32_t))
         return 0;
+
     s->l2_cache_offsets[min_index] = l2_offset;
     s->l2_cache_counts[min_index] = 1;
  found:
     l2_index = ((offset >> 9) / s->cluster_sectors) % s->l2_size;
     cluster_offset = le32_to_cpu(l2_table[l2_index]);
     if (!cluster_offset) {
+        struct stat file_buf;
+
         if (!allocate)
             return 0;
-        cluster_offset = lseek(s->fd, 0, SEEK_END);
-        ftruncate(s->fd, cluster_offset + (s->cluster_sectors << 9));
+        stat(s->hd->filename, &file_buf);
+        cluster_offset = file_buf.st_size;
+        bdrv_truncate(s->hd, cluster_offset + (s->cluster_sectors << 9));
+
         cluster_offset >>= 9;
         /* update L2 table */
         tmp = cpu_to_le32(cluster_offset);
         l2_table[l2_index] = tmp;
-        lseek(s->fd, ((int64_t)l2_offset * 512) + (l2_index * sizeof(tmp)), 
SEEK_SET);
-        if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
+        if (bdrv_pwrite(s->hd, ((int64_t)l2_offset * 512) + (l2_index * 
sizeof(tmp)), 
+                        &tmp, sizeof(tmp)) != sizeof(tmp))
             return 0;
         /* update backup L2 table */
         if (s->l1_backup_table_offset != 0) {
             l2_offset = s->l1_backup_table[l1_index];
-            lseek(s->fd, ((int64_t)l2_offset * 512) + (l2_index * 
sizeof(tmp)), SEEK_SET);
-            if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
+            if (bdrv_pwrite(s->hd, ((int64_t)l2_offset * 512) + (l2_index * 
sizeof(tmp)), 
+                            &tmp, sizeof(tmp)) != sizeof(tmp))
                 return 0;
         }
+
+        if (get_whole_cluster(bs, cluster_offset, offset, allocate) == -1)
+            return 0;
     }
     cluster_offset <<= 9;
     return cluster_offset;
@@ -265,9 +555,9 @@ static int vmdk_read(BlockDriverState *b
                     uint8_t *buf, int nb_sectors)
 {
     BDRVVmdkState *s = bs->opaque;
-    int ret, index_in_cluster, n;
+    int index_in_cluster, n, ret;
     uint64_t cluster_offset;
-    
+
     while (nb_sectors > 0) {
         cluster_offset = get_cluster_offset(bs, sector_num << 9, 0);
         index_in_cluster = sector_num % s->cluster_sectors;
@@ -275,11 +565,18 @@ static int vmdk_read(BlockDriverState *b
         if (n > nb_sectors)
             n = nb_sectors;
         if (!cluster_offset) {
-            memset(buf, 0, 512 * n);
+            // try to read from parent image, if exist
+            if (s->hd->backing_hd) {
+                if (!vmdk_is_cid_valid(bs))
+                    return -1;
+                ret = bdrv_read(s->hd->backing_hd, sector_num, buf, n);
+                if (ret < 0)
+                    return -1;
+            } else {
+                memset(buf, 0, 512 * n);
+            }
         } else {
-            lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
-            ret = read(s->fd, buf, n * 512);
-            if (ret != n * 512) 
+            if(bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, 
n * 512) != n * 512)
                 return -1;
         }
         nb_sectors -= n;
@@ -293,8 +590,9 @@ static int vmdk_write(BlockDriverState *
                      const uint8_t *buf, int nb_sectors)
 {
     BDRVVmdkState *s = bs->opaque;
-    int ret, index_in_cluster, n;
+    int index_in_cluster, n;
     uint64_t cluster_offset;
+    static int cid_update = 0;
 
     while (nb_sectors > 0) {
         index_in_cluster = sector_num & (s->cluster_sectors - 1);
@@ -304,13 +602,17 @@ static int vmdk_write(BlockDriverState *
         cluster_offset = get_cluster_offset(bs, sector_num << 9, 1);
         if (!cluster_offset)
             return -1;
-        lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
-        ret = write(s->fd, buf, n * 512);
-        if (ret != n * 512)
+        if (bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n 
* 512) != n * 512)
             return -1;
         nb_sectors -= n;
         sector_num += n;
         buf += n * 512;
+
+        // update CID on the first write every time the virtual disk is opened
+        if (!cid_update) {
+            vmdk_write_cid(bs, time(NULL));
+            cid_update++;
+        }
     }
     return 0;
 }
@@ -334,7 +636,7 @@ static int vmdk_create(const char *filen
         "# The Disk Data Base \n"
         "#DDB\n"
         "\n"
-        "ddb.virtualHWVersion = \"3\"\n"
+        "ddb.virtualHWVersion = \"4\"\n"
         "ddb.geometry.cylinders = \"%lu\"\n"
         "ddb.geometry.heads = \"16\"\n"
         "ddb.geometry.sectors = \"63\"\n"
@@ -343,6 +645,9 @@ static int vmdk_create(const char *filen
     const char *real_filename, *temp_str;
 
     /* XXX: add support for backing file */
+    if (backing_file) {
+        return vmdk_snapshot_create(filename, backing_file);
+    }
 
     fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
               0644);
@@ -421,15 +726,18 @@ static void vmdk_close(BlockDriverState 
 static void vmdk_close(BlockDriverState *bs)
 {
     BDRVVmdkState *s = bs->opaque;
+
     qemu_free(s->l1_table);
     qemu_free(s->l2_cache);
-    close(s->fd);
+    bdrv_delete(s->hd);
+    // try to close parent image, if exist
+    vmdk_parent_close(s->hd);
 }
 
 static void vmdk_flush(BlockDriverState *bs)
 {
     BDRVVmdkState *s = bs->opaque;
-    fsync(s->fd);
+    bdrv_flush(s->hd);
 }
 
 BlockDriver bdrv_vmdk = {
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/block-vpc.c
--- a/tools/ioemu/block-vpc.c   Tue May 08 10:38:06 2007 +0100
+++ b/tools/ioemu/block-vpc.c   Wed May 09 14:17:15 2007 +0100
@@ -86,19 +86,16 @@ static int vpc_probe(const uint8_t *buf,
     return 0;
 }
 
-static int vpc_open(BlockDriverState *bs, const char *filename)
+static int vpc_open(BlockDriverState *bs, const char *filename, int flags)
 {
     BDRVVPCState *s = bs->opaque;
     int fd, i;
     struct vpc_subheader header;
 
-    fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
-    if (fd < 0) {
-        fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
-        if (fd < 0)
-            return -1;
-    }
-    
+    fd = open(filename, O_RDONLY | O_BINARY);
+    if (fd < 0)
+        return -1;
+
     bs->read_only = 1; // no write support yet
     
     s->fd = fd;
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/block-vvfat.c
--- a/tools/ioemu/block-vvfat.c Tue May 08 10:38:06 2007 +0100
+++ b/tools/ioemu/block-vvfat.c Wed May 09 14:17:15 2007 +0100
@@ -61,7 +61,7 @@ void nonono(const char* file, int line, 
     exit(-5);
 }
 #undef assert
-#define assert(a) if (!(a)) nonono(__FILE__, __LINE__, #a)
+#define assert(a) do {if (!(a)) nonono(__FILE__, __LINE__, #a);}while(0)
 #endif
 
 #else
@@ -351,13 +351,6 @@ typedef struct BDRVVVFATState {
 } BDRVVVFATState;
 
 
-static int vvfat_probe(const uint8_t *buf, int buf_size, const char *filename)
-{
-    if (strstart(filename, "fat:", NULL))
-       return 100;
-    return 0;
-}
-
 static void init_mbr(BDRVVVFATState* s)
 {
     /* TODO: if the files mbr.img and bootsect.img exist, use them */
@@ -954,18 +947,22 @@ static int init_directories(BDRVVVFATSta
     return 0;
 }
 
+#ifdef DEBUG
 static BDRVVVFATState *vvv = NULL;
+#endif
 
 static int enable_write_target(BDRVVVFATState *s);
 static int is_consistent(BDRVVVFATState *s);
 
-static int vvfat_open(BlockDriverState *bs, const char* dirname)
+static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags)
 {
     BDRVVVFATState *s = bs->opaque;
     int floppy = 0;
     int i;
 
+#ifdef DEBUG
     vvv = s;
+#endif
 
 DLOG(if (stderr == NULL) {
     stderr = fopen("vvfat.log", "a");
@@ -1040,7 +1037,6 @@ DLOG(if (stderr == NULL) {
        bs->heads = bs->cyls = bs->secs = 0;
 
     //    assert(is_consistent(s));
-
     return 0;
 }
 
@@ -2178,7 +2174,7 @@ static int commit_one_file(BDRVVVFATStat
     for (i = s->cluster_size; i < offset; i += s->cluster_size)
        c = modified_fat_get(s, c);
 
-    fd = open(mapping->path, O_RDWR | O_CREAT, 0666);
+    fd = open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
     if (fd < 0) {
        fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
                strerror(errno), errno);
@@ -2732,8 +2728,7 @@ static int enable_write_target(BDRVVVFAT
     array_init(&(s->commits), sizeof(commit_t));
 
     s->qcow_filename = malloc(1024);
-    strcpy(s->qcow_filename, "/tmp/vl.XXXXXX");
-    get_tmp_filename(s->qcow_filename, strlen(s->qcow_filename) + 1);
+    get_tmp_filename(s->qcow_filename, 1024);
     if (bdrv_create(&bdrv_qcow,
                s->qcow_filename, s->sector_count, "fat:", 0) < 0)
        return -1;
@@ -2767,14 +2762,15 @@ BlockDriver bdrv_vvfat = {
 BlockDriver bdrv_vvfat = {
     "vvfat",
     sizeof(BDRVVVFATState),
-    vvfat_probe,
+    NULL, /* no probe for protocols */
     vvfat_open,
     vvfat_read,
     vvfat_write,
     vvfat_close,
     NULL, /* ??? Not sure if we can do any meaningful flushing.  */
     NULL,
-    vvfat_is_allocated
+    vvfat_is_allocated,
+    .protocol_name = "fat",
 };
 
 #ifdef DEBUG
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/block.c
--- a/tools/ioemu/block.c       Tue May 08 10:38:06 2007 +0100
+++ b/tools/ioemu/block.c       Wed May 09 14:17:15 2007 +0100
@@ -32,85 +32,108 @@
 #include <sys/disk.h>
 #endif
 
-#ifdef CONFIG_COCOA
-#include <paths.h>
-#include <sys/param.h>
-#include <IOKit/IOKitLib.h>
-#include <IOKit/IOBSD.h>
-#include <IOKit/storage/IOMediaBSDClient.h>
-#include <IOKit/storage/IOMedia.h>
-#include <IOKit/storage/IOCDMedia.h>
-//#include <IOKit/storage/IOCDTypes.h>
-#include <CoreFoundation/CoreFoundation.h>
-#endif
-
-#ifdef __sun__
-#include <sys/dkio.h>
-#endif
+#define SECTOR_BITS 9
+#define SECTOR_SIZE (1 << SECTOR_BITS)
+
+typedef struct BlockDriverAIOCBSync {
+    BlockDriverAIOCB common;
+    QEMUBH *bh;
+    int ret;
+} BlockDriverAIOCBSync;
+
+static BlockDriverAIOCB *bdrv_aio_read_em(BlockDriverState *bs,
+        int64_t sector_num, uint8_t *buf, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque);
+static BlockDriverAIOCB *bdrv_aio_write_em(BlockDriverState *bs,
+        int64_t sector_num, const uint8_t *buf, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque);
+static void bdrv_aio_cancel_em(BlockDriverAIOCB *acb);
+static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num, 
+                        uint8_t *buf, int nb_sectors);
+static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
+                         const uint8_t *buf, int nb_sectors);
 
 static BlockDriverState *bdrv_first;
 static BlockDriver *first_drv;
 
-#ifdef CONFIG_COCOA
-static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator );
-static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, 
CFIndex maxPathSize );
-
-kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )
-{
-    kern_return_t       kernResult; 
-    mach_port_t     masterPort;
-    CFMutableDictionaryRef  classesToMatch;
-
-    kernResult = IOMasterPort( MACH_PORT_NULL, &masterPort );
-    if ( KERN_SUCCESS != kernResult ) {
-        printf( "IOMasterPort returned %d\n", kernResult );
-    }
-    
-    classesToMatch = IOServiceMatching( kIOCDMediaClass ); 
-    if ( classesToMatch == NULL ) {
-        printf( "IOServiceMatching returned a NULL dictionary.\n" );
+int path_is_absolute(const char *path)
+{
+    const char *p;
+#ifdef _WIN32
+    /* specific case for names like: "\\.\d:" */
+    if (*path == '/' || *path == '\\')
+        return 1;
+#endif
+    p = strchr(path, ':');
+    if (p)
+        p++;
+    else
+        p = path;
+#ifdef _WIN32
+    return (*p == '/' || *p == '\\');
+#else
+    return (*p == '/');
+#endif
+}
+
+/* if filename is absolute, just copy it to dest. Otherwise, build a
+   path to it by considering it is relative to base_path. URL are
+   supported. */
+void path_combine(char *dest, int dest_size,
+                  const char *base_path,
+                  const char *filename)
+{
+    const char *p, *p1;
+    int len;
+
+    if (dest_size <= 0)
+        return;
+    if (path_is_absolute(filename)) {
+        pstrcpy(dest, dest_size, filename);
     } else {
-    CFDictionarySetValue( classesToMatch, CFSTR( kIOMediaEjectableKey ), 
kCFBooleanTrue );
-    }
-    kernResult = IOServiceGetMatchingServices( masterPort, classesToMatch, 
mediaIterator );
-    if ( KERN_SUCCESS != kernResult )
-    {
-        printf( "IOServiceGetMatchingServices returned %d\n", kernResult );
-    }
-    
-    return kernResult;
-}
-
-kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex 
maxPathSize )
-{
-    io_object_t     nextMedia;
-    kern_return_t   kernResult = KERN_FAILURE;
-    *bsdPath = '\0';
-    nextMedia = IOIteratorNext( mediaIterator );
-    if ( nextMedia )
-    {
-        CFTypeRef   bsdPathAsCFString;
-    bsdPathAsCFString = IORegistryEntryCreateCFProperty( nextMedia, CFSTR( 
kIOBSDNameKey ), kCFAllocatorDefault, 0 );
-        if ( bsdPathAsCFString ) {
-            size_t devPathLength;
-            strcpy( bsdPath, _PATH_DEV );
-            strcat( bsdPath, "r" );
-            devPathLength = strlen( bsdPath );
-            if ( CFStringGetCString( bsdPathAsCFString, bsdPath + 
devPathLength, maxPathSize - devPathLength, kCFStringEncodingASCII ) ) {
-                kernResult = KERN_SUCCESS;
-            }
-            CFRelease( bsdPathAsCFString );
-        }
-        IOObjectRelease( nextMedia );
-    }
-    
-    return kernResult;
-}
-
+        p = strchr(base_path, ':');
+        if (p)
+            p++;
+        else
+            p = base_path;
+        p1 = strrchr(base_path, '/');
+#ifdef _WIN32
+        {
+            const char *p2;
+            p2 = strrchr(base_path, '\\');
+            if (!p1 || p2 > p1)
+                p1 = p2;
+        }
 #endif
+        if (p1)
+            p1++;
+        else
+            p1 = base_path;
+        if (p1 > p)
+            p = p1;
+        len = p - base_path;
+        if (len > dest_size - 1)
+            len = dest_size - 1;
+        memcpy(dest, base_path, len);
+        dest[len] = '\0';
+        pstrcat(dest, dest_size, filename);
+    }
+}
+
 
 void bdrv_register(BlockDriver *bdrv)
 {
+    if (!bdrv->bdrv_aio_read) {
+        /* add AIO emulation layer */
+        bdrv->bdrv_aio_read = bdrv_aio_read_em;
+        bdrv->bdrv_aio_write = bdrv_aio_write_em;
+        bdrv->bdrv_aio_cancel = bdrv_aio_cancel_em;
+        bdrv->aiocb_size = sizeof(BlockDriverAIOCBSync);
+    } else if (!bdrv->bdrv_read && !bdrv->bdrv_pread) {
+        /* add synchronous IO emulation layer */
+        bdrv->bdrv_read = bdrv_read_em;
+        bdrv->bdrv_write = bdrv_write_em;
+    }
     bdrv->next = first_drv;
     first_drv = bdrv;
 }
@@ -156,14 +179,10 @@ int bdrv_create(BlockDriver *drv,
 #ifdef _WIN32
 void get_tmp_filename(char *filename, int size)
 {
-    char* p = strrchr(filename, '/');
-
-    if (p == NULL)
-       return;
-
-    /* XXX: find a better function */
-    tmpnam(p);
-    *p = '/';
+    char temp_dir[MAX_PATH];
+    
+    GetTempPath(MAX_PATH, temp_dir);
+    GetTempFileName(temp_dir, "qem", 0, filename);
 }
 #else
 void get_tmp_filename(char *filename, int size)
@@ -176,101 +195,141 @@ void get_tmp_filename(char *filename, in
 }
 #endif
 
+#ifdef _WIN32
+static int is_windows_drive_prefix(const char *filename)
+{
+    return (((filename[0] >= 'a' && filename[0] <= 'z') ||
+             (filename[0] >= 'A' && filename[0] <= 'Z')) &&
+            filename[1] == ':');
+}
+    
+static int is_windows_drive(const char *filename)
+{
+    if (is_windows_drive_prefix(filename) && 
+        filename[2] == '\0')
+        return 1;
+    if (strstart(filename, "\\\\.\\", NULL) ||
+        strstart(filename, "//./", NULL))
+        return 1;
+    return 0;
+}
+#endif
+
+static BlockDriver *find_protocol(const char *filename)
+{
+    BlockDriver *drv1;
+    char protocol[128];
+    int len;
+    const char *p;
+
+#ifdef _WIN32
+    if (is_windows_drive(filename) ||
+        is_windows_drive_prefix(filename))
+        return &bdrv_raw;
+#endif
+    p = strchr(filename, ':');
+    if (!p)
+        return &bdrv_raw;
+    len = p - filename;
+    if (len > sizeof(protocol) - 1)
+        len = sizeof(protocol) - 1;
+    memcpy(protocol, filename, len);
+    protocol[len] = '\0';
+    for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {
+        if (drv1->protocol_name && 
+            !strcmp(drv1->protocol_name, protocol))
+            return drv1;
+    }
+    return NULL;
+}
+
 /* XXX: force raw format if block or character device ? It would
    simplify the BSD case */
 static BlockDriver *find_image_format(const char *filename)
 {
-    int fd, ret, score, score_max;
+    int ret, score, score_max;
     BlockDriver *drv1, *drv;
-    uint8_t *buf;
-    size_t bufsize = 1024;
-
-    fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
-    if (fd < 0) {
-        buf = NULL;
-        ret = 0;
-    } else {
-#ifdef DIOCGSECTORSIZE
-        {
-            unsigned int sectorsize = 512;
-            if (!ioctl(fd, DIOCGSECTORSIZE, &sectorsize) &&
-                sectorsize > bufsize)
-                bufsize = sectorsize;
-        }
+    uint8_t buf[2048];
+    BlockDriverState *bs;
+    
+    /* detect host devices. By convention, /dev/cdrom[N] is always
+       recognized as a host CDROM */
+    if (strstart(filename, "/dev/cdrom", NULL))
+        return &bdrv_host_device;
+#ifdef _WIN32
+    if (is_windows_drive(filename))
+        return &bdrv_host_device;
+#else
+    {
+        struct stat st;
+        if (stat(filename, &st) >= 0 && 
+            (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode))) {
+            return &bdrv_host_device;
+        }
+    }
 #endif
-#ifdef CONFIG_COCOA
-        u_int32_t   blockSize = 512;
-        if ( !ioctl( fd, DKIOCGETBLOCKSIZE, &blockSize ) && blockSize > 
bufsize) {
-            bufsize = blockSize;
-        }
-#endif
-        buf = qemu_malloc(bufsize);
-        if (!buf)
-            return NULL;
-        ret = read(fd, buf, bufsize);
-        if (ret < 0) {
-            close(fd);
-            qemu_free(buf);
-            return NULL;
-        }
-        close(fd);
-    }
     
-    drv = NULL;
+    drv = find_protocol(filename);
+    /* no need to test disk image formats for vvfat */
+    if (drv == &bdrv_vvfat)
+        return drv;
+
+    ret = bdrv_file_open(&bs, filename, BDRV_O_RDONLY);
+    if (ret < 0)
+        return NULL;
+    ret = bdrv_pread(bs, 0, buf, sizeof(buf));
+    bdrv_delete(bs);
+    if (ret < 0) {
+        return NULL;
+    }
+
     score_max = 0;
     for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {
-        score = drv1->bdrv_probe(buf, ret, filename);
-        if (score > score_max) {
-            score_max = score;
-            drv = drv1;
-        }
-    }
-    qemu_free(buf);
+        if (drv1->bdrv_probe) {
+            score = drv1->bdrv_probe(buf, ret, filename);
+            if (score > score_max) {
+                score_max = score;
+                drv = drv1;
+            }
+        }
+    }
     return drv;
 }
 
-int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot)
-{
-#ifdef CONFIG_COCOA
-    if ( strncmp( filename, "/dev/cdrom", 10 ) == 0 ) {
-        kern_return_t kernResult;
-        io_iterator_t mediaIterator;
-        char bsdPath[ MAXPATHLEN ];
-        int fd;
- 
-        kernResult = FindEjectableCDMedia( &mediaIterator );
-        kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) );
-    
-        if ( bsdPath[ 0 ] != '\0' ) {
-            strcat(bsdPath,"s0");
-            /* some CDs don't have a partition 0 */
-            fd = open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE);
-            if (fd < 0) {
-                bsdPath[strlen(bsdPath)-1] = '1';
-            } else {
-                close(fd);
-            }
-            filename = bsdPath;
-        }
-        
-        if ( mediaIterator )
-            IOObjectRelease( mediaIterator );
-    }
-#endif
-    return bdrv_open2(bs, filename, snapshot, NULL);
-}
-
-int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot,
+int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags)
+{
+    BlockDriverState *bs;
+    int ret;
+
+    bs = bdrv_new("");
+    if (!bs)
+        return -ENOMEM;
+    ret = bdrv_open2(bs, filename, flags | BDRV_O_FILE, NULL);
+    if (ret < 0) {
+        bdrv_delete(bs);
+        return ret;
+    }
+    *pbs = bs;
+    return 0;
+}
+
+int bdrv_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    return bdrv_open2(bs, filename, flags, NULL);
+}
+
+int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
                BlockDriver *drv)
 {
-    int ret;
+    int ret, open_flags;
     char tmp_filename[1024];
+    char backing_filename[1024];
     
     bs->read_only = 0;
     bs->is_temporary = 0;
     bs->encrypted = 0;
 
-    if (snapshot) {
+    if (flags & BDRV_O_SNAPSHOT) {
         BlockDriverState *bs1;
         int64_t total_size;
         
@@ -280,19 +339,19 @@ int bdrv_open2(BlockDriverState *bs, con
         /* if there is a backing file, use it */
         bs1 = bdrv_new("");
         if (!bs1) {
-            return -1;
+            return -ENOMEM;
         }
         if (bdrv_open(bs1, filename, 0) < 0) {
             bdrv_delete(bs1);
             return -1;
         }
-        total_size = bs1->total_sectors;
+        total_size = bdrv_getlength(bs1) >> SECTOR_BITS;
         bdrv_delete(bs1);
         
         get_tmp_filename(tmp_filename, sizeof(tmp_filename));
-        /* XXX: use cow for linux as it is more efficient ? */
-        if (bdrv_create(&bdrv_qcow, tmp_filename, 
-                        total_size, filename, 0) < 0) {
+        realpath(filename, backing_filename);
+        if (bdrv_create(&bdrv_qcow2, tmp_filename, 
+                        total_size, backing_filename, 0) < 0) {
             return -1;
         }
         filename = tmp_filename;
@@ -300,41 +359,62 @@ int bdrv_open2(BlockDriverState *bs, con
     }
 
     pstrcpy(bs->filename, sizeof(bs->filename), filename);
-    if (!drv) {
-        drv = find_image_format(filename);
+    if (flags & BDRV_O_FILE) {
+        drv = find_protocol(filename);
         if (!drv)
-            return -1;
+            return -ENOENT;
+    } else {
+        if (!drv) {
+            drv = find_image_format(filename);
+            if (!drv)
+                return -1;
+        }
     }
     bs->drv = drv;
     bs->opaque = qemu_mallocz(drv->instance_size);
     if (bs->opaque == NULL && drv->instance_size > 0)
         return -1;
-    
-    ret = drv->bdrv_open(bs, filename);
+    /* Note: for compatibility, we open disk image files as RDWR, and
+       RDONLY as fallback */
+    if (!(flags & BDRV_O_FILE))
+        open_flags = BDRV_O_RDWR;
+    else
+        open_flags = flags & ~(BDRV_O_FILE | BDRV_O_SNAPSHOT);
+    ret = drv->bdrv_open(bs, filename, open_flags);
+    if (ret == -EACCES && !(flags & BDRV_O_FILE)) {
+        ret = drv->bdrv_open(bs, filename, BDRV_O_RDONLY);
+        bs->read_only = 1;
+    }
     if (ret < 0) {
         qemu_free(bs->opaque);
-        return -1;
+        bs->opaque = NULL;
+        bs->drv = NULL;
+        return ret;
+    }
+    if (drv->bdrv_getlength) {
+        bs->total_sectors = bdrv_getlength(bs) >> SECTOR_BITS;
     }
 #ifndef _WIN32
     if (bs->is_temporary) {
         unlink(filename);
     }
 #endif
-    if (bs->backing_file[0] != '\0' && drv->bdrv_is_allocated) {
+    if (bs->backing_file[0] != '\0') {
         /* if there is a backing file, use it */
         bs->backing_hd = bdrv_new("");
         if (!bs->backing_hd) {
         fail:
             bdrv_close(bs);
-            return -1;
-        }
-        if (bdrv_open(bs->backing_hd, bs->backing_file, 0) < 0)
+            return -ENOMEM;
+        }
+        path_combine(backing_filename, sizeof(backing_filename),
+                     filename, bs->backing_file);
+        if (bdrv_open(bs->backing_hd, backing_filename, 0) < 0)
             goto fail;
     }
 
-    bs->inserted = 1;
-
     /* call the change callback */
+    bs->media_changed = 1;
     if (bs->change_cb)
         bs->change_cb(bs->change_opaque);
 
@@ -343,7 +423,7 @@ int bdrv_open2(BlockDriverState *bs, con
 
 void bdrv_close(BlockDriverState *bs)
 {
-    if (bs->inserted) {
+    if (bs->drv) {
         if (bs->backing_hd)
             bdrv_delete(bs->backing_hd);
         bs->drv->bdrv_close(bs);
@@ -355,9 +435,9 @@ void bdrv_close(BlockDriverState *bs)
 #endif
         bs->opaque = NULL;
         bs->drv = NULL;
-        bs->inserted = 0;
 
         /* call the change callback */
+        bs->media_changed = 1;
         if (bs->change_cb)
             bs->change_cb(bs->change_opaque);
     }
@@ -373,12 +453,13 @@ void bdrv_delete(BlockDriverState *bs)
 /* commit COW file into the raw image */
 int bdrv_commit(BlockDriverState *bs)
 {
-    int64_t i;
+    BlockDriver *drv = bs->drv;
+    int64_t i, total_sectors;
     int n, j;
     unsigned char sector[512];
 
-    if (!bs->inserted)
-        return -ENOENT;
+    if (!drv)
+        return -ENOMEDIUM;
 
     if (bs->read_only) {
        return -EACCES;
@@ -388,8 +469,9 @@ int bdrv_commit(BlockDriverState *bs)
        return -ENOTSUP;
     }
 
-    for (i = 0; i < bs->total_sectors;) {
-        if (bs->drv->bdrv_is_allocated(bs, i, 65536, &n)) {
+    total_sectors = bdrv_getlength(bs) >> SECTOR_BITS;
+    for (i = 0; i < total_sectors;) {
+        if (drv->bdrv_is_allocated(bs, i, 65536, &n)) {
             for(j = 0; j < n; j++) {
                 if (bdrv_read(bs, i, sector, 1) != 0) {
                     return -EIO;
@@ -405,72 +487,241 @@ int bdrv_commit(BlockDriverState *bs)
         }
     }
 
-    if (bs->drv->bdrv_make_empty)
-       return bs->drv->bdrv_make_empty(bs);
+    if (drv->bdrv_make_empty)
+       return drv->bdrv_make_empty(bs);
 
     return 0;
 }
 
-/* return -1 if error */
+/* return < 0 if error. See bdrv_write() for the return codes */
 int bdrv_read(BlockDriverState *bs, int64_t sector_num, 
               uint8_t *buf, int nb_sectors)
 {
-    int ret, n;
-    BlockDriver *drv = bs->drv;
-
-    if (!bs->inserted)
-        return -1;
+    BlockDriver *drv = bs->drv;
+
+    if (!drv)
+        return -ENOMEDIUM;
+
     if (sector_num < 0)
-       return -1;
-
-    while (nb_sectors > 0) {
-        if (sector_num == 0 && bs->boot_sector_enabled) {
+       return -EINVAL;
+
+    if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
             memcpy(buf, bs->boot_sector_data, 512);
-            n = 1;
-        } else if (bs->backing_hd) {
-            if (drv->bdrv_is_allocated(bs, sector_num, nb_sectors, &n)) {
-                ret = drv->bdrv_read(bs, sector_num, buf, n);
-                if (ret < 0)
-                    return -1;
-            } else {
-                /* read from the base image */
-                ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
-                if (ret < 0)
-                    return -1;
-            }
-        } else {
-            ret = drv->bdrv_read(bs, sector_num, buf, nb_sectors);
-            if (ret < 0)
-                return -1;
-            /* no need to loop */
-            break;
-        }
-        nb_sectors -= n;
-        sector_num += n;
-        buf += n * 512;
-    }
-    return 0;
-}
-
-/* return -1 if error */
+        sector_num++;
+        nb_sectors--;
+        buf += 512;
+        if (nb_sectors == 0)
+            return 0;
+    }
+    if (drv->bdrv_pread) {
+        int ret, len;
+        len = nb_sectors * 512;
+        ret = drv->bdrv_pread(bs, sector_num * 512, buf, len);
+        if (ret < 0)
+            return ret;
+        else if (ret != len)
+            return -EINVAL;
+        else
+            return 0;
+    } else {
+        return drv->bdrv_read(bs, sector_num, buf, nb_sectors);
+    }
+}
+
+/* Return < 0 if error. Important errors are: 
+  -EIO         generic I/O error (may happen for all errors)
+  -ENOMEDIUM   No media inserted.
+  -EINVAL      Invalid sector number or nb_sectors
+  -EACCES      Trying to write a read-only device
+*/
 int bdrv_write(BlockDriverState *bs, int64_t sector_num, 
                const uint8_t *buf, int nb_sectors)
 {
-    if (!bs->inserted)
-        return -1;
+    BlockDriver *drv = bs->drv;
+    if (!bs->drv)
+        return -ENOMEDIUM;
     if (bs->read_only)
-        return -1;
+        return -EACCES;
     if (sector_num < 0)
-       return -1;
+       return -EINVAL;
     if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
         memcpy(bs->boot_sector_data, buf, 512);   
     }
-    return bs->drv->bdrv_write(bs, sector_num, buf, nb_sectors);
-}
-
+    if (drv->bdrv_pwrite) {
+        int ret, len;
+        len = nb_sectors * 512;
+        ret = drv->bdrv_pwrite(bs, sector_num * 512, buf, len);
+        if (ret < 0)
+            return ret;
+        else if (ret != len)
+            return -EIO;
+        else
+            return 0;
+    } else {
+        return drv->bdrv_write(bs, sector_num, buf, nb_sectors);
+    }
+}
+
+static int bdrv_pread_em(BlockDriverState *bs, int64_t offset, 
+                         uint8_t *buf, int count1)
+{
+    uint8_t tmp_buf[SECTOR_SIZE];
+    int len, nb_sectors, count;
+    int64_t sector_num;
+
+    count = count1;
+    /* first read to align to sector start */
+    len = (SECTOR_SIZE - offset) & (SECTOR_SIZE - 1);
+    if (len > count)
+        len = count;
+    sector_num = offset >> SECTOR_BITS;
+    if (len > 0) {
+        if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
+            return -EIO;
+        memcpy(buf, tmp_buf + (offset & (SECTOR_SIZE - 1)), len);
+        count -= len;
+        if (count == 0)
+            return count1;
+        sector_num++;
+        buf += len;
+    }
+
+    /* read the sectors "in place" */
+    nb_sectors = count >> SECTOR_BITS;
+    if (nb_sectors > 0) {
+        if (bdrv_read(bs, sector_num, buf, nb_sectors) < 0)
+            return -EIO;
+        sector_num += nb_sectors;
+        len = nb_sectors << SECTOR_BITS;
+        buf += len;
+        count -= len;
+    }
+
+    /* add data from the last sector */
+    if (count > 0) {
+        if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
+            return -EIO;
+        memcpy(buf, tmp_buf, count);
+    }
+    return count1;
+}
+
+static int bdrv_pwrite_em(BlockDriverState *bs, int64_t offset, 
+                          const uint8_t *buf, int count1)
+{
+    uint8_t tmp_buf[SECTOR_SIZE];
+    int len, nb_sectors, count;
+    int64_t sector_num;
+
+    count = count1;
+    /* first write to align to sector start */
+    len = (SECTOR_SIZE - offset) & (SECTOR_SIZE - 1);
+    if (len > count)
+        len = count;
+    sector_num = offset >> SECTOR_BITS;
+    if (len > 0) {
+        if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
+            return -EIO;
+        memcpy(tmp_buf + (offset & (SECTOR_SIZE - 1)), buf, len);
+        if (bdrv_write(bs, sector_num, tmp_buf, 1) < 0)
+            return -EIO;
+        count -= len;
+        if (count == 0)
+            return count1;
+        sector_num++;
+        buf += len;
+    }
+
+    /* write the sectors "in place" */
+    nb_sectors = count >> SECTOR_BITS;
+    if (nb_sectors > 0) {
+        if (bdrv_write(bs, sector_num, buf, nb_sectors) < 0)
+            return -EIO;
+        sector_num += nb_sectors;
+        len = nb_sectors << SECTOR_BITS;
+        buf += len;
+        count -= len;
+    }
+
+    /* add data from the last sector */
+    if (count > 0) {
+        if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
+            return -EIO;
+        memcpy(tmp_buf, buf, count);
+        if (bdrv_write(bs, sector_num, tmp_buf, 1) < 0)
+            return -EIO;
+    }
+    return count1;
+}
+
+/**
+ * Read with byte offsets (needed only for file protocols) 
+ */
+int bdrv_pread(BlockDriverState *bs, int64_t offset, 
+               void *buf1, int count1)
+{
+    BlockDriver *drv = bs->drv;
+
+    if (!drv)
+        return -ENOMEDIUM;
+    if (!drv->bdrv_pread)
+        return bdrv_pread_em(bs, offset, buf1, count1);
+    return drv->bdrv_pread(bs, offset, buf1, count1);
+}
+
+/** 
+ * Write with byte offsets (needed only for file protocols) 
+ */
+int bdrv_pwrite(BlockDriverState *bs, int64_t offset, 
+                const void *buf1, int count1)
+{
+    BlockDriver *drv = bs->drv;
+
+    if (!drv)
+        return -ENOMEDIUM;
+    if (!drv->bdrv_pwrite)
+        return bdrv_pwrite_em(bs, offset, buf1, count1);
+    return drv->bdrv_pwrite(bs, offset, buf1, count1);
+}
+
+/**
+ * Truncate file to 'offset' bytes (needed only for file protocols)
+ */
+int bdrv_truncate(BlockDriverState *bs, int64_t offset)
+{
+    BlockDriver *drv = bs->drv;
+    if (!drv)
+        return -ENOMEDIUM;
+    if (!drv->bdrv_truncate)
+        return -ENOTSUP;
+    return drv->bdrv_truncate(bs, offset);
+}
+
+/**
+ * Length of a file in bytes. Return < 0 if error or unknown.
+ */
+int64_t bdrv_getlength(BlockDriverState *bs)
+{
+    BlockDriver *drv = bs->drv;
+    if (!drv)
+        return -ENOMEDIUM;
+    if (!drv->bdrv_getlength) {
+        /* legacy mode */
+        return bs->total_sectors * SECTOR_SIZE;
+    }
+    return drv->bdrv_getlength(bs);
+}
+
+/* return 0 as number of sectors if no device present or error */
 void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr)
 {
-    *nb_sectors_ptr = bs->total_sectors;
+    int64_t length;
+    length = bdrv_getlength(bs);
+    if (length < 0)
+        length = 0;
+    else
+        length = length >> SECTOR_BITS;
+    *nb_sectors_ptr = length;
 }
 
 /* force a given boot sector. */
@@ -531,21 +782,7 @@ int bdrv_is_read_only(BlockDriverState *
     return bs->read_only;
 }
 
-int bdrv_is_inserted(BlockDriverState *bs)
-{
-    return bs->inserted;
-}
-
-int bdrv_is_locked(BlockDriverState *bs)
-{
-    return bs->locked;
-}
-
-void bdrv_set_locked(BlockDriverState *bs, int locked)
-{
-    bs->locked = locked;
-}
-
+/* XXX: no longer used */
 void bdrv_set_change_cb(BlockDriverState *bs, 
                         void (*change_cb)(void *opaque), void *opaque)
 {
@@ -577,7 +814,7 @@ int bdrv_set_key(BlockDriverState *bs, c
 
 void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size)
 {
-    if (!bs->inserted || !bs->drv) {
+    if (!bs->drv) {
         buf[0] = '\0';
     } else {
         pstrcpy(buf, buf_size, bs->drv->format_name);
@@ -649,10 +886,13 @@ void bdrv_info(void)
         if (bs->removable) {
             term_printf(" locked=%d", bs->locked);
         }
-        if (bs->inserted) {
-            term_printf(" file=%s", bs->filename);
-            if (bs->backing_file[0] != '\0')
-                term_printf(" backing_file=%s", bs->backing_file);
+        if (bs->drv) {
+            term_printf(" file=");
+           term_print_filename(bs->filename);
+            if (bs->backing_file[0] != '\0') {
+                term_printf(" backing_file=");
+               term_print_filename(bs->backing_file);
+           }
             term_printf(" ro=%d", bs->read_only);
             term_printf(" drv=%s", bs->drv->format_name);
             if (bs->encrypted)
@@ -664,192 +904,337 @@ void bdrv_info(void)
     }
 }
 
+void bdrv_get_backing_filename(BlockDriverState *bs, 
+                               char *filename, int filename_size)
+{
+    if (!bs->backing_hd) {
+        pstrcpy(filename, filename_size, "");
+    } else {
+        pstrcpy(filename, filename_size, bs->backing_file);
+    }
+}
+
+int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num, 
+                          const uint8_t *buf, int nb_sectors)
+{
+    BlockDriver *drv = bs->drv;
+    if (!drv)
+        return -ENOMEDIUM;
+    if (!drv->bdrv_write_compressed)
+        return -ENOTSUP;
+    return drv->bdrv_write_compressed(bs, sector_num, buf, nb_sectors);
+}
+    
+int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
+{
+    BlockDriver *drv = bs->drv;
+    if (!drv)
+        return -ENOMEDIUM;
+    if (!drv->bdrv_get_info)
+        return -ENOTSUP;
+    memset(bdi, 0, sizeof(*bdi));
+    return drv->bdrv_get_info(bs, bdi);
+}
+
 /**************************************************************/
-/* RAW block driver */
-
-typedef struct BDRVRawState {
-    int fd;
-} BDRVRawState;
-
-static int raw_probe(const uint8_t *buf, int buf_size, const char *filename)
-{
-    return 1; /* maybe */
-}
-
-static int raw_open(BlockDriverState *bs, const char *filename)
-{
-    BDRVRawState *s = bs->opaque;
-    int fd;
-    int64_t size;
-#ifdef _BSD
-    struct stat sb;
+/* handling of snapshots */
+
+int bdrv_snapshot_create(BlockDriverState *bs, 
+                         QEMUSnapshotInfo *sn_info)
+{
+    BlockDriver *drv = bs->drv;
+    if (!drv)
+        return -ENOMEDIUM;
+    if (!drv->bdrv_snapshot_create)
+        return -ENOTSUP;
+    return drv->bdrv_snapshot_create(bs, sn_info);
+}
+
+int bdrv_snapshot_goto(BlockDriverState *bs, 
+                       const char *snapshot_id)
+{
+    BlockDriver *drv = bs->drv;
+    if (!drv)
+        return -ENOMEDIUM;
+    if (!drv->bdrv_snapshot_goto)
+        return -ENOTSUP;
+    return drv->bdrv_snapshot_goto(bs, snapshot_id);
+}
+
+int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
+{
+    BlockDriver *drv = bs->drv;
+    if (!drv)
+        return -ENOMEDIUM;
+    if (!drv->bdrv_snapshot_delete)
+        return -ENOTSUP;
+    return drv->bdrv_snapshot_delete(bs, snapshot_id);
+}
+
+int bdrv_snapshot_list(BlockDriverState *bs, 
+                       QEMUSnapshotInfo **psn_info)
+{
+    BlockDriver *drv = bs->drv;
+    if (!drv)
+        return -ENOMEDIUM;
+    if (!drv->bdrv_snapshot_list)
+        return -ENOTSUP;
+    return drv->bdrv_snapshot_list(bs, psn_info);
+}
+
+#define NB_SUFFIXES 4
+
+char *get_human_readable_size(char *buf, int buf_size, int64_t size)
+{
+    static const char suffixes[NB_SUFFIXES] = "KMGT";
+    int64_t base;
+    int i;
+
+    if (size <= 999) {
+        snprintf(buf, buf_size, "%" PRId64, size);
+    } else {
+        base = 1024;
+        for(i = 0; i < NB_SUFFIXES; i++) {
+            if (size < (10 * base)) {
+                snprintf(buf, buf_size, "%0.1f%c", 
+                         (double)size / base,
+                         suffixes[i]);
+                break;
+            } else if (size < (1000 * base) || i == (NB_SUFFIXES - 1)) {
+                snprintf(buf, buf_size, "%" PRId64 "%c", 
+                         ((size + (base >> 1)) / base),
+                         suffixes[i]);
+                break;
+            }
+            base = base * 1024;
+        }
+    }
+    return buf;
+}
+
+char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn)
+{
+    char buf1[128], date_buf[128], clock_buf[128];
+#ifdef _WIN32
+    struct tm *ptm;
+#else
+    struct tm tm;
 #endif
-#ifdef __sun__
-    struct dk_minfo minfo;
-    int rv;
+    time_t ti;
+    int64_t secs;
+
+    if (!sn) {
+        snprintf(buf, buf_size, 
+                 "%-10s%-20s%7s%20s%15s", 
+                 "ID", "TAG", "VM SIZE", "DATE", "VM CLOCK");
+    } else {
+        ti = sn->date_sec;
+#ifdef _WIN32
+        ptm = localtime(&ti);
+        strftime(date_buf, sizeof(date_buf),
+                 "%Y-%m-%d %H:%M:%S", ptm);
+#else
+        localtime_r(&ti, &tm);
+        strftime(date_buf, sizeof(date_buf),
+                 "%Y-%m-%d %H:%M:%S", &tm);
 #endif
-
-    fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
-    if (fd < 0) {
-        fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
-        if (fd < 0)
-            return -1;
-        bs->read_only = 1;
-    }
-#ifdef _BSD
-    if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) {
-#ifdef DIOCGMEDIASIZE
-       if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size))
-#endif
-#ifdef CONFIG_COCOA
-        size = LONG_LONG_MAX;
+        secs = sn->vm_clock_nsec / 1000000000;
+        snprintf(clock_buf, sizeof(clock_buf),
+                 "%02d:%02d:%02d.%03d",
+                 (int)(secs / 3600),
+                 (int)((secs / 60) % 60),
+                 (int)(secs % 60), 
+                 (int)((sn->vm_clock_nsec / 1000000) % 1000));
+        snprintf(buf, buf_size,
+                 "%-10s%-20s%7s%20s%15s", 
+                 sn->id_str, sn->name,
+                 get_human_readable_size(buf1, sizeof(buf1), 
sn->vm_state_size),
+                 date_buf,
+                 clock_buf);
+    }
+    return buf;
+}
+
+
+/**************************************************************/
+/* async I/Os */
+
+BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num,
+                                uint8_t *buf, int nb_sectors,
+                                BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BlockDriver *drv = bs->drv;
+
+    if (!drv)
+        return NULL;
+    
+    /* XXX: we assume that nb_sectors == 0 is suppored by the async read */
+    if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
+        memcpy(buf, bs->boot_sector_data, 512);
+        sector_num++;
+        nb_sectors--;
+        buf += 512;
+    }
+
+    return drv->bdrv_aio_read(bs, sector_num, buf, nb_sectors, cb, opaque);
+}
+
+BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num,
+                                 const uint8_t *buf, int nb_sectors,
+                                 BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BlockDriver *drv = bs->drv;
+
+    if (!drv)
+        return NULL;
+    if (bs->read_only)
+        return NULL;
+    if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
+        memcpy(bs->boot_sector_data, buf, 512);   
+    }
+
+    return drv->bdrv_aio_write(bs, sector_num, buf, nb_sectors, cb, opaque);
+}
+
+void bdrv_aio_cancel(BlockDriverAIOCB *acb)
+{
+    BlockDriver *drv = acb->bs->drv;
+
+    drv->bdrv_aio_cancel(acb);
+}
+
+
+/**************************************************************/
+/* async block device emulation */
+
+#ifdef QEMU_TOOL
+static BlockDriverAIOCB *bdrv_aio_read_em(BlockDriverState *bs,
+        int64_t sector_num, uint8_t *buf, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    int ret;
+    ret = bdrv_read(bs, sector_num, buf, nb_sectors);
+    cb(opaque, ret);
+    return NULL;
+}
+
+static BlockDriverAIOCB *bdrv_aio_write_em(BlockDriverState *bs,
+        int64_t sector_num, const uint8_t *buf, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    int ret;
+    ret = bdrv_write(bs, sector_num, buf, nb_sectors);
+    cb(opaque, ret);
+    return NULL;
+}
+
+static void bdrv_aio_cancel_em(BlockDriverAIOCB *acb)
+{
+}
 #else
-        size = lseek(fd, 0LL, SEEK_END);
-#endif
-    } else
-#endif
-#ifdef __sun__
-    /*
-     * use the DKIOCGMEDIAINFO ioctl to read the size.
-     */
-    rv = ioctl ( fd, DKIOCGMEDIAINFO, &minfo );
-    if ( rv != -1 ) {
-        size = minfo.dki_lbsize * minfo.dki_capacity;
-    } else /* there are reports that lseek on some devices
-              fails, but irc discussion said that contingency
-              on contingency was overkill */
-#endif
-    {
-        size = lseek(fd, 0, SEEK_END);
-    }
-#ifdef _WIN32
-    /* On Windows hosts it can happen that we're unable to get file size
-       for CD-ROM raw device (it's inherent limitation of the CDFS driver). */
-    if (size == -1)
-        size = LONG_LONG_MAX;
-#endif
-    bs->total_sectors = size / 512;
-    s->fd = fd;
-    return 0;
-}
-
-static int raw_read(BlockDriverState *bs, int64_t sector_num, 
-                    uint8_t *buf, int nb_sectors)
-{
-    BDRVRawState *s = bs->opaque;
+static void bdrv_aio_bh_cb(void *opaque)
+{
+    BlockDriverAIOCBSync *acb = opaque;
+    acb->common.cb(acb->common.opaque, acb->ret);
+    qemu_aio_release(acb);
+}
+
+static BlockDriverAIOCB *bdrv_aio_read_em(BlockDriverState *bs,
+        int64_t sector_num, uint8_t *buf, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BlockDriverAIOCBSync *acb;
     int ret;
-    
-    lseek(s->fd, sector_num * 512, SEEK_SET);
-    ret = read(s->fd, buf, nb_sectors * 512);
-    if (ret != nb_sectors * 512) 
+
+    acb = qemu_aio_get(bs, cb, opaque);
+    if (!acb->bh)
+        acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb);
+    ret = bdrv_read(bs, sector_num, buf, nb_sectors);
+    acb->ret = ret;
+    qemu_bh_schedule(acb->bh);
+    return &acb->common;
+}
+
+static BlockDriverAIOCB *bdrv_aio_write_em(BlockDriverState *bs,
+        int64_t sector_num, const uint8_t *buf, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BlockDriverAIOCBSync *acb;
+    int ret;
+
+    acb = qemu_aio_get(bs, cb, opaque);
+    if (!acb->bh)
+        acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb);
+    ret = bdrv_write(bs, sector_num, buf, nb_sectors);
+    acb->ret = ret;
+    qemu_bh_schedule(acb->bh);
+    return &acb->common;
+}
+
+static void bdrv_aio_cancel_em(BlockDriverAIOCB *blockacb)
+{
+    BlockDriverAIOCBSync *acb = (BlockDriverAIOCBSync *)blockacb;
+    qemu_bh_cancel(acb->bh);
+    qemu_aio_release(acb);
+}
+#endif /* !QEMU_TOOL */
+
+/**************************************************************/
+/* sync block device emulation */
+
+static void bdrv_rw_em_cb(void *opaque, int ret)
+{
+    *(int *)opaque = ret;
+}
+
+#define NOT_DONE 0x7fffffff
+
+static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num, 
+                        uint8_t *buf, int nb_sectors)
+{
+    int async_ret;
+    BlockDriverAIOCB *acb;
+
+    async_ret = NOT_DONE;
+    qemu_aio_wait_start();
+    acb = bdrv_aio_read(bs, sector_num, buf, nb_sectors, 
+                        bdrv_rw_em_cb, &async_ret);
+    if (acb == NULL) {
+        qemu_aio_wait_end();
         return -1;
-    return 0;
-}
-
-static int raw_write(BlockDriverState *bs, int64_t sector_num, 
-                     const uint8_t *buf, int nb_sectors)
-{
-    BDRVRawState *s = bs->opaque;
-    int ret;
-    
-    lseek(s->fd, sector_num * 512, SEEK_SET);
-    ret = write(s->fd, buf, nb_sectors * 512);
-    if (ret != nb_sectors * 512) 
+    }
+    while (async_ret == NOT_DONE) {
+        qemu_aio_wait();
+    }
+    qemu_aio_wait_end();
+    return async_ret;
+}
+
+static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
+                         const uint8_t *buf, int nb_sectors)
+{
+    int async_ret;
+    BlockDriverAIOCB *acb;
+
+    async_ret = NOT_DONE;
+    qemu_aio_wait_start();
+    acb = bdrv_aio_write(bs, sector_num, buf, nb_sectors, 
+                         bdrv_rw_em_cb, &async_ret);
+    if (acb == NULL) {
+        qemu_aio_wait_end();
         return -1;
-    return 0;
-}
-
-static void raw_close(BlockDriverState *bs)
-{
-    BDRVRawState *s = bs->opaque;
-    bs->total_sectors = 0;
-    close(s->fd);
-}
-
-#ifdef _WIN32
-#include <windows.h>
-#include <winioctl.h>
-
-int qemu_ftruncate64(int fd, int64_t length)
-{
-    LARGE_INTEGER li;
-    LONG high;
-    HANDLE h;
-    BOOL res;
-
-    if ((GetVersion() & 0x80000000UL) && (length >> 32) != 0)
-       return -1;
-
-    h = (HANDLE)_get_osfhandle(fd);
-
-    /* get current position, ftruncate do not change position */
-    li.HighPart = 0;
-    li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT);
-    if (li.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
-       return -1;
-
-    high = length >> 32;
-    if (!SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN))
-       return -1;
-    res = SetEndOfFile(h);
-
-    /* back to old position */
-    SetFilePointer(h, li.LowPart, &li.HighPart, FILE_BEGIN);
-    return res ? 0 : -1;
-}
-
-static int set_sparse(int fd)
-{
-    DWORD returned;
-    return (int) DeviceIoControl((HANDLE)_get_osfhandle(fd), FSCTL_SET_SPARSE,
-                                NULL, 0, NULL, 0, &returned, NULL);
-}
-#else
-static inline int set_sparse(int fd)
-{
-    return 1;
-}
-#endif
-
-static int raw_create(const char *filename, int64_t total_size,
-                      const char *backing_file, int flags)
-{
-    int fd;
-
-    if (flags || backing_file)
-        return -ENOTSUP;
-
-    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 
-              0644);
-    if (fd < 0)
-        return -EIO;
-    set_sparse(fd);
-    ftruncate(fd, total_size * 512);
-    close(fd);
-    return 0;
-}
-
-static void raw_flush(BlockDriverState *bs)
-{
-    BDRVRawState *s = bs->opaque;
-    fsync(s->fd);
-}
-
-BlockDriver bdrv_raw = {
-    "raw",
-    sizeof(BDRVRawState),
-    raw_probe,
-    raw_open,
-    raw_read,
-    raw_write,
-    raw_close,
-    raw_create,
-    raw_flush,
-};
+    }
+    while (async_ret == NOT_DONE) {
+        qemu_aio_wait();
+    }
+    qemu_aio_wait_end();
+    return async_ret;
+}
 
 void bdrv_init(void)
 {
     bdrv_register(&bdrv_raw);
+    bdrv_register(&bdrv_host_device);
 #ifndef _WIN32
     bdrv_register(&bdrv_cow);
 #endif
@@ -860,4 +1245,109 @@ void bdrv_init(void)
     bdrv_register(&bdrv_bochs);
     bdrv_register(&bdrv_vpc);
     bdrv_register(&bdrv_vvfat);
-}
+    bdrv_register(&bdrv_qcow2);
+}
+
+void *qemu_aio_get(BlockDriverState *bs, BlockDriverCompletionFunc *cb,
+                   void *opaque)
+{
+    BlockDriver *drv;
+    BlockDriverAIOCB *acb;
+
+    drv = bs->drv;
+    if (drv->free_aiocb) {
+        acb = drv->free_aiocb;
+        drv->free_aiocb = acb->next;
+    } else {
+        acb = qemu_mallocz(drv->aiocb_size);
+        if (!acb)
+            return NULL;
+    }
+    acb->bs = bs;
+    acb->cb = cb;
+    acb->opaque = opaque;
+    return acb;
+}
+
+void qemu_aio_release(void *p)
+{
+    BlockDriverAIOCB *acb = p;
+    BlockDriver *drv = acb->bs->drv;
+    acb->next = drv->free_aiocb;
+    drv->free_aiocb = acb;
+}
+
+/**************************************************************/
+/* removable device support */
+
+/**
+ * Return TRUE if the media is present
+ */
+int bdrv_is_inserted(BlockDriverState *bs)
+{
+    BlockDriver *drv = bs->drv;
+    int ret;
+    if (!drv)
+        return 0;
+    if (!drv->bdrv_is_inserted)
+        return 1;
+    ret = drv->bdrv_is_inserted(bs);
+    return ret;
+}
+
+/**
+ * Return TRUE if the media changed since the last call to this
+ * function. It is currently only used for floppy disks 
+ */
+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 eject_flag is TRUE, eject the media. Otherwise, close the tray
+ */
+void bdrv_eject(BlockDriverState *bs, int eject_flag)
+{
+    BlockDriver *drv = bs->drv;
+    int ret;
+
+    if (!drv || !drv->bdrv_eject) {
+        ret = -ENOTSUP;
+    } else {
+        ret = drv->bdrv_eject(bs, eject_flag);
+    }
+    if (ret == -ENOTSUP) {
+        if (eject_flag)
+            bdrv_close(bs);
+    }
+}
+
+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).
+ */
+void bdrv_set_locked(BlockDriverState *bs, int locked)
+{
+    BlockDriver *drv = bs->drv;
+
+    bs->locked = locked;
+    if (drv && drv->bdrv_set_locked) {
+        drv->bdrv_set_locked(bs, locked);
+    }
+}
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/block_int.h
--- a/tools/ioemu/block_int.h   Tue May 08 10:38:06 2007 +0100
+++ b/tools/ioemu/block_int.h   Wed May 09 14:17:15 2007 +0100
@@ -28,7 +28,7 @@ struct BlockDriver {
     const char *format_name;
     int instance_size;
     int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename);
-    int (*bdrv_open)(BlockDriverState *bs, const char *filename);
+    int (*bdrv_open)(BlockDriverState *bs, const char *filename, int flags);
     int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num, 
                      uint8_t *buf, int nb_sectors);
     int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num, 
@@ -41,13 +41,49 @@ struct BlockDriver {
                              int nb_sectors, int *pnum);
     int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
     int (*bdrv_make_empty)(BlockDriverState *bs);
+    /* aio */
+    BlockDriverAIOCB *(*bdrv_aio_read)(BlockDriverState *bs,
+        int64_t sector_num, uint8_t *buf, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque);
+    BlockDriverAIOCB *(*bdrv_aio_write)(BlockDriverState *bs,
+        int64_t sector_num, const uint8_t *buf, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque);
+    void (*bdrv_aio_cancel)(BlockDriverAIOCB *acb);
+    int aiocb_size;
+
+    const char *protocol_name;
+    int (*bdrv_pread)(BlockDriverState *bs, int64_t offset, 
+                      uint8_t *buf, int count);
+    int (*bdrv_pwrite)(BlockDriverState *bs, int64_t offset, 
+                       const uint8_t *buf, int count);
+    int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset);
+    int64_t (*bdrv_getlength)(BlockDriverState *bs);
+    int (*bdrv_write_compressed)(BlockDriverState *bs, int64_t sector_num, 
+                                 const uint8_t *buf, int nb_sectors);
+
+    int (*bdrv_snapshot_create)(BlockDriverState *bs, 
+                                QEMUSnapshotInfo *sn_info);
+    int (*bdrv_snapshot_goto)(BlockDriverState *bs, 
+                              const char *snapshot_id);
+    int (*bdrv_snapshot_delete)(BlockDriverState *bs, const char *snapshot_id);
+    int (*bdrv_snapshot_list)(BlockDriverState *bs, 
+                              QEMUSnapshotInfo **psn_info);
+    int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi);
+
+    /* removable device specific */
+    int (*bdrv_is_inserted)(BlockDriverState *bs);
+    int (*bdrv_media_changed)(BlockDriverState *bs);
+    int (*bdrv_eject)(BlockDriverState *bs, int eject_flag);
+    int (*bdrv_set_locked)(BlockDriverState *bs, int locked);
+    
+    BlockDriverAIOCB *free_aiocb;
     struct BlockDriver *next;
 };
 
 struct BlockDriverState {
-    int64_t total_sectors;
+    int64_t total_sectors; /* if we are reading a disk image, give its
+                              size in sectors */
     int read_only; /* if true, the media is read only */
-    int inserted; /* if true, the media is present */
     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 */
@@ -55,7 +91,7 @@ struct BlockDriverState {
     void (*change_cb)(void *opaque);
     void *change_opaque;
 
-    BlockDriver *drv;
+    BlockDriver *drv; /* NULL means no media */
     void *opaque;
 
     int boot_sector_enabled;
@@ -65,8 +101,12 @@ struct BlockDriverState {
     char backing_file[1024]; /* if non zero, the image is a diff of
                                 this file image */
     int is_temporary;
-    
+    int media_changed;
+
     BlockDriverState *backing_hd;
+    /* async read/write emulation */
+
+    void *sync_aiocb;
     
     /* NOTE: the following infos are only hints for real hardware
        drivers. They are not used by the block driver */
@@ -76,6 +116,17 @@ struct BlockDriverState {
     BlockDriverState *next;
 };
 
+struct BlockDriverAIOCB {
+    BlockDriverState *bs;
+    BlockDriverCompletionFunc *cb;
+    void *opaque;
+    BlockDriverAIOCB *next;
+};
+
 void get_tmp_filename(char *filename, int size);
 
+void *qemu_aio_get(BlockDriverState *bs, BlockDriverCompletionFunc *cb,
+                   void *opaque);
+void qemu_aio_release(void *p);
+
 #endif /* BLOCK_INT_H */
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/check_ops.sh
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ioemu/check_ops.sh  Wed May 09 14:17:15 2007 +0100
@@ -0,0 +1,47 @@
+#! /bin/sh
+# Script to check for duplicate function prologues in op.o
+# Typically this indicates missing FORCE_RET();
+# This script does not detect other errors that may be present.
+
+# Usage: check_ops.sh [-m machine] [op.o]
+#   machine and op.o are guessed if not specified.
+
+if [ "x$1" = "x-m" ]; then
+  machine=$2
+  shift 2
+else
+  machine=`uname -m`
+fi
+if [ -z "$1" ]; then
+  for f in `find . -name op.o`; do
+    /bin/sh "$0" -m $machine $f
+  done
+  exit 0
+fi
+
+case $machine in
+  i?86)
+    ret='\tret'
+    ;;
+  x86_64)
+    ret='\tretq'
+    ;;
+  arm)
+    ret='\tldm.*pc'
+    ;;
+  ppc* | powerpc*)
+    ret='\tblr'
+    ;;
+  mips*)
+    ret='\tjr.*ra'
+    ;;
+  *)
+    echo "Unknown machine `uname -m`"
+    ;;
+esac
+echo $1
+# op_exit_tb causes false positives on some hosts.
+${CROSS}objdump -dr $1  | \
+  sed -e '/>:$\|'"$ret"'/!d' -e 's/.*<\(.*\)>:/~\1:/' -e 's/.*'"$ret"'.*/!/' | 
\
+  sed -e ':1;N;s/\n//;t1' | sed -e 's/~/\n/g' | grep -v '^op_exit_tb' | \
+  grep '^op_.*!!'
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/configure
--- a/tools/ioemu/configure     Tue May 08 10:38:06 2007 +0100
+++ b/tools/ioemu/configure     Wed May 09 14:17:15 2007 +0100
@@ -22,6 +22,8 @@ libdir="lib"
 libdir="lib"
 cross_prefix=""
 cc="gcc"
+gcc3_search="yes"
+gcc3_list="gcc-3.4 gcc34 gcc-3.3 gcc33 gcc-3.2 gcc32"
 host_cc="gcc"
 ar="ar"
 make="make"
@@ -89,14 +91,13 @@ linux="no"
 linux="no"
 kqemu="no"
 profiler="no"
-kernel_path=""
 cocoa="no"
 check_gfx="yes"
 check_gcc="no"
 softmmu="yes"
-user="no"
+linux_user="no"
+darwin_user="no"
 build_docs="no"
-build_acpi_tables="no"
 uname_release=""
 
 # OS specific
@@ -104,7 +105,7 @@ case $targetos in
 case $targetos in
 CYGWIN*)
 mingw32="yes"
-CFLAGS="-O2 -mno-cygwin"
+OS_CFLAGS="-mno-cygwin"
 ;;
 MINGW32*)
 mingw32="yes"
@@ -127,6 +128,10 @@ Darwin)
 Darwin)
 bsd="yes"
 darwin="yes"
+darwin_user="yes"
+cocoa="yes"
+coreaudio="yes"
+OS_CFLAGS="-mdynamic-no-pic"
 ;;
 SunOS)
 solaris="yes"
@@ -134,7 +139,7 @@ solaris="yes"
 *)
 oss="yes"
 linux="yes"
-user="yes"
+linux_user="yes"
 if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
     kqemu="yes"
 fi
@@ -151,6 +156,11 @@ if [ "$solaris" = "yes" ] ; then
     make="gmake"
     install="ginstall"
     solarisrev=`uname -r | cut -f2 -d.`
+    if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
+        if test "$solarisrev" -gt 10 ; then
+            kqemu="yes"
+        fi
+    fi
 fi
 
 # find source path
@@ -181,6 +191,7 @@ for opt do
   --cross-prefix=*) cross_prefix="$optarg"
   ;;
   --cc=*) cc="$optarg"
+  gcc3_search="no"
   ;;
   --host-cc=*) host_cc="$optarg"
   ;;
@@ -224,8 +235,6 @@ for opt do
   ;;
   --enable-profiler) profiler="yes"
   ;;
-  --kernel-path=*) kernel_path="$optarg"
-  ;;
   --enable-cocoa) cocoa="yes" ; coreaudio="yes" ; sdl="no"
   ;;
   --disable-gcc-check) check_gcc="no"
@@ -234,21 +243,22 @@ for opt do
   ;;
   --enable-system) softmmu="yes"
   ;;
-  --disable-user) user="no"
-  ;;
-  --enable-user) user="yes"
+  --disable-linux-user) linux_user="no"
+  ;;
+  --enable-linux-user) linux_user="yes"
+  ;;
+  --disable-darwin-user) darwin_user="no"
+  ;;
+  --enable-darwin-user) darwin_user="yes"
   ;;
   --enable-uname-release=*) uname_release="$optarg"
-  ;;
-  --enable-iasl) build_acpi_tables="yes"
   ;;
   esac
 done
 
-# Checking for CFLAGS
-if test -z "$CFLAGS"; then
-    CFLAGS="-O2"
-fi
+# default flags for all hosts
+CFLAGS="$CFLAGS -Wall -O2 -g -fno-strict-aliasing"
+LDFLAGS="$LDFLAGS -g"
 
 if test x"$show_help" = x"yes" ; then
 cat << EOF
@@ -266,7 +276,6 @@ echo ""
 echo ""
 echo "kqemu kernel acceleration support:"
 echo "  --disable-kqemu          disable kqemu support"
-echo "  --kernel-path=PATH       set the kernel path (configure probes it)"
 echo ""
 echo "Advanced options (experts only):"
 echo "  --source-path=PATH       path of source code [$source_path]"
@@ -285,14 +294,15 @@ echo "  --enabled-dsound         enable 
 echo "  --enabled-dsound         enable DirectSound audio driver"
 echo "  --enable-system          enable all system emulation targets"
 echo "  --disable-system         disable all system emulation targets"
-echo "  --enable-user            enable all linux usermode emulation targets"
-echo "  --disable-user           disable all linux usermode emulation targets"
+echo "  --enable-linux-user      enable all linux usermode emulation targets"
+echo "  --disable-linux-user     disable all linux usermode emulation targets"
+echo "  --enable-darwin-user     enable all darwin usermode emulation targets"
+echo "  --disable-darwin-user    disable all darwin usermode emulation targets"
 echo "  --fmod-lib               path to FMOD library"
 echo "  --fmod-inc               path to FMOD includes"
 echo "  --enable-uname-release=R Return R for uname -r in usermode emulation"
-echo "  --enable-iasl            compilation of ACPI tables with the IASL 
compiler"
 echo ""
-echo "NOTE: The object files are build at the place where configure is 
launched"
+echo "NOTE: The object files are built at the place where configure is 
launched"
 exit 1
 fi
 
@@ -318,6 +328,45 @@ if test "$mingw32" = "yes" ; then
     oss="no"
     if [ "$cpu" = "i386" ] ; then
         kqemu="yes"
+    fi
+fi
+
+# Check for gcc4, error if pre-gcc4 
+if test "$check_gcc" = "yes" ; then
+    cat > $TMPC <<EOF
+#if __GNUC__ < 4
+#error gcc3
+#endif
+int main(){return 0;}
+EOF
+    check_cc() {
+       which "$1" >&/dev/null
+       return $?
+    }
+
+    if "$cc" -o $TMPE $TMPC 2>/dev/null ; then
+       echo "WARNING: \"$cc\" looks like gcc 4.x"
+       found_compat_cc="no"
+       if test "$gcc3_search" = "yes" ; then
+           echo "Looking for gcc 3.x"
+           for compat_cc in $gcc3_list ; do
+               if check_cc "$compat_cc" ; then
+                   echo "Found \"$compat_cc\""
+                   cc="$compat_cc"
+                   found_compat_cc="yes"
+                   break
+               fi
+           done
+           if test "$found_compat_cc" = "no" ; then
+               echo "gcc 3.x not found!"
+           fi
+       fi
+       if test "$found_compat_cc" = "no" ; then
+           echo "QEMU is known to have problems when compiled with gcc 4.x"
+           echo "It is recommended that you use gcc 3.x to build QEMU"
+           echo "To use this compiler anyway, configure with 
--disable-gcc-check"
+           exit 1;
+       fi
     fi
 fi
 
@@ -368,8 +417,12 @@ if test -z "$target_list" ; then
         target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu 
mips-softmmu mipsel-softmmu arm-softmmu"
     fi
 # the following are Linux specific
-    if [ "$user" = "yes" ] ; then
-        target_list="i386-user arm-user armeb-user sparc-user ppc-user 
mips-user mipsel-user $target_list"
+    if [ "$linux_user" = "yes" ] ; then
+        target_list="i386-linux-user arm-linux-user armeb-linux-user 
sparc-linux-user ppc-linux-user mips-linux-user mipsel-linux-user 
m68k-linux-user $target_list"
+    fi
+# the following are Darwin specific
+    if [ "$darwin_user" = "yes" ] ; then
+        target_list="i386-darwin-user ppc-darwin-user $target_list"
     fi
 # the i386-dm target
     target_list="i386-dm"
@@ -427,23 +480,6 @@ if $cc -fno-reorder-blocks -fno-optimize
    have_gcc3_options="yes"
 fi
 
-# Check for gcc4, error if pre-gcc4 
-if test "$check_gcc" = "yes" ; then
-    cat > $TMPC <<EOF
-#if __GNUC__ < 4
-#error gcc3
-#endif
-int main(){return 0;}
-EOF
-    if $cc -o $TMPO $TMPC 2>/dev/null ; then
-        echo "ERROR: \"$cc\" looks like gcc 4.x"
-        echo "QEMU is known to have problems when compiled with gcc 4.x"
-        echo "It is recommended that you use gcc 3.x to build QEMU"
-        echo "To use this compiler anyway, configure with --disable-gcc-check"
-        exit 1;
-    fi
-fi
-
 ##########################################
 # SDL probe
 
@@ -472,7 +508,9 @@ if test "$_sdlversion" -lt 121 ; then
 if test "$_sdlversion" -lt 121 ; then
 sdl_too_old=yes
 else
-sdl=yes
+ if test "$cocoa" = "no" ; then
+   sdl=yes
+ fi
 fi
 
 # static link with sdl ?
@@ -493,7 +531,33 @@ fi # sdl compile test
 fi # sdl compile test
 
 fi # cross compilation
+
+else
+ # Make sure to disable cocoa if sdl was set
+ if test "$sdl" = "yes" ; then
+   cocoa="no"
+   coreaudio="no"
+ fi
 fi # -z $sdl
+
+##########################################
+# alsa sound support libraries
+
+if test "$alsa" = "yes" ; then
+  cat > $TMPC << EOF
+#include <alsa/asoundlib.h>
+int main(void) { snd_pcm_t **handle; return snd_pcm_close(*handle); }
+EOF
+  if $cc -o $TMPE $TMPC -lasound 2> /dev/null ; then
+    :
+  else
+    echo
+    echo "Error: Could not find alsa"
+    echo "Make sure to have the alsa libs and headers installed."
+    echo
+    exit 1
+  fi
+fi
 
 # Check if tools are available to build documentation.
 if [ -x "`which texi2html`" ] && [ -x "`which pod2man`" ]; then
@@ -600,6 +664,7 @@ echo "HOST_CC=$host_cc" >> $config_mak
 echo "HOST_CC=$host_cc" >> $config_mak
 echo "AR=$ar" >> $config_mak
 echo "STRIP=$strip -s -R .comment -R .note" >> $config_mak
+echo "OS_CFLAGS=$OS_CFLAGS" >> $config_mak
 echo "CFLAGS=$CFLAGS" >> $config_mak
 echo "LDFLAGS=$LDFLAGS" >> $config_mak
 echo "EXESUF=$EXESUF" >> $config_mak
@@ -719,9 +784,6 @@ if [ "$build_docs" = "yes" ] ; then
 if [ "$build_docs" = "yes" ] ; then
   echo "BUILD_DOCS=yes" >> $config_mak
 fi
-if [ "$build_acpi_tables" = "yes" ] ; then
-  echo "BUILD_ACPI_TABLES=yes" >> $config_mak
-fi
 
 # XXX: suppress that
 if [ "$bsd" = "yes" ] ; then
@@ -745,6 +807,7 @@ target_bigendian="no"
 [ "$target_cpu" = "ppc64" ] && target_bigendian=yes
 [ "$target_cpu" = "mips" ] && target_bigendian=yes
 [ "$target_cpu" = "sh4eb" ] && target_bigendian=yes
+[ "$target_cpu" = "m68k" ] && target_bigendian=yes
 target_softmmu="no"
 if expr $target : '.*-softmmu' > /dev/null ; then
   target_softmmu="yes"
@@ -756,11 +819,21 @@ if expr $target : '.*-user' > /dev/null 
   target_user_only="yes"
 fi
 
+target_linux_user="no"
+if expr $target : '.*-linux-user' > /dev/null ; then
+  target_linux_user="yes"
+fi
+
+target_darwin_user="no"
+if expr $target : '.*-darwin-user' > /dev/null ; then
+  target_darwin_user="yes"
+fi
+
 #echo "Creating $config_mak, $config_h and $target_dir/Makefile"
 
 mkdir -p $target_dir
 mkdir -p $target_dir/fpu
-if test "$target" = "arm-user" -o "$target" = "armeb-user" ; then
+if test "$target" = "arm-linux-user" -o "$target" = "armeb-linux-user" ; then
   mkdir -p $target_dir/nwfpe
 fi
 if test "$target_user_only" = "no" ; then
@@ -840,6 +913,11 @@ elif test "$target_cpu" = "sh4" -o "$tar
   echo "#define TARGET_ARCH \"sh4\"" >> $config_h
   echo "#define TARGET_SH4 1" >> $config_h
   bflt="yes"
+elif test "$target_cpu" = "m68k" ; then
+  echo "TARGET_ARCH=m68k" >> $config_mak
+  echo "#define TARGET_ARCH \"m68k\"" >> $config_h
+  echo "#define TARGET_M68K 1" >> $config_h
+  bflt="yes"
 else
   echo "Unsupported target CPU"
   exit 1
@@ -856,12 +934,19 @@ if test "$target_user_only" = "yes" ; th
   echo "CONFIG_USER_ONLY=yes" >> $config_mak
   echo "#define CONFIG_USER_ONLY 1" >> $config_h
 fi
-
+if test "$target_linux_user" = "yes" ; then
+  echo "CONFIG_LINUX_USER=yes" >> $config_mak
+  echo "#define CONFIG_LINUX_USER 1" >> $config_h
+fi
+if test "$target_darwin_user" = "yes" ; then
+  echo "CONFIG_DARWIN_USER=yes" >> $config_mak
+  echo "#define CONFIG_DARWIN_USER 1" >> $config_h
+fi
 if expr $target : '.*-dm' > /dev/null ; then
   echo "#define CONFIG_DM 1" >> $config_h
 fi
 
-if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" -o "$target_cpu" = 
"sparc" -o "$target_cpu" = "sparc64"; then
+if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" -o "$target_cpu" = 
"sparc" -o "$target_cpu" = "sparc64" -o "$target_cpu" = "m68k"; then
   echo "CONFIG_SOFTFLOAT=yes" >> $config_mak
   echo "#define CONFIG_SOFTFLOAT 1" >> $config_h
 fi
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/console.c
--- a/tools/ioemu/console.c     Tue May 08 10:38:06 2007 +0100
+++ b/tools/ioemu/console.c     Wed May 09 14:17:15 2007 +0100
@@ -121,6 +121,7 @@ struct TextConsole {
     int total_height;
     int backscroll_height;
     int x, y;
+    int x_saved, y_saved;
     int y_displayed;
     int y_base;
     TextAttributes t_attrib_default; /* default text attributes */
@@ -131,10 +132,7 @@ struct TextConsole {
     int esc_params[MAX_ESC_PARAMS];
     int nb_esc_params;
 
-    /* kbd read handler */
-    IOCanRWHandler *fd_can_read; 
-    IOReadHandler *fd_read;
-    void *fd_opaque;
+    CharDriverState *chr;
     /* fifo for key pressed */
     QEMUFIFO out_fifo;
     uint8_t out_fifo_buf[16];
@@ -147,7 +145,7 @@ static int nb_consoles = 0;
 
 void vga_hw_update(void)
 {
-    if (active_console->hw_update)
+    if (active_console && active_console->hw_update)
         active_console->hw_update(active_console->hw);
 }
 
@@ -659,10 +657,6 @@ static void console_handle_escape(TextCo
 {
     int i;
 
-    if (s->nb_esc_params == 0) { /* ESC[m sets all attributes to default */
-        s->t_attrib = s->t_attrib_default;
-        return;
-    }
     for (i=0; i<s->nb_esc_params; i++) {
         switch (s->esc_params[i]) {
             case 0: /* reset all console attributes to default */
@@ -752,10 +746,21 @@ static void console_handle_escape(TextCo
     }
 }
 
+static void console_clear_xy(TextConsole *s, int x, int y)
+{
+    int y1 = (s->y_base + y) % s->total_height;
+    TextCell *c = &s->cells[y1 * s->width + x];
+    c->ch = ' ';
+    c->t_attrib = s->t_attrib_default;
+    c++;
+    update_xy(s, x, y);
+}
+
 static void console_putchar(TextConsole *s, int ch)
 {
     TextCell *c;
-    int y1, i, x;
+    int y1, i;
+    int x, y;
 
     switch(s->state) {
     case TTY_STATE_NORM:
@@ -781,20 +786,31 @@ static void console_putchar(TextConsole 
         case '\a':  /* alert aka. bell */
             /* TODO: has to be implemented */
             break;
+        case 14:
+            /* SI (shift in), character set 0 (ignored) */
+            break;
+        case 15:
+            /* SO (shift out), character set 1 (ignored) */
+            break;
         case 27:    /* esc (introducing an escape sequence) */
             s->state = TTY_STATE_ESC;
             break;
         default:
+            if (s->x >= s->width - 1) {
+                break;
+            }
             y1 = (s->y_base + s->y) % s->total_height;
             c = &s->cells[y1 * s->width + s->x];
             c->ch = ch;
             c->t_attrib = s->t_attrib;
             update_xy(s, s->x, s->y);
             s->x++;
+#if 0 /* line wrap disabled */
             if (s->x >= s->width) {
                 s->x = 0;
                 console_put_lf(s);
             }
+#endif
             break;
         }
         break;
@@ -818,31 +834,149 @@ static void console_putchar(TextConsole 
             s->nb_esc_params++;
             if (ch == ';')
                 break;
+#ifdef DEBUG_CONSOLE
+            fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
+                    s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
+#endif
             s->state = TTY_STATE_NORM;
             switch(ch) {
+            case 'A':
+                /* move cursor up */
+                if (s->esc_params[0] == 0) {
+                    s->esc_params[0] = 1;
+                }
+                s->y -= s->esc_params[0];
+                if (s->y < 0) {
+                    s->y = 0;
+                }
+                break;
+            case 'B':
+                /* move cursor down */
+                if (s->esc_params[0] == 0) {
+                    s->esc_params[0] = 1;
+                }
+                s->y += s->esc_params[0];
+                if (s->y >= s->height) {
+                    s->y = s->height - 1;
+                }
+                break;
+            case 'C':
+                /* move cursor right */
+                if (s->esc_params[0] == 0) {
+                    s->esc_params[0] = 1;
+                }
+                s->x += s->esc_params[0];
+                if (s->x >= s->width) {
+                    s->x = s->width - 1;
+                }
+                break;
             case 'D':
-                if (s->x > 0)
-                    s->x--;
-                break;
-            case 'C':
-                if (s->x < (s->width - 1))
-                    s->x++;
-                break;
+                /* move cursor left */
+                if (s->esc_params[0] == 0) {
+                    s->esc_params[0] = 1;
+                }
+                s->x -= s->esc_params[0];
+                if (s->x < 0) {
+                    s->x = 0;
+                }
+                break;
+            case 'G':
+                /* move cursor to column */
+                s->x = s->esc_params[0] - 1;
+                if (s->x < 0) {
+                    s->x = 0;
+                }
+                break;
+            case 'f':
+            case 'H':
+                /* move cursor to row, column */
+                s->x = s->esc_params[1] - 1;
+                if (s->x < 0) {
+                    s->x = 0;
+                }
+                s->y = s->esc_params[0] - 1;
+                if (s->y < 0) {
+                    s->y = 0;
+                }
+                break;
+            case 'J':
+                switch (s->esc_params[0]) {
+                case 0:
+                    /* clear to end of screen */
+                    for (y = s->y; y < s->height; y++) {
+                        for (x = 0; x < s->width; x++) {
+                            if (y == s->y && x < s->x) {
+                                continue;
+                            }
+                            console_clear_xy(s, x, y);
+                        }
+                    }
+                    break;
+                case 1:
+                    /* clear from beginning of screen */
+                    for (y = 0; y <= s->y; y++) {
+                        for (x = 0; x < s->width; x++) {
+                            if (y == s->y && x > s->x) {
+                                break;
+                            }
+                            console_clear_xy(s, x, y);
+                        }
+                    }
+                    break;
+                case 2:
+                    /* clear entire screen */
+                    for (y = 0; y <= s->height; y++) {
+                        for (x = 0; x < s->width; x++) {
+                            console_clear_xy(s, x, y);
+                        }
+                    }
+                break;
+                }
             case 'K':
+                switch (s->esc_params[0]) {
+                case 0:
                 /* clear to eol */
-                y1 = (s->y_base + s->y) % s->total_height;
                 for(x = s->x; x < s->width; x++) {
-                    c = &s->cells[y1 * s->width + x];
-                    c->ch = ' ';
-                    c->t_attrib = s->t_attrib_default;
-                    c++;
-                    update_xy(s, x, s->y);
-                }
+                        console_clear_xy(s, x, s->y);
+                }
+                break;
+                case 1:
+                    /* clear from beginning of line */
+                    for (x = 0; x <= s->x; x++) {
+                        console_clear_xy(s, x, s->y);
+                    }
+                    break;
+                case 2:
+                    /* clear entire line */
+                    for(x = 0; x < s->width; x++) {
+                        console_clear_xy(s, x, s->y);
+                    }
+                break;
+            }
+                break;
+            case 'm':
+            console_handle_escape(s);
+            break;
+            case 'n':
+                /* report cursor position */
+                /* TODO: send ESC[row;colR */
+                break;
+            case 's':
+                /* save cursor position */
+                s->x_saved = s->x;
+                s->y_saved = s->y;
+                break;
+            case 'u':
+                /* restore cursor position */
+                s->x = s->x_saved;
+                s->y = s->y_saved;
                 break;
             default:
-                break;
-            }
-            console_handle_escape(s);
+#ifdef DEBUG_CONSOLE
+                fprintf(stderr, "unhandled escape character '%c'\n", ch);
+#endif
+                break;
+            }
             break;
         }
     }
@@ -884,16 +1018,6 @@ static int console_puts(CharDriverState 
     return len;
 }
 
-static void console_chr_add_read_handler(CharDriverState *chr, 
-                                         IOCanRWHandler *fd_can_read, 
-                                         IOReadHandler *fd_read, void *opaque)
-{
-    TextConsole *s = chr->opaque;
-    s->fd_can_read = fd_can_read;
-    s->fd_read = fd_read;
-    s->fd_opaque = opaque;
-}
-
 static void console_send_event(CharDriverState *chr, int event)
 {
     TextConsole *s = chr->opaque;
@@ -915,14 +1039,14 @@ static void kbd_send_chars(void *opaque)
     int len;
     uint8_t buf[16];
     
-    len = s->fd_can_read(s->fd_opaque);
+    len = qemu_chr_can_read(s->chr);
     if (len > s->out_fifo.count)
         len = s->out_fifo.count;
     if (len > 0) {
         if (len > sizeof(buf))
             len = sizeof(buf);
         qemu_fifo_read(&s->out_fifo, buf, len);
-        s->fd_read(s->fd_opaque, buf, len);
+        qemu_chr_read(s->chr, buf, len);
     }
     /* characters are pending: we send them a bit later (XXX:
        horrible, should change char device API) */
@@ -973,7 +1097,7 @@ void kbd_put_keysym(int keysym)
         } else {
                 *q++ = keysym;
         }
-        if (s->fd_read) {
+        if (s->chr->chr_read) {
             qemu_fifo_write(&s->out_fifo, buf, q - buf);
             kbd_send_chars(s);
         }
@@ -1059,9 +1183,9 @@ CharDriverState *text_console_init(Displ
     }
     chr->opaque = s;
     chr->chr_write = console_puts;
-    chr->chr_add_read_handler = console_chr_add_read_handler;
     chr->chr_send_event = console_send_event;
 
+    s->chr = chr;
     s->out_fifo.buf = s->out_fifo_buf;
     s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
     s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
@@ -1091,5 +1215,7 @@ CharDriverState *text_console_init(Displ
     s->t_attrib = s->t_attrib_default;
     text_console_resize(s);
 
+    qemu_chr_reset(chr);
+
     return chr;
 }
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/cpu-all.h
--- a/tools/ioemu/cpu-all.h     Tue May 08 10:38:06 2007 +0100
+++ b/tools/ioemu/cpu-all.h     Wed May 09 14:17:15 2007 +0100
@@ -727,6 +727,13 @@ void page_unprotect_range(target_ulong d
 #define cpu_gen_code cpu_ppc_gen_code
 #define cpu_signal_handler cpu_ppc_signal_handler
 
+#elif defined(TARGET_M68K)
+#define CPUState CPUM68KState
+#define cpu_init cpu_m68k_init
+#define cpu_exec cpu_m68k_exec
+#define cpu_gen_code cpu_m68k_gen_code
+#define cpu_signal_handler cpu_m68k_signal_handler
+
 #elif defined(TARGET_MIPS)
 #define CPUState CPUMIPSState
 #define cpu_init cpu_mips_init
@@ -770,6 +777,7 @@ extern int code_copy_enabled;
 #define CPU_INTERRUPT_TIMER  0x08 /* internal timer exception pending */
 #define CPU_INTERRUPT_FIQ    0x10 /* Fast interrupt pending.  */
 #define CPU_INTERRUPT_HALT   0x20 /* CPU halt wanted */
+#define CPU_INTERRUPT_SMI    0x40 /* (x86 only) SMI interrupt pending */
 
 void cpu_interrupt(CPUState *s, int mask);
 void cpu_reset_interrupt(CPUState *env, int mask);
@@ -889,6 +897,7 @@ void cpu_register_physical_memory(target
 void cpu_register_physical_memory(target_phys_addr_t start_addr, 
                                   unsigned long size,
                                   unsigned long phys_offset);
+uint32_t cpu_get_physical_page_desc(target_phys_addr_t addr);
 int cpu_register_io_memory(int io_index,
                            CPUReadMemoryFunc **mem_read,
                            CPUWriteMemoryFunc **mem_write,
@@ -1042,6 +1051,15 @@ static inline int64_t cpu_get_real_ticks
         return rval.i64;
 #endif
 }
+#else
+/* The host CPU doesn't have an easily accessible cycle counter.
+   Just return a monotonically increasing vlue.  This will be totally wrong,
+   but hopefully better than nothing.  */
+static inline int64_t cpu_get_real_ticks (void)
+{
+    static int64_t ticks = 0;
+    return ticks++;
+}
 #endif
 
 /* profiling */
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/cpu-defs.h
--- a/tools/ioemu/cpu-defs.h    Tue May 08 10:38:06 2007 +0100
+++ b/tools/ioemu/cpu-defs.h    Wed May 09 14:17:15 2007 +0100
@@ -80,6 +80,14 @@ typedef unsigned long ram_addr_t;
 #define TB_JMP_CACHE_BITS 12
 #define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS)
 
+/* Only the bottom TB_JMP_PAGE_BITS of the jump cache hash bits vary for
+   addresses on the same page.  The top bits are the same.  This allows
+   TLB invalidation to quickly clear a subset of the hash table.  */
+#define TB_JMP_PAGE_BITS (TB_JMP_CACHE_BITS / 2)
+#define TB_JMP_PAGE_SIZE (1 << TB_JMP_PAGE_BITS)
+#define TB_JMP_ADDR_MASK (TB_JMP_PAGE_SIZE - 1)
+#define TB_JMP_PAGE_MASK (TB_JMP_CACHE_SIZE - TB_JMP_PAGE_SIZE)
+
 #define CPU_TLB_BITS 8
 #define CPU_TLB_SIZE (1 << CPU_TLB_BITS)
 
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/cpu-exec.c
--- a/tools/ioemu/cpu-exec.c    Tue May 08 10:38:06 2007 +0100
+++ b/tools/ioemu/cpu-exec.c    Wed May 09 14:17:15 2007 +0100
@@ -40,14 +40,14 @@ int tb_invalidated_flag;
 //#define DEBUG_EXEC
 //#define DEBUG_SIGNAL
 
-#if defined(TARGET_ARM) || defined(TARGET_SPARC)
+#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_M68K)
 /* XXX: unify with i386 target */
 void cpu_loop_exit(void)
 {
     longjmp(env->jmp_env, 1);
 }
 #endif
-#if !(defined(TARGET_SPARC) || defined(TARGET_SH4))
+#if !(defined(TARGET_SPARC) || defined(TARGET_SH4) || defined(TARGET_M68K))
 #define reg_T2
 #endif
 
@@ -194,6 +194,10 @@ static inline TranslationBlock *tb_find_
     flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK);
     cs_base = 0;
     pc = env->PC;
+#elif defined(TARGET_M68K)
+    flags = env->fpcr & M68K_FPCR_PREC;
+    cs_base = 0;
+    pc = env->pc;
 #elif defined(TARGET_SH4)
     flags = env->sr & (SR_MD | SR_RB);
     cs_base = 0;         /* XXXXX */
@@ -222,43 +226,16 @@ static inline TranslationBlock *tb_find_
 
 int cpu_exec(CPUState *env1)
 {
-    int saved_T0, saved_T1;
-#if defined(reg_T2)
-    int saved_T2;
-#endif
-    CPUState *saved_env;
-#if defined(TARGET_I386)
-#ifdef reg_EAX
-    int saved_EAX;
-#endif
-#ifdef reg_ECX
-    int saved_ECX;
-#endif
-#ifdef reg_EDX
-    int saved_EDX;
-#endif
-#ifdef reg_EBX
-    int saved_EBX;
-#endif
-#ifdef reg_ESP
-    int saved_ESP;
-#endif
-#ifdef reg_EBP
-    int saved_EBP;
-#endif
-#ifdef reg_ESI
-    int saved_ESI;
-#endif
-#ifdef reg_EDI
-    int saved_EDI;
-#endif
-#elif defined(TARGET_SPARC)
+#define DECLARE_HOST_REGS 1
+#include "hostregs_helper.h"
+#if defined(TARGET_SPARC)
 #if defined(reg_REGWPTR)
     uint32_t *saved_regwptr;
 #endif
 #endif
 #if defined(__sparc__) && !defined(HOST_SOLARIS)
-    int saved_i7, tmp_T0;
+    int saved_i7;
+    target_ulong tmp_T0;
 #endif
     int ret, interrupt_request;
     void (*gen_func)(void);
@@ -320,44 +297,15 @@ int cpu_exec(CPUState *env1)
     cpu_single_env = env1; 
 
     /* first we save global registers */
-    saved_env = env;
+#define SAVE_HOST_REGS 1
+#include "hostregs_helper.h"
     env = env1;
-    saved_T0 = T0;
-    saved_T1 = T1;
-#if defined(reg_T2)
-    saved_T2 = T2;
-#endif
 #if defined(__sparc__) && !defined(HOST_SOLARIS)
     /* we also save i7 because longjmp may not restore it */
     asm volatile ("mov %%i7, %0" : "=r" (saved_i7));
 #endif
 
 #if defined(TARGET_I386)
-#ifdef reg_EAX
-    saved_EAX = EAX;
-#endif
-#ifdef reg_ECX
-    saved_ECX = ECX;
-#endif
-#ifdef reg_EDX
-    saved_EDX = EDX;
-#endif
-#ifdef reg_EBX
-    saved_EBX = EBX;
-#endif
-#ifdef reg_ESP
-    saved_ESP = ESP;
-#endif
-#ifdef reg_EBP
-    saved_EBP = EBP;
-#endif
-#ifdef reg_ESI
-    saved_ESI = ESI;
-#endif
-#ifdef reg_EDI
-    saved_EDI = EDI;
-#endif
-
     env_to_regs();
     /* put eflags in CPU temporary format */
     CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
@@ -370,6 +318,10 @@ int cpu_exec(CPUState *env1)
     saved_regwptr = REGWPTR;
 #endif
 #elif defined(TARGET_PPC)
+#elif defined(TARGET_M68K)
+    env->cc_op = CC_OP_FLAGS;
+    env->cc_dest = env->sr & 0xf;
+    env->cc_x = (env->sr >> 4) & 1;
 #elif defined(TARGET_MIPS)
 #elif defined(TARGET_SH4)
     /* XXXXX */
@@ -390,7 +342,7 @@ int cpu_exec(CPUState *env1)
                     break;
                 } else if (env->user_mode_only) {
                     /* if user mode only, we simulate a fake exception
-                       which will be hanlded outside the cpu execution
+                       which will be handled outside the cpu execution
                        loop */
 #if defined(TARGET_I386)
                     do_interrupt_user(env->exception_index, 
@@ -458,8 +410,16 @@ int cpu_exec(CPUState *env1)
                 interrupt_request = env->interrupt_request;
                 if (__builtin_expect(interrupt_request, 0)) {
 #if defined(TARGET_I386)
-                    /* if hardware interrupt pending, we execute it */
-                    if ((interrupt_request & CPU_INTERRUPT_HARD) &&
+                    if ((interrupt_request & CPU_INTERRUPT_SMI) &&
+                        !(env->hflags & HF_SMM_MASK)) {
+                        env->interrupt_request &= ~CPU_INTERRUPT_SMI;
+                        do_smm_enter();
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
+                        tmp_T0 = 0;
+#else
+                        T0 = 0;
+#endif
+                    } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
                         (env->eflags & IF_MASK) && 
                         !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
                         int intno;
@@ -519,7 +479,6 @@ int cpu_exec(CPUState *env1)
                         env->exception_index = EXCP_EXT_INTERRUPT;
                         env->error_code = 0;
                         do_interrupt(env);
-                        env->interrupt_request &= ~CPU_INTERRUPT_HARD;
 #if defined(__sparc__) && !defined(HOST_SOLARIS)
                         tmp_T0 = 0;
 #else
@@ -548,8 +507,10 @@ int cpu_exec(CPUState *env1)
                        //do_interrupt(0, 0, 0, 0, 0);
                        env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
                    } else if (interrupt_request & CPU_INTERRUPT_HALT) {
-                        env1->halted = 1;
-                        return EXCP_HALTED;
+                       env->interrupt_request &= ~CPU_INTERRUPT_HALT;
+                       env->halted = 1;
+                       env->exception_index = EXCP_HLT;
+                       cpu_loop_exit();
                     }
 #elif defined(TARGET_ARM)
                     if (interrupt_request & CPU_INTERRUPT_FIQ
@@ -621,6 +582,12 @@ int cpu_exec(CPUState *env1)
                    env->regwptr = REGWPTR;
                     cpu_dump_state(env, logfile, fprintf, 0);
 #elif defined(TARGET_PPC)
+                    cpu_dump_state(env, logfile, fprintf, 0);
+#elif defined(TARGET_M68K)
+                    cpu_m68k_flush_flags(env, env->cc_op);
+                    env->cc_op = CC_OP_FLAGS;
+                    env->sr = (env->sr & 0xffe0)
+                              | env->cc_dest | (env->cc_x << 4);
                     cpu_dump_state(env, logfile, fprintf, 0);
 #elif defined(TARGET_MIPS)
                     cpu_dump_state(env, logfile, fprintf, 0);
@@ -803,32 +770,6 @@ int cpu_exec(CPUState *env1)
 #endif
     /* restore flags in standard format */
     env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
-
-    /* restore global registers */
-#ifdef reg_EAX
-    EAX = saved_EAX;
-#endif
-#ifdef reg_ECX
-    ECX = saved_ECX;
-#endif
-#ifdef reg_EDX
-    EDX = saved_EDX;
-#endif
-#ifdef reg_EBX
-    EBX = saved_EBX;
-#endif
-#ifdef reg_ESP
-    ESP = saved_ESP;
-#endif
-#ifdef reg_EBP
-    EBP = saved_EBP;
-#endif
-#ifdef reg_ESI
-    ESI = saved_ESI;
-#endif
-#ifdef reg_EDI
-    EDI = saved_EDI;
-#endif
 #elif defined(TARGET_ARM)
     /* XXX: Save/restore host fpu exception state?.  */
 #elif defined(TARGET_SPARC)
@@ -836,21 +777,24 @@ int cpu_exec(CPUState *env1)
     REGWPTR = saved_regwptr;
 #endif
 #elif defined(TARGET_PPC)
+#elif defined(TARGET_M68K)
+    cpu_m68k_flush_flags(env, env->cc_op);
+    env->cc_op = CC_OP_FLAGS;
+    env->sr = (env->sr & 0xffe0)
+              | env->cc_dest | (env->cc_x << 4);
 #elif defined(TARGET_MIPS)
 #elif defined(TARGET_SH4)
     /* XXXXX */
 #else
 #error unsupported target CPU
 #endif
+
+    /* restore global registers */
 #if defined(__sparc__) && !defined(HOST_SOLARIS)
     asm volatile ("mov %0, %%i7" : : "r" (saved_i7));
 #endif
-    T0 = saved_T0;
-    T1 = saved_T1;
-#if defined(reg_T2)
-    T2 = saved_T2;
-#endif
-    env = saved_env;
+#include "hostregs_helper.h"
+
     /* fail safe : never use cpu_single_env outside cpu_exec() */
     cpu_single_env = NULL; 
     return ret;
@@ -1093,6 +1037,45 @@ static inline int handle_cpu_signal(unsi
     return 1;
 }
 
+#elif defined(TARGET_M68K)
+static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
+                                    int is_write, sigset_t *old_set,
+                                    void *puc)
+{
+    TranslationBlock *tb;
+    int ret;
+
+    if (cpu_single_env)
+        env = cpu_single_env; /* XXX: find a correct solution for multithread 
*/
+#if defined(DEBUG_SIGNAL)
+    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", 
+           pc, address, is_write, *(unsigned long *)old_set);
+#endif
+    /* XXX: locking issue */
+    if (is_write && page_unprotect(address, pc, puc)) {
+        return 1;
+    }
+    /* see if it is an MMU fault */
+    ret = cpu_m68k_handle_mmu_fault(env, address, is_write, 1, 0);
+    if (ret < 0)
+        return 0; /* not an MMU fault */
+    if (ret == 0)
+        return 1; /* the MMU fault was handled without causing real CPU fault 
*/
+    /* now we have a real cpu fault */
+    tb = tb_find_pc(pc);
+    if (tb) {
+        /* the PC is inside the translated code. It means that we have
+           a virtual CPU fault */
+        cpu_restore_state(tb, env, pc, puc);
+    }
+    /* we restore the process signal mask as the sigreturn should
+       do it (XXX: use sigsetjmp) */
+    sigprocmask(SIG_SETMASK, old_set, NULL);
+    cpu_loop_exit();
+    /* never comes here */
+    return 1;
+}
+
 #elif defined (TARGET_MIPS)
 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
                                     int is_write, sigset_t *old_set,
@@ -1193,6 +1176,18 @@ static inline int handle_cpu_signal(unsi
 
 #if defined(__i386__)
 
+#if defined(__APPLE__)
+# include <sys/ucontext.h>
+
+# define EIP_sig(context)  (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
+# define TRAP_sig(context)    ((context)->uc_mcontext->es.trapno)
+# define ERROR_sig(context)   ((context)->uc_mcontext->es.err)
+#else
+# define EIP_sig(context)     ((context)->uc_mcontext.gregs[REG_EIP])
+# define TRAP_sig(context)    ((context)->uc_mcontext.gregs[REG_TRAPNO])
+# define ERROR_sig(context)   ((context)->uc_mcontext.gregs[REG_ERR])
+#endif
+
 #if defined(USE_CODE_COPY)
 static void cpu_send_trap(unsigned long pc, int trap, 
                           struct ucontext *uc)
@@ -1213,9 +1208,10 @@ static void cpu_send_trap(unsigned long 
 }
 #endif
 
-int cpu_signal_handler(int host_signum, struct siginfo *info, 
+int cpu_signal_handler(int host_signum, void *pinfo, 
                        void *puc)
 {
+    siginfo_t *info = pinfo;
     struct ucontext *uc = puc;
     unsigned long pc;
     int trapno;
@@ -1226,8 +1222,8 @@ int cpu_signal_handler(int host_signum, 
 #define REG_ERR    ERR
 #define REG_TRAPNO TRAPNO
 #endif
-    pc = uc->uc_mcontext.gregs[REG_EIP];
-    trapno = uc->uc_mcontext.gregs[REG_TRAPNO];
+    pc = EIP_sig(uc);
+    trapno = TRAP_sig(uc);
 #if defined(TARGET_I386) && defined(USE_CODE_COPY)
     if (trapno == 0x00 || trapno == 0x05) {
         /* send division by zero or bound exception */
@@ -1237,15 +1233,16 @@ int cpu_signal_handler(int host_signum, 
 #endif
         return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
                                  trapno == 0xe ? 
-                                 (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
+                                 (ERROR_sig(uc) >> 1) & 1 : 0,
                                  &uc->uc_sigmask, puc);
 }
 
 #elif defined(__x86_64__)
 
-int cpu_signal_handler(int host_signum, struct siginfo *info,
+int cpu_signal_handler(int host_signum, void *pinfo,
                        void *puc)
 {
+    siginfo_t *info = pinfo;
     struct ucontext *uc = puc;
     unsigned long pc;
 
@@ -1307,9 +1304,10 @@ typedef struct ucontext SIGCONTEXT;
 # define TRAP_sig(context)                     EXCEPREG_sig(exception, 
context) /* number of powerpc exception taken */
 #endif /* __APPLE__ */
 
-int cpu_signal_handler(int host_signum, struct siginfo *info, 
+int cpu_signal_handler(int host_signum, void *pinfo, 
                        void *puc)
 {
+    siginfo_t *info = pinfo;
     struct ucontext *uc = puc;
     unsigned long pc;
     int is_write;
@@ -1330,9 +1328,10 @@ int cpu_signal_handler(int host_signum, 
 
 #elif defined(__alpha__)
 
-int cpu_signal_handler(int host_signum, struct siginfo *info, 
+int cpu_signal_handler(int host_signum, void *pinfo, 
                            void *puc)
 {
+    siginfo_t *info = pinfo;
     struct ucontext *uc = puc;
     uint32_t *pc = uc->uc_mcontext.sc_pc;
     uint32_t insn = *pc;
@@ -1359,9 +1358,10 @@ int cpu_signal_handler(int host_signum, 
 }
 #elif defined(__sparc__)
 
-int cpu_signal_handler(int host_signum, struct siginfo *info, 
+int cpu_signal_handler(int host_signum, void *pinfo, 
                        void *puc)
 {
+    siginfo_t *info = pinfo;
     uint32_t *regs = (uint32_t *)(info + 1);
     void *sigmask = (regs + 20);
     unsigned long pc;
@@ -1392,9 +1392,10 @@ int cpu_signal_handler(int host_signum, 
 
 #elif defined(__arm__)
 
-int cpu_signal_handler(int host_signum, struct siginfo *info, 
+int cpu_signal_handler(int host_signum, void *pinfo, 
                        void *puc)
 {
+    siginfo_t *info = pinfo;
     struct ucontext *uc = puc;
     unsigned long pc;
     int is_write;
@@ -1404,14 +1405,15 @@ int cpu_signal_handler(int host_signum, 
     is_write = 0;
     return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
                              is_write,
-                             &uc->uc_sigmask);
+                             &uc->uc_sigmask, puc);
 }
 
 #elif defined(__mc68000)
 
-int cpu_signal_handler(int host_signum, struct siginfo *info, 
+int cpu_signal_handler(int host_signum, void *pinfo, 
                        void *puc)
 {
+    siginfo_t *info = pinfo;
     struct ucontext *uc = puc;
     unsigned long pc;
     int is_write;
@@ -1431,8 +1433,9 @@ int cpu_signal_handler(int host_signum, 
 # define __ISR_VALID   1
 #endif
 
-int cpu_signal_handler(int host_signum, struct siginfo *info, void *puc)
-{
+int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
+{
+    siginfo_t *info = pinfo;
     struct ucontext *uc = puc;
     unsigned long ip;
     int is_write = 0;
@@ -1459,9 +1462,10 @@ int cpu_signal_handler(int host_signum, 
 
 #elif defined(__s390__)
 
-int cpu_signal_handler(int host_signum, struct siginfo *info, 
+int cpu_signal_handler(int host_signum, void *pinfo, 
                        void *puc)
 {
+    siginfo_t *info = pinfo;
     struct ucontext *uc = puc;
     unsigned long pc;
     int is_write;
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/cutils.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ioemu/cutils.c      Wed May 09 14:17:15 2007 +0100
@@ -0,0 +1,83 @@
+/*
+ * Simple C functions to supplement the C library
+ * 
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * 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 "vl.h"
+
+void pstrcpy(char *buf, int buf_size, const char *str)
+{
+    int c;
+    char *q = buf;
+
+    if (buf_size <= 0)
+        return;
+
+    for(;;) {
+        c = *str++;
+        if (c == 0 || q >= buf + buf_size - 1)
+            break;
+        *q++ = c;
+    }
+    *q = '\0';
+}
+
+/* strcat and truncate. */
+char *pstrcat(char *buf, int buf_size, const char *s)
+{
+    int len;
+    len = strlen(buf);
+    if (len < buf_size) 
+        pstrcpy(buf + len, buf_size - len, s);
+    return buf;
+}
+
+int strstart(const char *str, const char *val, const char **ptr)
+{
+    const char *p, *q;
+    p = str;
+    q = val;
+    while (*q != '\0') {
+        if (*p != *q)
+            return 0;
+        p++;
+        q++;
+    }
+    if (ptr)
+        *ptr = p;
+    return 1;
+}
+
+int stristart(const char *str, const char *val, const char **ptr)
+{
+    const char *p, *q;
+    p = str;
+    q = val;
+    while (*q != '\0') {
+        if (toupper(*p) != toupper(*q))
+            return 0;
+        p++;
+        q++;
+    }
+    if (ptr)
+        *ptr = p;
+    return 1;
+}
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/disas.c
--- a/tools/ioemu/disas.c       Tue May 08 10:38:06 2007 +0100
+++ b/tools/ioemu/disas.c       Wed May 09 14:17:15 2007 +0100
@@ -186,14 +186,14 @@ void target_disas(FILE *out, target_ulon
     disasm_info.mach = bfd_mach_ppc;
 #endif
     print_insn = print_insn_ppc;
+#elif defined(TARGET_M68K)
+    print_insn = print_insn_m68k;
 #elif defined(TARGET_MIPS)
 #ifdef TARGET_WORDS_BIGENDIAN
     print_insn = print_insn_big_mips;
 #else
     print_insn = print_insn_little_mips;
 #endif
-#elif defined(TARGET_M68K)
-    print_insn = print_insn_m68k;
 #elif defined(TARGET_SH4)
     disasm_info.mach = bfd_mach_sh4;
     print_insn = print_insn_sh;
@@ -271,11 +271,9 @@ void disas(FILE *out, void *code, unsign
     for (pc = (unsigned long)code; pc < (unsigned long)code + size; pc += 
count) {
        fprintf(out, "0x%08lx:  ", pc);
 #ifdef __arm__
-        /* since data are included in the code, it is better to
+        /* since data is included in the code, it is better to
            display code data too */
-        if (is_host) {
-            fprintf(out, "%08x  ", (int)bfd_getl32((const bfd_byte *)pc));
-        }
+        fprintf(out, "%08x  ", (int)bfd_getl32((const bfd_byte *)pc));
 #endif
        count = print_insn(pc, &disasm_info);
        fprintf(out, "\n");
@@ -387,14 +385,14 @@ void monitor_disas(CPUState *env,
     disasm_info.mach = bfd_mach_ppc;
 #endif
     print_insn = print_insn_ppc;
+#elif defined(TARGET_M68K)
+    print_insn = print_insn_m68k;
 #elif defined(TARGET_MIPS)
 #ifdef TARGET_WORDS_BIGENDIAN
     print_insn = print_insn_big_mips;
 #else
     print_insn = print_insn_little_mips;
 #endif
-#elif defined(TARGET_M68K)
-    print_insn = print_insn_m68k;
 #else
     term_printf("0x" TARGET_FMT_lx
                ": Asm output not supported on this arch\n", pc);
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/dyngen-exec.h
--- a/tools/ioemu/dyngen-exec.h Tue May 08 10:38:06 2007 +0100
+++ b/tools/ioemu/dyngen-exec.h Wed May 09 14:17:15 2007 +0100
@@ -61,6 +61,9 @@ typedef signed long long int64_t;
 typedef signed long long int64_t;
 #endif
 #endif
+
+/* XXX: This may be wrong for 64-bit ILP32 hosts.  */
+typedef void * host_reg_t;
 
 #define INT8_MIN               (-128)
 #define INT16_MIN              (-32767-1)
@@ -188,7 +191,7 @@ extern int printf(const char *, ...);
 #endif
 
 /* force GCC to generate only one epilog at the end of the function */
-#define FORCE_RET() asm volatile ("");
+#define FORCE_RET() __asm__ __volatile__("" : : : "memory");
 
 #ifndef OPPROTO
 #define OPPROTO
diff -r d2ef85c6bf84 -r 00618037d37d tools/ioemu/dyngen.c
--- a/tools/ioemu/dyngen.c      Tue May 08 10:38:06 2007 +0100
+++ b/tools/ioemu/dyngen.c      Wed May 09 14:17:15 2007 +0100
@@ -127,10 +127,12 @@ typedef int32_t host_long;
 typedef int32_t host_long;
 typedef uint32_t host_ulong;
 #define swabls(x) swab32s(x)
+#define swablss(x) swab32ss(x)
 #else
 typedef int64_t host_long;
 typedef uint64_t host_ulong;
 #define swabls(x) swab64s(x)
+#define swablss(x) swab64ss(x)
 #endif
 
 #ifdef ELF_USES_RELOCA
@@ -284,7 +286,17 @@ void swab32s(uint32_t *p)
     *p = bswap32(*p);
 }
 
+void swab32ss(int32_t *p)
+{
+    *p = bswap32(*p);
+}
+
 void swab64s(uint64_t *p)
+{
+    *p = bswap64(*p);
+}
+
+void swab64ss(int64_t *p)
 {
     *p = bswap64(*p);
 }
@@ -397,7 +409,7 @@ void elf_swap_rel(ELF_RELOC *rel)
     swabls(&rel->r_offset);
     swabls(&rel->r_info);
 #ifdef ELF_USES_RELOCA
-    swabls(&rel->r_addend);
+    swablss(&rel->r_addend);
 #endif
 }
 
@@ -505,7 +517,7 @@ int load_object(const char *filename)
     }
 
     sec = &shdr[ehdr.e_shstrndx];
-    shstr = sdata[ehdr.e_shstrndx];
+    shstr = (char *)sdata[ehdr.e_shstrndx];
 
     /* swap relocations */
     for(i = 0; i < ehdr.e_shnum; i++) {
@@ -541,7 +553,7 @@ int load_object(const char *filename)
     strtab_sec = &shdr[symtab_sec->sh_link];
 
     symtab = (ElfW(Sym) *)sdata[symtab_sec - shdr];
-    strtab = sdata[symtab_sec->sh_link];
+    strtab = (char *)sdata[symtab_sec->sh_link];
     
     nb_syms = symtab_sec->sh_size / sizeof(ElfW(Sym));
     if (do_swap) {
@@ -1255,90 +1267,149 @@ int arm_emit_ldr_info(const char *name, 
 {
     uint8_t *p;
     uint32_t insn;
-    int offset, min_offset, pc_offset, data_size;
+    int offset, min_offset, pc_offset, data_size, spare, max_pool;
     uint8_t data_allocated[1024];
     unsigned int data_index;
+    int type;
     
     memset(data_allocated, 0, sizeof(data_allocated));
     
     p = p_start;
     min_offset = p_end - p_start;
+    spare = 0x7fffffff;
     while (p < p_start + min_offset) {
         insn = get32((uint32_t *)p);
+        /* TODO: Armv5e ldrd.  */
+        /* TODO: VFP load.  */
         if ((insn & 0x0d5f0000) == 0x051f0000) {
             /* ldr reg, [pc, #im] */
             offset = insn & 0xfff;
             if (!(insn & 0x00800000))
-                        offset = -offset;
+                offset = -offset;
+            max_pool = 4096;
+            type = 0;
+        } else if ((insn & 0x0e5f0f00) == 0x0c1f0100) {
+            /* FPA ldf.  */
+            offset = (insn & 0xff) << 2;
+            if (!(insn & 0x00800000))
+                offset = -offset;
+            max_pool = 1024;
+            type = 1;
+        } else if ((insn & 0x0fff0000) == 0x028f0000) {
+            /* Some gcc load a doubleword immediate with
+               add regN, pc, #imm
+               ldmia regN, {regN, regM}
+               Hope and pray the compiler never generates somethin like
+               add reg, pc, #imm1; ldr reg, [reg, #-imm2]; */
+            int r;
+
+            r = (insn & 0xf00) >> 7;
+            offset = ((insn & 0xff) >> r) | ((insn & 0xff) << (32 - r));
+            max_pool = 1024;
+            type = 2;
+        } else {
+            max_pool = 0;
+            type = -1;
+        }
+        if (type >= 0) {
+            /* PC-relative load needs fixing up.  */
+            if (spare > max_pool - offset)
+                spare = max_pool - offset;
             if ((offset & 3) !=0)
-                error("%s:%04x: ldr pc offset must be 32 bit aligned", 
+                error("%s:%04x: pc offset must be 32 bit aligned", 
+                      name, start_offset + p - p_start);
+            if (offset < 0)
+                error("%s:%04x: Embedded literal value",
                       name, start_offset + p - p_start);
             pc_offset = p - p_start + offset + 8;
             if (pc_offset <= (p - p_start) || 
                 pc_offset >= (p_end - p_start))
-                error("%s:%04x: ldr pc offset must point inside the function 
code", 
+                error("%s:%04x: pc offset must point inside the function 
code", 
                       name, start_offset + p - p_start);
             if (pc_offset < min_offset)
                 min_offset = pc_offset;
             if (outfile) {
-                /* ldr position */
+                /* The intruction position */
                 fprintf(outfile, "    arm_ldr_ptr->ptr = gen_code_ptr + 
%d;\n", 
                         p - p_start);
-                /* ldr data index */
-                data_index = ((p_end - p_start) - pc_offset - 4) >> 2;
-                fprintf(outfile, "    arm_ldr_ptr->data_ptr = arm_data_ptr + 
%d;\n", 
+                /* The position of the constant pool data.  */
+                data_index = ((p_end - p_start) - pc_offset) >> 2;
+                fprintf(outfile, "    arm_ldr_ptr->data_ptr = arm_data_ptr - 
%d;\n", 
                         data_index);
+                fprintf(outfile, "    arm_ldr_ptr->type = %d;\n", type);
                 fprintf(outfile, "    arm_ldr_ptr++;\n");
-                if (data_index >= sizeof(data_allocated))
-                    error("%s: too many data", name);
-                if (!data_allocated[data_index]) {
-                    ELF_RELOC *rel;
-                    int i, addend, type;
-                    const char *sym_name, *p;
-                    char relname[1024];
-
-                    data_allocated[data_index] = 1;
-
-                    /* data value */
-                    addend = get32((uint32_t *)(p_start + pc_offset));
-                    relname[0] = '\0';
-                    for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
-                        if (rel->r_offset == (pc_offset + start_offset)) {
-                            sym_name = get_rel_sym_name(rel);
-                            /* the compiler leave some unnecessary references 
to the code */
-                            get_reloc_expr(relname, sizeof(relname), sym_name);
-                            type = ELF32_R_TYPE(rel->r_info);
-                            if (type != R_ARM_ABS32)
-                                error("%s: unsupported data relocation", name);
-                            break;
-                        }
-                    }
-                    fprintf(outfile, "    arm_data_ptr[%d] = 0x%x",
-                            data_index, addend);
-                    if (relname[0] != '\0')
-                        fprintf(outfile, " + %s", relname);
-                    fprintf(outfile, ";\n");
+            }
+        }
+        p += 4;
+    }
+
+    /* Copy and relocate the constant pool data.  */
+    data_size = (p_end - p_start) - min_offset;
+    if (data_size > 0 && outfile) {
+        spare += min_offset;
+        fprintf(outfile, "    arm_data_ptr -= %d;\n", data_size >> 2);
+        fprintf(outfile, "    arm_pool_ptr -= %d;\n", data_size);
+        fprintf(outfile, "    if (arm_pool_ptr > gen_code_ptr + %d)\n"
+                         "        arm_pool_ptr = gen_code_ptr + %d;\n",
+                         spare, spare);
+
+        data_index = 0;
+        for (pc_offset = min_offset;
+             pc_offset < p_end - p_start;
+             pc_offset += 4) {
+
+            ELF_RELOC *rel;
+            int i, addend, type;
+            const char *sym_name;
+            char relname[1024];
+
+            /* data value */
+            addend = get32((uint32_t *)(p_start + pc_offset));
+            relname[0] = '\0';
+            for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
+                if (rel->r_offset == (pc_offset + start_offset)) {
+                    sym_name = get_rel_sym_name(rel);
+                    /* the compiler leave some unnecessary references to the 
code */
+                    get_reloc_expr(relname, sizeof(relname), sym_name);
+                    type = ELF32_R_TYPE(rel->r_info);
+                    if (type != R_ARM_ABS32)
+                        error("%s: unsupported data relocation", name);
+                    break;
                 }
             }
-        }
-        p += 4;
-    }
-    data_size = (p_end - p_start) - min_offset;
-    if (data_size > 0 && outfile) {
-        fprintf(outfile, "    arm_data_ptr += %d;\n", data_size >> 2);
-    }
-
-    /* the last instruction must be a mov pc, lr */
+            fprintf(outfile, "    arm_data_ptr[%d] = 0x%x",
+                    data_index, addend);
+            if (relname[0] != '\0')
+                fprintf(outfile, " + %s", relname);
+            fprintf(outfile, ";\n");
+
+            data_index++;
+        }
+    }
+
     if (p == p_start)
         goto arm_ret_error;
     p -= 4;
     insn = get32((uint32_t *)p);
-    if ((insn & 0xffff0000) != 0xe91b0000) {
+    /* The last instruction must be an ldm instruction.  There are several
+       forms generated by gcc:
+        ldmib sp, {..., pc}  (implies a sp adjustment of +4)
+        ldmia sp, {..., pc}
+        ldmea fp, {..., pc} */
+    if ((insn & 0xffff8000) == 0xe99d8000) {
+        if (outfile) {
+            fprintf(outfile,
+                    "    *(uint32_t *)(gen_code_ptr + %d) = 0xe28dd004;\n",
+                    p - p_start);
+        }
+        p += 4;
+    } else if ((insn & 0xffff8000) != 0xe89d8000
+        && (insn & 0xffff8000) != 0xe91b8000) {
     arm_ret_error:
         if (!outfile)
             printf("%s: invalid epilog\n", name);
     }
-    return p - p_start;            
+    return p - p_start;
 }
 #endif
 
@@ -1537,6 +1608,8 @@ void gen_code(const char *name, host_ulo
     }
 #elif defined(HOST_ARM)
     {
+        uint32_t insn;
+
         if ((p_end - p_start) <= 16)
             error("%s: function too small", name);
         if (get32((uint32_t *)p_start) != 0xe1a0c00d ||
@@ -1545,6 +1618,12 @@ void gen_code(const char *name, host_ulo
             error("%s: invalid prolog", name);
         p_start += 12;
         start_offset += 12;
+        insn = get32((uint32_t *)p_start);
+        if ((insn & 0xffffff00) == 0xe24dd000) {
+            /* Stack adjustment.  Assume op uses the frame pointer.  */
+            p_start -= 4;
+            start_offset -= 4;
+        }
         copy_size = arm_emit_ldr_info(name, start_offset, NULL, p_start, 
p_end, 
                                       relocs, nb_relocs);
     }
@@ -2282,7 +2361,37 @@ void gen_code(const char *name, host_ulo
                 int type;
                 int addend;
                 int reloc_offset;
-
+                uint32_t insn;
+
+                insn = get32((uint32_t *)(p_start + 4));
+                /* If prologue ends in sub sp, sp, #const then assume
+                   op has a stack frame and needs the frame pointer.  */
+                if ((insn & 0xffffff00) == 0xe24dd000) {
+                    int i;
+                    uint32_t opcode;
+                    opcode = 0xe28db000; /* add fp, sp, #0.  */
+#if 0
+/* ??? Need to undo the extra stack adjustment at the end of the op.
+   For now just leave the stack misaligned and hope it doesn't break anything
+   too important.  */
+                    if ((insn & 4) != 0) {
+                        /* Preserve doubleword stack alignment.  */
+                        fprintf(outfile,
+                                "    *(uint32_t *)(gen_code_ptr + 4)= 0x%x;\n",
+                                insn + 4);
+                        opcode -= 4;
+                    }
+#endif
+                    insn = get32((uint32_t *)(p_start - 4));
+                    /* Calculate the size of the saved registers,
+                       excluding pc.  */
+                    for (i = 0; i < 15; i++) {
+                        if (insn & (1 << i))
+                            opcode += 4;
+                    }
+                    fprintf(outfile,
+                            "    *(uint32_t *)gen_code_ptr = 0x%x;\n", opcode);
+                }
                 arm_emit_ldr_info(name, start_offset, outfile, p_start, p_end,
                                   relocs, nb_relocs);
 
@@ -2303,6 +2412,8 @@ void gen_code(const char *name, host_ulo
                                 reloc_offset, name, addend);
                         break;
                     case R_ARM_PC24:
+                    case R_ARM_JUMP24:
+                    case R_ARM_CALL:
                         fprintf(outfile, "    arm_reloc_pc24((uint32_t 
*)(gen_code_ptr + %d), 0x%x, %s);\n", 
                                 reloc_offset, addend, name);
                         break;
@@ -2407,6 +2518,28 @@ int gen_file(FILE *outfile, int out_type
         
     } else {
         /* generate big code generation switch */
+
+#ifdef HOST_ARM
+        /* We need to know the size of all the ops so we can figure out when
+           to emit constant pools.  This must be consistent with opc.h.  */
+fprintf(outfile,
+"static const uint32_t arm_opc_size[] = {\n"
+"  0,\n" /* end */
+"  0,\n" /* nop */
+"  0,\n" /* nop1 */
+"  0,\n" /* nop2 */
+"  0,\n"); /* nop3 */
+        for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
+            const char *name;
+            name = get_sym_name(sym);
+            if (strstart(name, OP_PREFIX, NULL)) {
+                fprintf(outfile, "  %d,\n", sym->st_size);
+            }
+       }
+fprintf(outfile,
+"};\n");
+#endif
+
 fprintf(outfile,
 "int dyngen_code(uint8_t *gen_code_buf,\n"
 "                uint16_t *label_offsets, uint16_t *jmp_offsets,\n"
@@ -2417,10 +2550,36 @@ fprintf(outfile,
 "    const uint32_t *opparam_ptr;\n");
 
 #ifdef HOST_ARM
+/* Arm is tricky because it uses constant pools for loading immediate values.
+   We assume (and require) each function is code followed by a constant pool.
+   All the ops are small so this should be ok.  For each op we figure
+   out how much "spare" range we have in the load instructions.  This allows
+   us to insert subsequent ops in between the op and the constant pool,
+   eliminating the neeed to jump around the pool.
+
+   We currently generate:
+   
+   [ For this example we assume merging would move op1_pool out of range.
+     In practice we should be able to combine many ops before the offset
+     limits are reached. ]
+   op1_code;
+   op2_code;
+   goto op3;
+   op2_pool;
+   op1_pool;
+op3:
+   op3_code;
+   ret;
+   op3_pool;
+
+   Ideally we'd put op1_pool before op2_pool, but that requires two passes.
+ */
 fprintf(outfile,
 "    uint8_t *last_gen_code_ptr = gen_code_buf;\n"
 "    LDREntry *arm_ldr_ptr = arm_ldr_table;\n"
-"    uint32_t *arm_data_ptr = arm_data_table;\n");
+"    uint32_t *arm_data_ptr = arm_data_table + ARM_LDR_TABLE_SIZE;\n"
+/* Initialise the parmissible pool offset to an arbitary large value.  */
+"    uint8_t *arm_pool_ptr = gen_code_buf + 0x1000000;\n");
 #endif
 #ifdef HOST_IA64
     {
@@ -2489,9 +2648,23 @@ fprintf(outfile,
        /* Generate prologue, if needed. */ 
 
 fprintf(outfile,
-"    for(;;) {\n"
-"        switch(*opc_ptr++) {\n"
-);
+"    for(;;) {\n");
+
+#ifdef HOST_ARM
+/* Generate constant pool if needed */
+fprintf(outfile,
+"            if (gen_code_ptr + arm_opc_size[*opc_ptr] >= arm_pool_ptr) {\n"
+"                gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, "
+"arm_ldr_ptr, arm_data_ptr, arm_data_table + ARM_LDR_TABLE_SIZE, 1);\n"
+"                last_gen_code_ptr = gen_code_ptr;\n"
+"                arm_ldr_ptr = arm_ldr_table;\n"
+"                arm_data_ptr = arm_data_table + ARM_LDR_TABLE_SIZE;\n"
+"                arm_pool_ptr = gen_code_ptr + 0x1000000;\n"
+"            }\n");
+#endif
+
+fprintf(outfile,
+"        switch(*opc_ptr++) {\n");
 
         for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
             const char *name;
@@ -2525,17 +2698,6 @@ fprintf(outfile,
 "            goto the_end;\n"
 "        }\n");
 
-#ifdef HOST_ARM
-/* generate constant table if needed */
-fprintf(outfile,
-"        if ((gen_code_ptr - last_gen_code_ptr) >= (MAX_FRAG_SIZE - 
MAX_OP_SIZE)) {\n"
-"            gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, 
arm_ldr_ptr, arm_data_table, arm_data_ptr, 1);\n"
-"            last_gen_code_ptr = gen_code_ptr;\n"
-"            arm_ldr_ptr = arm_ldr_table;\n"
-"            arm_data_ptr = arm_data_table;\n"
-"        }\n");         
-#endif
-
 
 fprintf(outfile,
 "    }\n"
@@ -2553,7 +2715,10 @@ fprintf(outfile,
 
 /* generate some code patching */ 
 #ifdef HOST_ARM
-fprintf(outfile, "gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, 
arm_ldr_ptr, arm_data_table, arm_data_ptr, 0);\n");
+fprintf(outfile,
+"if (arm_data_ptr != arm_data_table + ARM_LDR_TABLE_SIZE)\n"
+"    gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, "
+"arm_ldr_ptr, arm_data_ptr, arm_data_table + ARM_LDR_TABLE_SIZE, 0);\n");

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.