WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

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

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] [ioemu] Update to qemu 0.90.
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Tue, 15 May 2007 08:20:11 -0700
Delivery-date: Tue, 15 May 2007 08:19:22 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# 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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] [ioemu] Update to qemu 0.90., Xen patchbot-unstable <=