ia64/xen-unstable

changeset 15060:00618037d37d

[ioemu] Update to qemu 0.90.

Signed-off-by: Christian Limpach <Christian.Limpach@xensource.com>
author Christian Limpach <Christian.Limpach@xensource.com>
date Wed May 09 14:17:15 2007 +0100 (2007-05-09)
parents d2ef85c6bf84
children 8df600f56acd
files tools/ioemu/.CVS/Entries tools/ioemu/.CVS/Entries.Log tools/ioemu/.CVS/Tag tools/ioemu/.cvsignore tools/ioemu/Changelog tools/ioemu/LICENSE tools/ioemu/Makefile tools/ioemu/Makefile.target tools/ioemu/README.distrib tools/ioemu/VERSION tools/ioemu/audio/.CVS/Entries tools/ioemu/audio/.CVS/Tag tools/ioemu/audio/wavaudio.c tools/ioemu/audio/wavcapture.c tools/ioemu/block-bochs.c tools/ioemu/block-cloop.c tools/ioemu/block-cow.c tools/ioemu/block-dmg.c tools/ioemu/block-qcow.c tools/ioemu/block-qcow2.c tools/ioemu/block-raw.c tools/ioemu/block-vmdk.c tools/ioemu/block-vpc.c tools/ioemu/block-vvfat.c tools/ioemu/block.c tools/ioemu/block_int.h tools/ioemu/check_ops.sh tools/ioemu/configure tools/ioemu/console.c tools/ioemu/cpu-all.h tools/ioemu/cpu-defs.h tools/ioemu/cpu-exec.c tools/ioemu/cutils.c tools/ioemu/disas.c tools/ioemu/dyngen-exec.h tools/ioemu/dyngen.c tools/ioemu/dyngen.h tools/ioemu/elf.h tools/ioemu/elf_ops.h tools/ioemu/exec-all.h tools/ioemu/exec.c tools/ioemu/fpu/.CVS/Entries tools/ioemu/fpu/.CVS/Tag tools/ioemu/fpu/softfloat-native.c tools/ioemu/fpu/softfloat-native.h tools/ioemu/fpu/softfloat-specialize.h tools/ioemu/fpu/softfloat.c tools/ioemu/fpu/softfloat.h tools/ioemu/gdbstub.c tools/ioemu/gdbstub.h tools/ioemu/hostregs_helper.h tools/ioemu/hw/.CVS/Entries tools/ioemu/hw/.CVS/Tag tools/ioemu/hw/acpi-dsdt.dsl tools/ioemu/hw/acpi-dsdt.hex tools/ioemu/hw/acpi.c tools/ioemu/hw/adb.c tools/ioemu/hw/apb_pci.c tools/ioemu/hw/apic.c tools/ioemu/hw/arm_boot.c tools/ioemu/hw/arm_gic.c tools/ioemu/hw/arm_sysctl.c tools/ioemu/hw/arm_timer.c tools/ioemu/hw/cirrus_vga.c tools/ioemu/hw/cs4231.c tools/ioemu/hw/esp.c tools/ioemu/hw/fdc.c tools/ioemu/hw/grackle_pci.c tools/ioemu/hw/gt64xxx.c tools/ioemu/hw/i8259.c tools/ioemu/hw/ide.c tools/ioemu/hw/integratorcp.c tools/ioemu/hw/iommu.c tools/ioemu/hw/isa_mmio.c tools/ioemu/hw/lance.c tools/ioemu/hw/lsi53c895a.c tools/ioemu/hw/mc146818rtc.c tools/ioemu/hw/mips_int.c tools/ioemu/hw/mips_malta.c tools/ioemu/hw/mips_r4k.c tools/ioemu/hw/mips_timer.c tools/ioemu/hw/ne2000.c tools/ioemu/hw/pc.c tools/ioemu/hw/pci.c tools/ioemu/hw/pcnet.c tools/ioemu/hw/pflash_cfi02.c tools/ioemu/hw/piix4acpi.c tools/ioemu/hw/piix_pci.c tools/ioemu/hw/pl011.c tools/ioemu/hw/pl080.c tools/ioemu/hw/pl110.c tools/ioemu/hw/pl110_template.h tools/ioemu/hw/ppc.c tools/ioemu/hw/ppc_chrp.c tools/ioemu/hw/ppc_prep.c tools/ioemu/hw/prep_pci.c tools/ioemu/hw/ps2.c tools/ioemu/hw/realview.c tools/ioemu/hw/rtl8139.c tools/ioemu/hw/scsi-disk.c tools/ioemu/hw/serial.c tools/ioemu/hw/sh7750.c tools/ioemu/hw/slavio_misc.c tools/ioemu/hw/slavio_serial.c tools/ioemu/hw/smbus.h tools/ioemu/hw/smbus_eeprom.c tools/ioemu/hw/smc91c111.c tools/ioemu/hw/sparc32_dma.c tools/ioemu/hw/sun4m.c tools/ioemu/hw/sun4u.c tools/ioemu/hw/tcx.c tools/ioemu/hw/unin_pci.c tools/ioemu/hw/usb-hid.c tools/ioemu/hw/usb-hub.c tools/ioemu/hw/usb-msd.c tools/ioemu/hw/usb-ohci.c tools/ioemu/hw/usb-uhci.c tools/ioemu/hw/usb.c tools/ioemu/hw/usb.h tools/ioemu/hw/versatile_pci.c tools/ioemu/hw/versatilepb.c tools/ioemu/hw/vga.c tools/ioemu/hw/vga_int.h tools/ioemu/hw/xen_platform.c tools/ioemu/keymaps.c tools/ioemu/keymaps/.CVS/Entries tools/ioemu/keymaps/.CVS/Tag tools/ioemu/keymaps/ja tools/ioemu/kqemu.c tools/ioemu/loader.c tools/ioemu/monitor.c tools/ioemu/osdep.c tools/ioemu/osdep.h tools/ioemu/patches/acpi-poweroff-support tools/ioemu/patches/acpi-support tools/ioemu/patches/acpi-timer-support tools/ioemu/patches/domain-destroy tools/ioemu/patches/domain-reset tools/ioemu/patches/domain-timeoffset tools/ioemu/patches/fix-interrupt-routing tools/ioemu/patches/fix-vga-scanning-code-overflow tools/ioemu/patches/hypervisor-pit tools/ioemu/patches/hypervisor-rtc tools/ioemu/patches/ide-error-reporting tools/ioemu/patches/ioemu-buffer-pio-ia64 tools/ioemu/patches/ioemu-ia64 tools/ioemu/patches/ioemu-save-restore tools/ioemu/patches/ioemu-save-restore-acpi tools/ioemu/patches/ioemu-save-restore-ide tools/ioemu/patches/ioemu-save-restore-logdirty tools/ioemu/patches/ioemu-save-restore-ne2000 tools/ioemu/patches/ioemu-save-restore-pcnet tools/ioemu/patches/ioemu-save-restore-rtl8139 tools/ioemu/patches/ioemu-save-restore-timer tools/ioemu/patches/ioemu-save-restore-usb tools/ioemu/patches/ne2000-bounds-checks tools/ioemu/patches/qemu-64bit tools/ioemu/patches/qemu-allow-disable-sdl tools/ioemu/patches/qemu-block-device-bounds-checks tools/ioemu/patches/qemu-bootorder tools/ioemu/patches/qemu-bugfixes tools/ioemu/patches/qemu-cirrus-bounds-checks tools/ioemu/patches/qemu-cleanup tools/ioemu/patches/qemu-daemonize tools/ioemu/patches/qemu-dm tools/ioemu/patches/qemu-dma-null-pointer-check tools/ioemu/patches/qemu-hvm-banner tools/ioemu/patches/qemu-infrastructure tools/ioemu/patches/qemu-init-vgabios tools/ioemu/patches/qemu-logging tools/ioemu/patches/qemu-no-apic tools/ioemu/patches/qemu-nobios tools/ioemu/patches/qemu-pci tools/ioemu/patches/qemu-pci-vendor-ids tools/ioemu/patches/qemu-serial-fixes tools/ioemu/patches/qemu-smp tools/ioemu/patches/qemu-target-i386-dm tools/ioemu/patches/qemu-timer tools/ioemu/patches/qemu-tunable-ide-write-cache tools/ioemu/patches/remove-pci-bridge-setup tools/ioemu/patches/rtl8139-bound-chaining tools/ioemu/patches/scsi tools/ioemu/patches/serial-non-block tools/ioemu/patches/serial-port-rate-limit tools/ioemu/patches/series tools/ioemu/patches/shadow-vram tools/ioemu/patches/shared-vram tools/ioemu/patches/support-xm-console tools/ioemu/patches/tpm-tis-device tools/ioemu/patches/usb-mouse-tablet-status-check tools/ioemu/patches/vnc-access-monitor-vt tools/ioemu/patches/vnc-backoff-screen-scan tools/ioemu/patches/vnc-cleanup tools/ioemu/patches/vnc-display-find-unused tools/ioemu/patches/vnc-fix-signedness tools/ioemu/patches/vnc-fix-version-check tools/ioemu/patches/vnc-fixes tools/ioemu/patches/vnc-listen-specific-interface tools/ioemu/patches/vnc-password tools/ioemu/patches/vnc-protocol-fixes tools/ioemu/patches/vnc-start-vncviewer tools/ioemu/patches/vnc-title-domain-name tools/ioemu/patches/xen-build tools/ioemu/patches/xen-domain-name tools/ioemu/patches/xen-domid tools/ioemu/patches/xen-mapcache tools/ioemu/patches/xen-mm tools/ioemu/patches/xen-network tools/ioemu/patches/xen-platform-device tools/ioemu/patches/xen-support-buffered-ioreqs tools/ioemu/patches/xenstore tools/ioemu/patches/xenstore-block-device-config tools/ioemu/patches/xenstore-device-info-functions tools/ioemu/patches/xenstore-write-vnc-port tools/ioemu/pc-bios/.CVS/Entries tools/ioemu/pc-bios/.CVS/Tag tools/ioemu/pc-bios/README tools/ioemu/pc-bios/bios.diff tools/ioemu/pc-bios/pxe-ne2k_pci.bin tools/ioemu/pc-bios/pxe-pcnet.bin tools/ioemu/pc-bios/pxe-rtl8139.bin tools/ioemu/qemu-doc.texi tools/ioemu/qemu-img.c tools/ioemu/qemu-img.texi tools/ioemu/qemu_socket.h tools/ioemu/sdl.c tools/ioemu/tap-win32.c tools/ioemu/target-i386-dm/helper2.c tools/ioemu/target-i386-dm/piix_pci-dm.c tools/ioemu/target-i386-dm/rtc-dm.c tools/ioemu/target-i386/.CVS/Entries tools/ioemu/target-i386/.CVS/Tag tools/ioemu/target-i386/cpu.h tools/ioemu/target-i386/exec.h tools/ioemu/target-i386/helper.c tools/ioemu/target-i386/helper2.c tools/ioemu/target-i386/op.c tools/ioemu/target-i386/ops_sse.h tools/ioemu/target-i386/translate.c tools/ioemu/tests/.CVS/Entries tools/ioemu/tests/.CVS/Tag tools/ioemu/tests/Makefile tools/ioemu/tests/hello-mips.c tools/ioemu/tests/test-i386.c tools/ioemu/translate-all.c tools/ioemu/usb-linux.c tools/ioemu/vl.c tools/ioemu/vl.h tools/ioemu/vnc.c tools/ioemu/vnc_keysym.h tools/ioemu/vnchextile.h tools/ioemu/x_keymap.c
line diff
     1.1 --- a/tools/ioemu/.CVS/Entries	Tue May 08 10:38:06 2007 +0100
     1.2 +++ b/tools/ioemu/.CVS/Entries	Wed May 09 14:17:15 2007 +0100
     1.3 @@ -1,109 +1,117 @@
     1.4  D/audio////
     1.5  D/hw////
     1.6 -D/linux-user////
     1.7  D/pc-bios////
     1.8 -D/slirp////
     1.9 -D/target-arm////
    1.10  D/target-i386////
    1.11 -D/target-ppc////
    1.12 -D/target-sparc////
    1.13  D/tests////
    1.14  D/fpu////
    1.15  D/keymaps////
    1.16 +/.cvsignore/1.16/Thu May  3 17:17:53 2007//Trelease_0_9_0
    1.17 +/COPYING/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_9_0
    1.18 +/COPYING.LIB/1.2/Thu Jul 13 09:23:22 2006//Trelease_0_9_0
    1.19 +/Changelog/1.128/Thu May  3 17:17:53 2007//Trelease_0_9_0
    1.20 +/LICENSE/1.3/Thu May  3 17:17:53 2007//Trelease_0_9_0
    1.21 +/Makefile/1.112/Thu May  3 17:17:53 2007//Trelease_0_9_0
    1.22 +/Makefile.target/1.144/Thu May  3 17:17:53 2007//Trelease_0_9_0
    1.23 +/README/1.12/Wed Oct 18 10:11:20 2006//Trelease_0_9_0
    1.24 +/TODO/1.39/Fri Jan  5 14:34:35 2007//Trelease_0_9_0
    1.25 +/VERSION/1.30/Thu May  3 17:17:53 2007//Trelease_0_9_0
    1.26 +/a.out.h/1.2/Wed Oct 18 10:11:20 2006//Trelease_0_9_0
    1.27 +/aes.c/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_9_0
    1.28 +/aes.h/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_9_0
    1.29 +/alpha-dis.c/1.3/Thu May  3 17:17:54 2007//Trelease_0_9_0
    1.30 +/alpha.ld/1.1/Thu May  3 17:17:54 2007//Trelease_0_9_0
    1.31 +/arm-dis.c/1.3/Thu May  3 17:17:54 2007//Trelease_0_9_0
    1.32 +/arm-semi.c/1.2/Sun Jan 28 03:10:55 2007//Trelease_0_9_0
    1.33 +/arm.ld/1.2/Thu May  3 17:17:54 2007//Trelease_0_9_0
    1.34 +/block-bochs.c/1.3/Thu May  3 17:17:54 2007//Trelease_0_9_0
    1.35 +/block-cloop.c/1.4/Thu May  3 17:17:54 2007//Trelease_0_9_0
    1.36 +/block-cow.c/1.7/Thu May  3 17:17:54 2007//Trelease_0_9_0
    1.37 +/block-dmg.c/1.5/Thu May  3 17:17:54 2007//Trelease_0_9_0
    1.38 +/block-qcow.c/1.11/Thu May  3 17:17:54 2007//Trelease_0_9_0
    1.39 +/block-qcow2.c/1.4/Mon Aug  7 02:38:06 2006//Trelease_0_9_0
    1.40 +/block-raw.c/1.17/Thu Jan 18 00:22:11 2007//Trelease_0_9_0
    1.41 +/block-vmdk.c/1.10/Thu May  3 17:17:55 2007//Trelease_0_9_0
    1.42 +/block-vpc.c/1.4/Thu May  3 17:17:55 2007//Trelease_0_9_0
    1.43 +/block-vvfat.c/1.8/Thu May  3 17:17:55 2007//Trelease_0_9_0
    1.44 +/block.c/1.42/Thu May  3 17:17:55 2007//Trelease_0_9_0
    1.45 +/block_int.h/1.10/Thu May  3 17:17:55 2007//Trelease_0_9_0
    1.46 +/bswap.h/1.5/Thu Jul 13 09:23:22 2006//Trelease_0_9_0
    1.47 +/check_ops.sh/1.1/Sun Jan  7 19:38:08 2007//Trelease_0_9_0
    1.48 +/cocoa.m/1.10/Fri Jan  5 14:34:35 2007//Trelease_0_9_0
    1.49 +/configure/1.120/Thu May  3 17:17:55 2007//Trelease_0_9_0
    1.50 +/console.c/1.11/Thu May  3 17:17:55 2007//Trelease_0_9_0
    1.51 +/cpu-all.h/1.60/Thu May  3 17:17:55 2007//Trelease_0_9_0
    1.52 +/cpu-defs.h/1.17/Thu May  3 17:17:55 2007//Trelease_0_9_0
    1.53 +/cpu-exec.c/1.93/Thu May  3 17:17:55 2007//Trelease_0_9_0
    1.54 +/cutils.c/1.1/Sun Jan  7 22:04:40 2007//Trelease_0_9_0
    1.55 +/dis-asm.h/1.11/Wed Oct 18 10:11:20 2006//Trelease_0_9_0
    1.56 +/disas.c/1.34/Thu May  3 17:17:55 2007//Trelease_0_9_0
    1.57 +/disas.h/1.7/Thu May  3 17:17:36 2007//Trelease_0_9_0
    1.58 +/dyngen-exec.h/1.31/Thu May  3 17:17:55 2007//Trelease_0_9_0
    1.59 +/dyngen-op.h/1.1/Wed Oct 18 10:11:20 2006//Trelease_0_9_0
    1.60 +/dyngen.c/1.47/Thu May  3 17:17:55 2007//Trelease_0_9_0
    1.61 +/dyngen.h/1.12/Thu May  3 17:17:55 2007//Trelease_0_9_0
    1.62 +/elf.h/1.8/Thu May  3 17:17:55 2007//Trelease_0_9_0
    1.63 +/elf_ops.h/1.5/Thu May  3 17:17:55 2007//Trelease_0_9_0
    1.64 +/exec-all.h/1.49/Thu May  3 17:17:55 2007//Trelease_0_9_0
    1.65 +/exec.c/1.85/Thu May  3 17:17:55 2007//Trelease_0_9_0
    1.66 +/gdbstub.c/1.47/Thu May  3 17:17:55 2007//Trelease_0_9_0
    1.67 +/gdbstub.h/1.5/Thu May  3 17:17:55 2007//Trelease_0_9_0
    1.68 +/hostregs_helper.h/1.1/Sun Feb  4 13:37:44 2007//Trelease_0_9_0
    1.69 +/i386-dis.c/1.5/Wed Oct 18 10:11:21 2006//Trelease_0_9_0
    1.70 +/i386-vl.ld/1.3/Wed Oct 18 10:11:21 2006//Trelease_0_9_0
    1.71 +/i386.ld/1.2/Wed Oct 18 10:11:21 2006//Trelease_0_9_0
    1.72 +/ia64.ld/1.1/Wed Oct 18 10:11:21 2006//Trelease_0_9_0
    1.73 +/keymaps.c/1.2/Thu May  3 17:17:34 2007//Trelease_0_9_0
    1.74 +/kqemu.c/1.15/Thu May  3 17:17:55 2007//Trelease_0_9_0
    1.75 +/kqemu.h/1.1/Wed Oct 18 10:11:21 2006//Trelease_0_9_0
    1.76 +/loader.c/1.4/Thu May  3 17:17:55 2007//Trelease_0_9_0
    1.77 +/m68k-dis.c/1.1/Thu May  3 17:17:56 2007//Trelease_0_9_0
    1.78 +/m68k.ld/1.1/Thu May  3 17:17:56 2007//Trelease_0_9_0
    1.79 +/mips-dis.c/1.4/Thu May  3 17:17:57 2007//Trelease_0_9_0
    1.80 +/monitor.c/1.64/Thu May  3 17:17:57 2007//Trelease_0_9_0
    1.81 +/osdep.c/1.15/Thu May  3 17:17:57 2007//Trelease_0_9_0
    1.82 +/osdep.h/1.8/Thu May  3 17:17:57 2007//Trelease_0_9_0
    1.83 +/ppc-dis.c/1.7/Thu May  3 17:17:58 2007//Trelease_0_9_0
    1.84 +/ppc.ld/1.2/Thu May  3 17:17:58 2007//Trelease_0_9_0
    1.85 +/qemu-binfmt-conf.sh/1.4/Wed Oct 18 10:11:21 2006//Trelease_0_9_0
    1.86 +/qemu-doc.texi/1.128/Thu May  3 17:17:58 2007//Trelease_0_9_0
    1.87 +/qemu-img.c/1.16/Thu May  3 17:17:58 2007//Trelease_0_9_0
    1.88 +/qemu-img.texi/1.3/Thu May  3 17:17:58 2007//Trelease_0_9_0
    1.89 +/qemu-tech.texi/1.9/Wed Oct 18 10:11:21 2006//Trelease_0_9_0
    1.90 +/qemu_socket.h/1.2/Thu May  3 17:17:58 2007//Trelease_0_9_0
    1.91 +/readline.c/1.1/Wed Oct 18 10:11:21 2006//Trelease_0_9_0
    1.92 +/s390.ld/1.1/Thu May  3 17:17:58 2007//Trelease_0_9_0
    1.93 +/sdl.c/1.34/Thu May  3 17:17:58 2007//Trelease_0_9_0
    1.94 +/sdl_keysym.h/1.3/Wed Oct 18 10:11:21 2006//Trelease_0_9_0
    1.95 +/sh4-dis.c/1.1/Thu May  3 17:17:58 2007//Trelease_0_9_0
    1.96 +/softmmu_exec.h/1.1/Wed Oct 18 10:11:21 2006//Trelease_0_9_0
    1.97 +/softmmu_header.h/1.13/Wed Oct 18 10:11:21 2006//Trelease_0_9_0
    1.98 +/softmmu_template.h/1.16/Wed Oct 18 10:11:21 2006//Trelease_0_9_0
    1.99 +/sparc-dis.c/1.3/Thu May  3 17:17:59 2007//Trelease_0_9_0
   1.100 +/sparc.ld/1.1/Thu May  3 17:17:59 2007//Trelease_0_9_0
   1.101 +/sparc64.ld/1.1/Fri Aug  4 21:55:15 2006//Trelease_0_9_0
   1.102 +/tap-win32.c/1.4/Thu May  3 17:17:59 2007//Trelease_0_9_0
   1.103 +/texi2pod.pl/1.1/Wed Oct 18 10:11:21 2006//Trelease_0_9_0
   1.104 +/thunk.c/1.6/Wed Oct 18 10:11:21 2006//Trelease_0_9_0
   1.105 +/thunk.h/1.13/Thu Jul 13 09:23:22 2006//Trelease_0_9_0
   1.106 +/translate-all.c/1.15/Thu May  3 17:17:59 2007//Trelease_0_9_0
   1.107 +/translate-op.c/1.1/Wed Oct 18 10:11:21 2006//Trelease_0_9_0
   1.108 +/usb-linux.c/1.10/Thu May  3 17:17:59 2007//Trelease_0_9_0
   1.109 +/vgafont.h/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_9_0
   1.110 +/vl.c/1.248/Thu May  3 17:17:59 2007//Trelease_0_9_0
   1.111 +/vl.h/1.184/Thu May  3 17:17:59 2007//Trelease_0_9_0
   1.112 +/vnc.c/1.12/Thu May  3 17:17:59 2007//Trelease_0_9_0
   1.113 +/vnc_keysym.h/1.2/Thu May  3 17:17:59 2007//Trelease_0_9_0
   1.114 +/vnchextile.h/1.3/Thu May  3 17:17:59 2007//Trelease_0_9_0
   1.115 +/x86_64.ld/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_9_0
   1.116 +/x_keymap.c/1.1/Wed Jan 24 21:40:21 2007//Trelease_0_9_0
   1.117 +D/darwin-user////
   1.118 +D/linux-user////
   1.119 +D/slirp////
   1.120 +D/target-arm////
   1.121 +D/target-m68k////
   1.122  D/target-mips////
   1.123 +D/target-ppc////
   1.124  D/target-sh4////
   1.125 -/.cvsignore/1.14/Sun Aug  6 01:03:44 2006//Trelease_0_8_2
   1.126 -/COPYING/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2
   1.127 -/COPYING.LIB/1.2/Thu Jul 13 09:23:22 2006//Trelease_0_8_2
   1.128 -/Changelog/1.121/Sun Aug  6 01:03:44 2006//Trelease_0_8_2
   1.129 -/LICENSE/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
   1.130 -/Makefile/1.104/Sun Aug  6 01:03:44 2006//Trelease_0_8_2
   1.131 -/Makefile.target/1.121/Sun Aug  6 01:03:44 2006//Trelease_0_8_2
   1.132 -/README/1.12/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
   1.133 -/README.distrib/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
   1.134 -/TODO/1.39/Sun Aug  6 01:03:44 2006//Trelease_0_8_2
   1.135 -/VERSION/1.29/Sun Aug  6 01:03:44 2006//Trelease_0_8_2
   1.136 -/a.out.h/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
   1.137 -/aes.c/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2
   1.138 -/aes.h/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2
   1.139 -/alpha-dis.c/1.3/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
   1.140 -/alpha.ld/1.1/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
   1.141 -/arm-dis.c/1.3/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
   1.142 -/arm.ld/1.1/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
   1.143 -/block-bochs.c/1.1/Sun Aug  6 00:55:02 2006//Trelease_0_8_2
   1.144 -/block-cloop.c/1.3/Sun Aug  6 00:55:02 2006//Trelease_0_8_2
   1.145 -/block-cow.c/1.6/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
   1.146 -/block-dmg.c/1.4/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
   1.147 -/block-qcow.c/1.7/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
   1.148 -/block-vmdk.c/1.8/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
   1.149 -/block-vpc.c/1.3/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
   1.150 -/block-vvfat.c/1.6/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
   1.151 -/block.c/1.28/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
   1.152 -/block_int.h/1.5/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
   1.153 -/bswap.h/1.5/Thu Jul 13 09:23:22 2006//Trelease_0_8_2
   1.154 -/cocoa.m/1.10/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
   1.155 -/configure/1.110/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
   1.156 -/console.c/1.8/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
   1.157 -/cpu-all.h/1.57/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
   1.158 -/cpu-defs.h/1.16/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
   1.159 -/cpu-exec.c/1.83/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
   1.160 -/dis-asm.h/1.11/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
   1.161 -/disas.c/1.31/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
   1.162 -/disas.h/1.7/Sun Aug  6 00:55:03 2006//Trelease_0_8_2
   1.163 -/dyngen-exec.h/1.29/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
   1.164 -/dyngen-op.h/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
   1.165 -/dyngen.c/1.45/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
   1.166 -/dyngen.h/1.11/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
   1.167 -/elf.h/1.7/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
   1.168 -/elf_ops.h/1.3/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
   1.169 -/exec-all.h/1.48/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
   1.170 -/exec.c/1.82/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
   1.171 -/gdbstub.c/1.40/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
   1.172 -/gdbstub.h/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
   1.173 -/i386-dis.c/1.5/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
   1.174 -/i386-vl.ld/1.3/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
   1.175 -/i386.ld/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
   1.176 -/ia64.ld/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
   1.177 -/keymaps.c/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
   1.178 -/kqemu.c/1.12/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
   1.179 -/kqemu.h/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
   1.180 -/linux-2.6.9-qemu-fast.patch/1.1/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
   1.181 -/loader.c/1.3/Sun Aug  6 01:03:45 2006//Trelease_0_8_2
   1.182 -/m68k-dis.c/1.1/Sun Aug  6 01:03:46 2006//Trelease_0_8_2
   1.183 -/m68k.ld/1.1/Sun Aug  6 01:03:46 2006//Trelease_0_8_2
   1.184 -/mips-dis.c/1.4/Sun Aug  6 01:03:47 2006//Trelease_0_8_2
   1.185 -/monitor.c/1.54/Sun Aug  6 01:03:47 2006//Trelease_0_8_2
   1.186 -/osdep.c/1.11/Sun Aug  6 01:03:47 2006//Trelease_0_8_2
   1.187 -/osdep.h/1.6/Sun Aug  6 01:03:47 2006//Trelease_0_8_2
   1.188 -/ppc-dis.c/1.7/Sun Aug  6 01:03:48 2006//Trelease_0_8_2
   1.189 -/ppc.ld/1.2/Sun Aug  6 01:03:48 2006//Trelease_0_8_2
   1.190 -/qemu-binfmt-conf.sh/1.4/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
   1.191 -/qemu-doc.texi/1.100/Sun Aug  6 01:03:48 2006//Trelease_0_8_2
   1.192 -/qemu-img.c/1.10/Sun Aug  6 01:03:48 2006//Trelease_0_8_2
   1.193 -/qemu-img.texi/1.2/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
   1.194 -/qemu-tech.texi/1.9/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
   1.195 -/qemu_socket.h/1.1/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
   1.196 -/readline.c/1.1/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
   1.197 -/s390.ld/1.1/Sun Aug  6 01:03:48 2006//Trelease_0_8_2
   1.198 -/sdl.c/1.29/Sun Aug  6 01:03:48 2006//Trelease_0_8_2
   1.199 -/sdl_keysym.h/1.3/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
   1.200 -/sh4-dis.c/1.1/Sun Aug  6 01:03:48 2006//Trelease_0_8_2
   1.201 -/softmmu_exec.h/1.1/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
   1.202 -/softmmu_header.h/1.13/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
   1.203 -/softmmu_template.h/1.16/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
   1.204 -/sparc-dis.c/1.3/Sun Aug  6 01:03:49 2006//Trelease_0_8_2
   1.205 -/sparc.ld/1.1/Sun Aug  6 01:03:49 2006//Trelease_0_8_2
   1.206 -/tap-win32.c/1.3/Sun Aug  6 01:03:49 2006//Trelease_0_8_2
   1.207 -/texi2pod.pl/1.1/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
   1.208 -/thunk.c/1.6/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
   1.209 -/thunk.h/1.13/Thu Jul 13 09:23:22 2006//Trelease_0_8_2
   1.210 -/translate-all.c/1.14/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
   1.211 -/translate-op.c/1.1/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
   1.212 -/usb-linux.c/1.8/Sun Aug  6 01:03:49 2006//Trelease_0_8_2
   1.213 -/vgafont.h/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2
   1.214 -/vl.c/1.202/Sun Aug  6 01:03:49 2006//Trelease_0_8_2
   1.215 -/vl.h/1.136/Sun Aug  6 01:03:49 2006//Trelease_0_8_2
   1.216 -/vnc.c/1.7/Sun Aug  6 01:03:49 2006//Trelease_0_8_2
   1.217 -/vnc_keysym.h/1.1/Fri Jul 14 12:43:46 2006//Trelease_0_8_2
   1.218 -/vnchextile.h/1.2/Sun Aug  6 01:03:49 2006//Trelease_0_8_2
   1.219 -/x86_64.ld/1.1/Thu Jul 13 09:23:22 2006//Trelease_0_8_2
   1.220 +D/target-sparc////
     2.1 --- a/tools/ioemu/.CVS/Entries.Log	Tue May 08 10:38:06 2007 +0100
     2.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.3 @@ -1,7 +0,0 @@
     2.4 -A D/linux-user////
     2.5 -A D/slirp////
     2.6 -A D/target-arm////
     2.7 -A D/target-mips////
     2.8 -A D/target-ppc////
     2.9 -A D/target-sh4////
    2.10 -A D/target-sparc////
     3.1 --- a/tools/ioemu/.CVS/Tag	Tue May 08 10:38:06 2007 +0100
     3.2 +++ b/tools/ioemu/.CVS/Tag	Wed May 09 14:17:15 2007 +0100
     3.3 @@ -1,1 +1,1 @@
     3.4 -Nrelease_0_8_2
     3.5 +Nrelease_0_9_0
     4.1 --- a/tools/ioemu/.cvsignore	Tue May 08 10:38:06 2007 +0100
     4.2 +++ b/tools/ioemu/.cvsignore	Wed May 09 14:17:15 2007 +0100
     4.3 @@ -1,14 +1,16 @@
     4.4 -arm-user
     4.5 +arm-linux-user
     4.6  arm-softmmu
     4.7 -armeb-user
     4.8 +armeb-linux-user
     4.9  config-host.*
    4.10  dyngen
    4.11  i386
    4.12  i386-softmmu
    4.13 -i386-user
    4.14 +i386-darwin-user
    4.15 +i386-linux-user
    4.16  ppc-softmmu
    4.17  ppc64-softmmu
    4.18 -ppc-user
    4.19 +ppc-darwin-user
    4.20 +ppc-linux-user
    4.21  qemu-doc.html
    4.22  qemu-tech.html
    4.23  qemu-doc.info
    4.24 @@ -17,18 +19,19 @@ qemu.1
    4.25  qemu.pod
    4.26  qemu-img.1
    4.27  qemu-img.pod
    4.28 -sparc-user
    4.29 +sparc-linux-user
    4.30  qemu-img
    4.31  sparc-softmmu
    4.32  x86_64-softmmu
    4.33 -sparc64-user
    4.34 +sparc64-linux-user
    4.35  sparc64-softmmu
    4.36  mips-softmmu
    4.37  mipsel-softmmu
    4.38 -mips-user
    4.39 -mipsel-user
    4.40 +mips-linux-user
    4.41 +mipsel-linux-user
    4.42 +m68k-linux-user
    4.43  .gdbinit
    4.44 -sh4-user
    4.45 +sh4-linux-user
    4.46  sh4-softmmu
    4.47  *.aux
    4.48  *.cp
     5.1 --- a/tools/ioemu/Changelog	Tue May 08 10:38:06 2007 +0100
     5.2 +++ b/tools/ioemu/Changelog	Wed May 09 14:17:15 2007 +0100
     5.3 @@ -1,3 +1,21 @@
     5.4 +version 0.9.0:
     5.5 +
     5.6 +  - Support for relative paths in backing files for disk images
     5.7 +  - Async file I/O API
     5.8 +  - New qcow2 disk image format
     5.9 +  - Support of multiple VM snapshots
    5.10 +  - Linux: specific host CDROM and floppy support
    5.11 +  - SMM support
    5.12 +  - Moved PCI init, MP table init and ACPI table init to Bochs BIOS
    5.13 +  - Support for MIPS32 Release 2 instruction set (Thiemo Seufer)
    5.14 +  - MIPS Malta system emulation (Aurelien Jarno, Stefan Weil)
    5.15 +  - Darwin userspace emulation (Pierre d'Herbemont)
    5.16 +  - m68k user support (Paul Brook)
    5.17 +  - several x86 and x86_64 emulation fixes
    5.18 +  - Mouse relative offset VNC extension (Anthony Liguori)
    5.19 +  - PXE boot support (Anthony Liguori)
    5.20 +  - '-daemonize' option (Anthony Liguori)
    5.21 +
    5.22  version 0.8.2:
    5.23  
    5.24    - ACPI support
     6.1 --- a/tools/ioemu/LICENSE	Tue May 08 10:38:06 2007 +0100
     6.2 +++ b/tools/ioemu/LICENSE	Wed May 09 14:17:15 2007 +0100
     6.3 @@ -1,11 +1,14 @@
     6.4 -The following points clarify the QEMU licenses:
     6.5 +The following points clarify the QEMU license:
     6.6 +
     6.7 +1) QEMU as a whole is released under the GNU General Public License
     6.8  
     6.9 -1) The QEMU virtual CPU core library (libqemu.a) and the QEMU PC
    6.10 -   system emulator are released under the GNU Lesser General Public
    6.11 -   License.
    6.12 +2) Parts of QEMU have specific licenses which are compatible with the
    6.13 +GNU General Public License. Hence each source file contains its own
    6.14 +licensing information.
    6.15  
    6.16 -2) The Linux user mode QEMU emulator is released under the GNU General
    6.17 -   Public License.
    6.18 +In particular, the QEMU virtual CPU core library (libqemu.a) is
    6.19 +released under the GNU Lesser General Public License. Many hardware
    6.20 +device emulation sources are released under the BSD license.
    6.21  
    6.22  3) QEMU is a trademark of Fabrice Bellard.
    6.23  
     7.1 --- a/tools/ioemu/Makefile	Tue May 08 10:38:06 2007 +0100
     7.2 +++ b/tools/ioemu/Makefile	Wed May 09 14:17:15 2007 +0100
     7.3 @@ -8,19 +8,18 @@ include $(XEN_ROOT)/tools/Rules.mk
     7.4  .PHONY: all clean distclean dvi info install install-doc tar tarbin \
     7.5  	speed test test2 html dvi info
     7.6  
     7.7 -CFLAGS+=-Wall -O2 -g -fno-strict-aliasing -I.
     7.8 -ifdef CONFIG_DARWIN
     7.9 -CFLAGS+= -mdynamic-no-pic
    7.10 -endif
    7.11 +BASE_CFLAGS=
    7.12 +BASE_LDFLAGS=
    7.13 +
    7.14 +BASE_CFLAGS += $(OS_CFLAGS)
    7.15  ifeq ($(ARCH),sparc)
    7.16 -CFLAGS+=-mcpu=ultrasparc
    7.17 +BASE_CFLAGS += -mcpu=ultrasparc
    7.18  endif
    7.19 -LDFLAGS=-g
    7.20 +CPPFLAGS += -I. -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
    7.21  LIBS=
    7.22 -DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
    7.23  TOOLS=qemu-img$(EXESUF)
    7.24  ifdef CONFIG_STATIC
    7.25 -LDFLAGS+=-static
    7.26 +BASE_LDFLAGS += -static
    7.27  endif
    7.28  ifdef BUILD_DOCS
    7.29  DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1
    7.30 @@ -28,6 +27,14 @@ else
    7.31  DOCS=
    7.32  endif
    7.33  
    7.34 +ifndef CONFIG_DARWIN
    7.35 +ifndef CONFIG_WIN32
    7.36 +ifndef CONFIG_SOLARIS
    7.37 +LIBS+=-lrt
    7.38 +endif
    7.39 +endif
    7.40 +endif
    7.41 +
    7.42  TOOLS=
    7.43  
    7.44  all: $(TOOLS) $(DOCS) recurse-all
    7.45 @@ -36,12 +43,12 @@ subdir-%:
    7.46  	$(MAKE) -C $(subst subdir-,,$@) all
    7.47  
    7.48  recurse-all: $(patsubst %,subdir-%, $(TARGET_DIRS))
    7.49 -        
    7.50 -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
    7.51 -	$(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS)
    7.52 +
    7.53 +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
    7.54 +	$(CC) -DQEMU_TOOL $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $(LDFLAGS) $(BASE_LDFLAGS) -o $@ $^ -lz $(LIBS)
    7.55  
    7.56  dyngen$(EXESUF): dyngen.c
    7.57 -	$(HOST_CC) $(CFLAGS) $(DEFINES) -o $@ $^
    7.58 +	$(HOST_CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -o $@ $^
    7.59  
    7.60  clean:
    7.61  # avoid old build problems by removing potentially incorrect old files
    7.62 @@ -65,7 +72,7 @@ common  de-ch  es     fo  fr-ca  hu     
    7.63  
    7.64  install-doc: $(DOCS)
    7.65  	mkdir -p "$(DESTDIR)$(docdir)"
    7.66 -	$(INSTALL_DATA) qemu-doc.html  qemu-tech.html "$(DESTDIR)$(docdir)"
    7.67 +	$(INSTALL_DATA) -m 644 qemu-doc.html  qemu-tech.html "$(DESTDIR)$(docdir)"
    7.68  ifndef CONFIG_WIN32
    7.69  	mkdir -p "$(DESTDIR)$(mandir)/man1"
    7.70  	$(INSTALL_DATA) qemu.1 qemu-img.1 "$(DESTDIR)$(mandir)/man1"
    7.71 @@ -76,13 +83,14 @@ install: all $(if $(BUILD_DOCS),install-
    7.72  #	$(INSTALL) -m 755 -s $(TOOLS) "$(DESTDIR)$(bindir)"
    7.73  #	mkdir -p "$(DESTDIR)$(datadir)"
    7.74  #	for x in bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \
    7.75 -#			video.x openbios-sparc32 linux_boot.bin; do \
    7.76 -#		$(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \
    7.77 +#		video.x openbios-sparc32 linux_boot.bin pxe-ne2k_pci.bin \
    7.78 +#		pxe-rtl8139.bin pxe-pcnet.bin; do \
    7.79 +#		$(INSTALL) -m 644 $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \
    7.80  #	done
    7.81  ifndef CONFIG_WIN32
    7.82  	mkdir -p "$(DESTDIR)$(datadir)/keymaps"
    7.83  	for x in $(KEYMAPS); do \
    7.84 -		$(INSTALL_DATA) $(SRC_PATH)/keymaps/$$x "$(DESTDIR)$(datadir)/keymaps"; \
    7.85 +		$(INSTALL_DATA) -m 644 $(SRC_PATH)/keymaps/$$x "$(DESTDIR)$(datadir)/keymaps"; \
    7.86  	done
    7.87  endif
    7.88  	for d in $(TARGET_DIRS); do \
    7.89 @@ -125,7 +133,8 @@ dvi: qemu-doc.dvi qemu-tech.dvi
    7.90  
    7.91  html: qemu-doc.html qemu-tech.html
    7.92  
    7.93 -FILE=qemu-$(shell cat VERSION)
    7.94 +VERSION ?= $(shell cat VERSION)
    7.95 +FILE = qemu-$(VERSION)
    7.96  
    7.97  # tar release (use 'make -k tar' on a checkouted tree)
    7.98  tar:
    7.99 @@ -159,6 +168,9 @@ tarbin:
   7.100  	$(datadir)/video.x \
   7.101  	$(datadir)/openbios-sparc32 \
   7.102  	$(datadir)/linux_boot.bin \
   7.103 +        $(datadir)/pxe-ne2k_pci.bin \
   7.104 +	$(datadir)/pxe-rtl8139.bin \
   7.105 +        $(datadir)/pxe-pcnet.bin \
   7.106  	$(docdir)/qemu-doc.html \
   7.107  	$(docdir)/qemu-tech.html \
   7.108  	$(mandir)/man1/qemu.1 $(mandir)/man1/qemu-img.1 )
     8.1 --- a/tools/ioemu/Makefile.target	Tue May 08 10:38:06 2007 +0100
     8.2 +++ b/tools/ioemu/Makefile.target	Wed May 09 14:17:15 2007 +0100
     8.3 @@ -15,21 +15,24 @@ TARGET_BASE_ARCH:=sparc
     8.4  endif
     8.5  TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH)$(TARGET_SUB)
     8.6  VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw:$(SRC_PATH)/audio
     8.7 -DEFINES=-I. -I.. -I$(TARGET_PATH) -I$(SRC_PATH)
     8.8 -DEFINES+= -I$(XEN_ROOT)/tools/libxc
     8.9 -DEFINES+= -I$(XEN_ROOT)/tools/xenstore
    8.10 -ifdef CONFIG_USER_ONLY
    8.11 +CPPFLAGS=-I. -I.. -I$(TARGET_PATH) -I$(SRC_PATH)
    8.12 +CPPFLAGS+= -I$(XEN_ROOT)/tools/libxc
    8.13 +CPPFLAGS+= -I$(XEN_ROOT)/tools/xenstore
    8.14 +ifdef CONFIG_DARWIN_USER
    8.15 +VPATH+=:$(SRC_PATH)/darwin-user
    8.16 +CPPFLAGS+=-I$(SRC_PATH)/darwin-user -I$(SRC_PATH)/darwin-user/$(TARGET_ARCH)
    8.17 +endif
    8.18 +ifdef CONFIG_LINUX_USER
    8.19  VPATH+=:$(SRC_PATH)/linux-user
    8.20 -DEFINES+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ARCH)
    8.21 +CPPFLAGS+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ARCH)
    8.22  endif
    8.23 -CFLAGS+=-Wall -O2 -g -fno-strict-aliasing
    8.24 +BASE_CFLAGS=
    8.25 +BASE_LDFLAGS=
    8.26  SSE2 := $(call cc-option,$(CC),-msse2,)
    8.27  ifeq ($(SSE2),-msse2)
    8.28  CFLAGS += -DUSE_SSE2=1 -msse2
    8.29  endif
    8.30 -CFLAGS+= $(LOCAL_CFLAGS)
    8.31  #CFLAGS+=-Werror
    8.32 -LDFLAGS=-g
    8.33  LIBS=
    8.34  HELPER_CFLAGS=$(CFLAGS)
    8.35  DYNGEN=../dyngen$(EXESUF)
    8.36 @@ -74,18 +77,20 @@ endif
    8.37  endif # !CONFIG_USER_ONLY
    8.38  
    8.39  ifdef CONFIG_STATIC
    8.40 -LDFLAGS+=-static
    8.41 +BASE_LDFLAGS+=-static
    8.42  endif
    8.43  
    8.44 +# We require -O2 to avoid the stack setup prologue in EXIT_TB
    8.45 +OP_CFLAGS = -Wall -O2 -g -fno-strict-aliasing
    8.46 +
    8.47  ifeq ($(ARCH),i386)
    8.48 -CFLAGS+=-fomit-frame-pointer
    8.49 -OP_CFLAGS=$(CFLAGS) -mpreferred-stack-boundary=2
    8.50 +HELPER_CFLAGS+=-fomit-frame-pointer
    8.51 +OP_CFLAGS+=-mpreferred-stack-boundary=2 -fomit-frame-pointer
    8.52  ifeq ($(HAVE_GCC3_OPTIONS),yes)
    8.53  OP_CFLAGS+= -falign-functions=0 -fno-gcse
    8.54  else
    8.55  OP_CFLAGS+= -malign-functions=0
    8.56  endif
    8.57 -
    8.58  ifdef TARGET_GPROF
    8.59  USE_I386_LD=y
    8.60  endif
    8.61 @@ -93,76 +98,80 @@ ifdef CONFIG_STATIC
    8.62  USE_I386_LD=y
    8.63  endif
    8.64  ifdef USE_I386_LD
    8.65 -LDFLAGS+=-Wl,-T,$(SRC_PATH)/i386.ld
    8.66 +BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
    8.67  else
    8.68 +ifdef CONFIG_LINUX_USER
    8.69  # WARNING: this LDFLAGS is _very_ tricky : qemu is an ELF shared object
    8.70  # that the kernel ELF loader considers as an executable. I think this
    8.71  # is the simplest way to make it self virtualizable!
    8.72 -LDFLAGS+=-Wl,-shared
    8.73 +BASE_LDFLAGS+=-Wl,-shared
    8.74 +endif
    8.75  endif
    8.76  endif
    8.77  
    8.78  ifeq ($(ARCH),x86_64)
    8.79 -OP_CFLAGS=$(CFLAGS) -falign-functions=0
    8.80 -LDFLAGS+=-Wl,-T,$(SRC_PATH)/x86_64.ld
    8.81 +BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
    8.82  endif
    8.83  
    8.84  ifeq ($(ARCH),ppc)
    8.85 -CFLAGS+= -D__powerpc__
    8.86 -OP_CFLAGS=$(CFLAGS)
    8.87 -LDFLAGS+=-Wl,-T,$(SRC_PATH)/ppc.ld
    8.88 +CPPFLAGS+= -D__powerpc__
    8.89 +ifdef CONFIG_LINUX_USER
    8.90 +BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
    8.91 +endif
    8.92  endif
    8.93  
    8.94  ifeq ($(ARCH),s390)
    8.95 -OP_CFLAGS=$(CFLAGS)
    8.96 -LDFLAGS+=-Wl,-T,$(SRC_PATH)/s390.ld
    8.97 +BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
    8.98  endif
    8.99  
   8.100  ifeq ($(ARCH),sparc)
   8.101  ifeq ($(CONFIG_SOLARIS),yes)
   8.102 -CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g2 -ffixed-g3
   8.103 -LDFLAGS+=-m32
   8.104 -OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -fno-omit-frame-pointer -ffixed-i0
   8.105 +BASE_CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g2 -ffixed-g3
   8.106 +BASE_LDFLAGS+=-m32
   8.107 +OP_CFLAGS+=-fno-delayed-branch -fno-omit-frame-pointer -ffixed-i0
   8.108  else
   8.109 -CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
   8.110 -LDFLAGS+=-m32
   8.111 -OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
   8.112 +BASE_CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
   8.113 +BASE_LDFLAGS+=-m32
   8.114 +OP_CFLAGS+=-fno-delayed-branch -ffixed-i0
   8.115  HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat
   8.116  # -static is used to avoid g1/g3 usage by the dynamic linker
   8.117 -LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc.ld -static
   8.118 +BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld -static
   8.119  endif
   8.120  endif
   8.121  
   8.122  ifeq ($(ARCH),sparc64)
   8.123 -CFLAGS+=-mcpu=ultrasparc -m64 -ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7
   8.124 -LDFLAGS+=-m64
   8.125 -LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc64.ld
   8.126 -OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
   8.127 +BASE_CFLAGS+=-mcpu=ultrasparc -m64 -ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7
   8.128 +BASE_LDFLAGS+=-m64
   8.129 +BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
   8.130 +OP_CFLAGS+=-mcpu=ultrasparc -m64 -ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7 -fno-delayed-branch -ffixed-i0
   8.131  endif
   8.132  
   8.133  ifeq ($(ARCH),alpha)
   8.134 -# -msmall-data is not used because we want two-instruction relocations
   8.135 -# for the constant constructions
   8.136 -OP_CFLAGS=-Wall -O2 -g
   8.137 +# -msmall-data is not used for OP_CFLAGS because we want two-instruction
   8.138 +# relocations for the constant constructions
   8.139  # Ensure there's only a single GP
   8.140 -CFLAGS += -msmall-data
   8.141 -LDFLAGS+=-Wl,-T,$(SRC_PATH)/alpha.ld
   8.142 +BASE_CFLAGS+=-msmall-data
   8.143 +BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
   8.144  endif
   8.145  
   8.146  ifeq ($(ARCH),ia64)
   8.147 -CFLAGS += -mno-sdata
   8.148 -OP_CFLAGS=$(CFLAGS)
   8.149 -LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/ia64.ld
   8.150 +BASE_CFLAGS+=-mno-sdata
   8.151 +OP_CFLAGS+=-mno-sdata
   8.152 +BASE_LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/$(ARCH).ld
   8.153  endif
   8.154  
   8.155  ifeq ($(ARCH),arm)
   8.156 -OP_CFLAGS=$(CFLAGS) -mno-sched-prolog -fno-omit-frame-pointer
   8.157 -LDFLAGS+=-Wl,-T,$(SRC_PATH)/arm.ld
   8.158 +OP_CFLAGS+=-mno-sched-prolog -fno-omit-frame-pointer
   8.159 +BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
   8.160  endif
   8.161  
   8.162  ifeq ($(ARCH),m68k)
   8.163 -OP_CFLAGS=$(CFLAGS) -fomit-frame-pointer
   8.164 -LDFLAGS+=-Wl,-T,m68k.ld
   8.165 +OP_CFLAGS+=-fomit-frame-pointer
   8.166 +BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
   8.167 +endif
   8.168 +
   8.169 +ifeq ($(ARCH),mips)
   8.170 +BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
   8.171  endif
   8.172  
   8.173  ifeq ($(HAVE_GCC3_OPTIONS),yes)
   8.174 @@ -171,14 +180,20 @@ OP_CFLAGS+=-fno-reorder-blocks -fno-opti
   8.175  endif
   8.176  
   8.177  ifeq ($(CONFIG_DARWIN),yes)
   8.178 -OP_CFLAGS+= -mdynamic-no-pic
   8.179  LIBS+=-lmx
   8.180  endif
   8.181  
   8.182 +ifdef CONFIG_DARWIN_USER
   8.183 +# Leave some space for the regular program loading zone
   8.184 +BASE_LDFLAGS+=-Wl,-segaddr,__STD_PROG_ZONE,0x1000 -image_base 0x0e000000
   8.185 +endif
   8.186 +
   8.187 +OP_CFLAGS+=$(OS_CFLAGS)
   8.188 +
   8.189  #########################################################
   8.190  
   8.191 -DEFINES+=-D_GNU_SOURCE
   8.192 -#-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
   8.193 +CPPFLAGS+=-D_GNU_SOURCE
   8.194 +# -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
   8.195  LIBS+=-lm
   8.196  LIBS+=-L../../libxc -lxenctrl -lxenguest
   8.197  LIBS+=-L../../xenstore -lxenstore
   8.198 @@ -195,10 +210,11 @@ endif
   8.199  
   8.200  # profiling code
   8.201  ifdef TARGET_GPROF
   8.202 -LDFLAGS+=-p
   8.203 -main.o: CFLAGS+=-p
   8.204 +BASE_LDFLAGS+=-p
   8.205 +main.o: BASE_CFLAGS+=-p
   8.206  endif
   8.207  
   8.208 +ifdef CONFIG_LINUX_USER
   8.209  OBJS= main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o \
   8.210        elfload.o linuxload.o
   8.211  ifdef TARGET_HAS_BFLT
   8.212 @@ -213,6 +229,15 @@ OBJS+=nwfpe/fpa11.o nwfpe/fpa11_cpdo.o \
   8.213  nwfpe/fpa11_cpdt.o nwfpe/fpa11_cprt.o nwfpe/fpopcode.o nwfpe/single_cpdo.o \
   8.214   nwfpe/double_cpdo.o nwfpe/extended_cpdo.o arm-semi.o
   8.215  endif
   8.216 +ifeq ($(TARGET_ARCH), m68k)
   8.217 +OBJS+= m68k-sim.o m68k-semi.o
   8.218 +endif
   8.219 +endif #CONFIG_LINUX_USER
   8.220 +
   8.221 +ifdef CONFIG_DARWIN_USER
   8.222 +OBJS= main.o commpage.o machload.o mmap.o osdep.o signal.o syscall.o thunk.o
   8.223 +endif
   8.224 +
   8.225  SRCS:= $(OBJS:.o=.c)
   8.226  OBJS+= libqemu.a
   8.227  
   8.228 @@ -224,7 +249,7 @@ LIBOBJS+=fpu/softfloat.o
   8.229  else
   8.230  LIBOBJS+=fpu/softfloat-native.o
   8.231  endif
   8.232 -DEFINES+=-I$(SRC_PATH)/fpu
   8.233 +CPPFLAGS+=-I$(SRC_PATH)/fpu
   8.234  
   8.235  ifeq ($(TARGET_ARCH), i386)
   8.236  LIBOBJS+=helper.o helper2.o
   8.237 @@ -257,6 +282,10 @@ ifeq ($(TARGET_BASE_ARCH), sh4)
   8.238  LIBOBJS+= op_helper.o helper.o
   8.239  endif
   8.240  
   8.241 +ifeq ($(TARGET_BASE_ARCH), m68k)
   8.242 +LIBOBJS+= helper.o
   8.243 +endif
   8.244 +
   8.245  # NOTE: the disassembler code is only needed for debugging
   8.246  LIBOBJS+=disas.o 
   8.247  ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386)
   8.248 @@ -304,7 +333,7 @@ endif
   8.249  all: $(PROGS)
   8.250  
   8.251  $(QEMU_USER): $(OBJS)
   8.252 -	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^  $(LIBS)
   8.253 +	$(CC) $(CFLAGS) $(LDFLAGS) $(BASE_LDFLAGS) -o $@ $^  $(LIBS)
   8.254  ifeq ($(ARCH),alpha)
   8.255  # Mark as 32 bit binary, i. e. it will be mapped into the low 31 bit of
   8.256  # the address space (31 bit so sign extending doesn't matter)
   8.257 @@ -312,8 +341,10 @@ ifeq ($(ARCH),alpha)
   8.258  endif
   8.259  
   8.260  # must use static linking to avoid leaving stuff in virtual address space
   8.261 -VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o
   8.262 -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
   8.263 +VL_OBJS=vl.o osdep.o readline.o monitor.o pci.o console.o isa_mmio.o
   8.264 +VL_OBJS+=cutils.o
   8.265 +VL_OBJS+=block.o block-raw.o
   8.266 +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
   8.267  ifdef CONFIG_WIN32
   8.268  VL_OBJS+=tap-win32.o
   8.269  endif
   8.270 @@ -339,7 +370,7 @@ LIBS += -lole32 -ldxguid
   8.271  endif
   8.272  ifdef CONFIG_FMOD
   8.273  AUDIODRV += fmodaudio.o
   8.274 -audio.o fmodaudio.o: DEFINES := -I$(CONFIG_FMOD_INC) $(DEFINES)
   8.275 +audio.o fmodaudio.o: CPPFLAGS := -I$(CONFIG_FMOD_INC) $(CPPFLAGS)
   8.276  LIBS += $(CONFIG_FMOD_LIB)
   8.277  endif
   8.278  ifdef CONFIG_ADLIB
   8.279 @@ -365,23 +396,25 @@ else
   8.280  VL_OBJS+= fdc.o serial.o pc.o
   8.281  endif
   8.282  VL_OBJS+= cirrus_vga.o mixeng.o parallel.o acpi.o
   8.283 -VL_OBJS+= usb-uhci.o
   8.284 +VL_OBJS+= usb-uhci.o smbus_eeprom.o
   8.285  VL_OBJS+= piix4acpi.o
   8.286  VL_OBJS+= xenstore.o
   8.287  VL_OBJS+= xen_platform.o
   8.288  VL_OBJS+= tpm_tis.o
   8.289 -DEFINES += -DHAS_AUDIO
   8.290 +CPPFLAGS += -DHAS_AUDIO
   8.291  endif
   8.292  ifeq ($(TARGET_BASE_ARCH), ppc)
   8.293  VL_OBJS+= ppc.o ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
   8.294  VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o
   8.295  VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.o
   8.296  VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o
   8.297 -DEFINES += -DHAS_AUDIO
   8.298 +CPPFLAGS += -DHAS_AUDIO
   8.299  endif
   8.300  ifeq ($(TARGET_ARCH), mips)
   8.301 -VL_OBJS+= mips_r4k.o dma.o vga.o serial.o i8254.o i8259.o
   8.302 -#VL_OBJS+= #ide.o pckbd.o fdc.o m48t59.o
   8.303 +VL_OBJS+= mips_r4k.o mips_malta.o mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o
   8.304 +VL_OBJS+= ide.o gt64xxx.o pckbd.o ps2.o fdc.o mc146818rtc.o usb-uhci.o acpi.o
   8.305 +VL_OBJS+= piix_pci.o parallel.o mixeng.o cirrus_vga.o $(SOUND_HW) $(AUDIODRV)
   8.306 +DEFINES += -DHAS_AUDIO
   8.307  endif
   8.308  ifeq ($(TARGET_BASE_ARCH), sparc)
   8.309  ifeq ($(TARGET_ARCH), sparc64)
   8.310 @@ -389,14 +422,17 @@ VL_OBJS+= sun4u.o ide.o pckbd.o ps2.o vg
   8.311  VL_OBJS+= fdc.o mc146818rtc.o serial.o m48t59.o
   8.312  VL_OBJS+= cirrus_vga.o parallel.o
   8.313  else
   8.314 -VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t59.o slavio_intctl.o
   8.315 -VL_OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o
   8.316 +VL_OBJS+= sun4m.o tcx.o pcnet.o iommu.o m48t59.o slavio_intctl.o
   8.317 +VL_OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o sparc32_dma.o
   8.318 +VL_OBJS+= cs4231.o
   8.319  endif
   8.320  endif
   8.321  ifeq ($(TARGET_BASE_ARCH), arm)
   8.322  VL_OBJS+= integratorcp.o versatilepb.o ps2.o smc91c111.o arm_pic.o arm_timer.o
   8.323  VL_OBJS+= arm_boot.o pl011.o pl050.o pl080.o pl110.o pl190.o
   8.324  VL_OBJS+= versatile_pci.o
   8.325 +VL_OBJS+= arm_gic.o realview.o arm_sysctl.o
   8.326 +VL_OBJS+= arm-semi.o
   8.327  endif
   8.328  ifeq ($(TARGET_BASE_ARCH), sh4)
   8.329  VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o
   8.330 @@ -405,7 +441,7 @@ ifdef CONFIG_GDBSTUB
   8.331  VL_OBJS+=gdbstub.o 
   8.332  endif
   8.333  ifdef CONFIG_SDL
   8.334 -VL_OBJS+=sdl.o
   8.335 +VL_OBJS+=sdl.o x_keymap.o
   8.336  endif
   8.337  VL_OBJS+=vnc.o
   8.338  VL_OBJS+=d3des.o
   8.339 @@ -417,7 +453,7 @@ COCOA_LIBS+=-framework CoreAudio
   8.340  endif
   8.341  endif
   8.342  ifdef CONFIG_SLIRP
   8.343 -DEFINES+=-I$(SRC_PATH)/slirp
   8.344 +CPPFLAGS+=-I$(SRC_PATH)/slirp
   8.345  SLIRP_OBJS=cksum.o if.o ip_icmp.o ip_input.o ip_output.o \
   8.346  slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tcp_output.o \
   8.347  tcp_subr.o tcp_timer.o udp.o bootp.o debug.o tftp.o
   8.348 @@ -440,7 +476,7 @@ endif
   8.349  endif
   8.350  endif
   8.351  ifdef TARGET_GPROF
   8.352 -vl.o: CFLAGS+=-p
   8.353 +vl.o: BASE_CFLAGS+=-p
   8.354  VL_LDFLAGS+=-p
   8.355  endif
   8.356  
   8.357 @@ -461,25 +497,25 @@ endif
   8.358  	$(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(VL_LIBS)
   8.359  
   8.360  cocoa.o: cocoa.m
   8.361 -	$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
   8.362 +	$(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
   8.363  
   8.364  sdl.o: sdl.c keymaps.c sdl_keysym.h
   8.365 -	$(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
   8.366 +	$(CC) $(CFLAGS) $(CPPFLAGS) $(SDL_CFLAGS) $(BASE_CFLAGS) -c -o $@ $<
   8.367  
   8.368  vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h
   8.369 -	$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
   8.370 +	$(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
   8.371  
   8.372  d3des.o: d3des.c d3des.h
   8.373  	$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
   8.374  
   8.375  sdlaudio.o: sdlaudio.c
   8.376 -	$(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
   8.377 +	$(CC) $(CFLAGS) $(CPPFLAGS) $(SDL_CFLAGS) $(BASE_CFLAGS) -c -o $@ $<
   8.378  
   8.379  depend: $(SRCS)
   8.380 -	$(CC) -MM $(CFLAGS) $(DEFINES) $^ 1>.depend
   8.381 +	$(CC) -MM $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $^ 1>.depend
   8.382  
   8.383  vldepend: $(VL_OBJS:.o=.c)
   8.384 -	$(CC) -MM $(CFLAGS) $(DEFINES) $^ 1>.depend
   8.385 +	$(CC) -MM $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $^ 1>.depend
   8.386  
   8.387  # libqemu 
   8.388  
   8.389 @@ -503,10 +539,26 @@ gen-op.h: op.o $(DYNGEN)
   8.390  	$(DYNGEN) -g -o $@ $<
   8.391  
   8.392  op.o: op.c
   8.393 -	$(CC) $(OP_CFLAGS) $(DEFINES) -c -o $@ $<
   8.394 +	$(CC) $(OP_CFLAGS) $(CPPFLAGS) -c -o $@ $<
   8.395  
   8.396 +# HELPER_CFLAGS is used for all the code compiled with static register
   8.397 +# variables
   8.398 +ifeq ($(TARGET_BASE_ARCH), i386)
   8.399 +# XXX: rename helper.c to op_helper.c
   8.400  helper.o: helper.c
   8.401 -	$(CC) $(HELPER_CFLAGS) $(DEFINES) -c -o $@ $<
   8.402 +	$(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
   8.403 +else
   8.404 +op_helper.o: op_helper.c
   8.405 +	$(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
   8.406 +endif
   8.407 +
   8.408 +cpu-exec.o: cpu-exec.c
   8.409 +	$(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
   8.410 +
   8.411 +# Note: this is a workaround. The real fix is to avoid compiling
   8.412 +# cpu_signal_handler() in cpu-exec.c.
   8.413 +signal.o: signal.c
   8.414 +	$(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
   8.415  
   8.416  ifeq ($(TARGET_BASE_ARCH), i386)
   8.417  op.o: op.c opreg_template.h ops_template.h ops_template_mem.h ops_mem.h ops_sse.h
   8.418 @@ -529,19 +581,12 @@ translate.o: translate.c translate_init.
   8.419  endif
   8.420  
   8.421  ifeq ($(TARGET_ARCH), mips)
   8.422 -op.o: op.c op_template.c op_mem.c
   8.423 +op.o: op.c op_template.c fop_template.c op_mem.c
   8.424  op_helper.o: op_helper_mem.c
   8.425  endif
   8.426  
   8.427  loader.o: loader.c elf_ops.h
   8.428  
   8.429 -acpi.o: acpi.c acpi-dsdt.hex
   8.430 -
   8.431 -ifdef BUILD_ACPI_TABLES
   8.432 -$(SRC_PATH)/hw/acpi-dsdt.hex: acpi-dsdt.dsl
   8.433 -	iasl -tc -p $@ $<
   8.434 -endif
   8.435 -
   8.436  ifeq ($(TARGET_ARCH), sh4)
   8.437  op.o: op.c op_mem.c cpu.h
   8.438  op_helper.o: op_helper.c exec.h cpu.h
   8.439 @@ -555,10 +600,10 @@ endif
   8.440  $(OBJS) $(LIBOBJS) $(VL_OBJS): config.h ../config-host.h
   8.441  
   8.442  %.o: %.c
   8.443 -	$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
   8.444 +	$(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
   8.445  
   8.446  %.o: %.S
   8.447 -	$(CC) $(DEFINES) -c -o $@ $<
   8.448 +	$(CC) $(CPPFLAGS) -c -o $@ $<
   8.449  
   8.450  clean:
   8.451  	rm -f *.o  *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o slirp/*.o fpu/*.o
     9.1 --- a/tools/ioemu/README.distrib	Tue May 08 10:38:06 2007 +0100
     9.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.3 @@ -1,16 +0,0 @@
     9.4 -Information about the various packages used to build the current qemu
     9.5 -x86 binary distribution:
     9.6 -
     9.7 -* gcc 2.95.2 was used for the build. A glibc 2.1.3 Debian distribution
     9.8 -  was used to get most of the binary packages.
     9.9 -
    9.10 -* wine-20020411 tarball
    9.11 -
    9.12 -  ./configure --prefix=/usr/local/wine-i386
    9.13 -  
    9.14 -  All exe and libs were stripped. Some compile time tools and the
    9.15 -  includes were deleted.
    9.16 -
    9.17 -* ldconfig was launched to build the library links:
    9.18 -
    9.19 -  qemu-i386 /usr/gnemul/qemu-i386/bin/ldconfig-i386 -C /usr/gnemul/qemu-i386/etc/ld.so.cache
    10.1 --- a/tools/ioemu/VERSION	Tue May 08 10:38:06 2007 +0100
    10.2 +++ b/tools/ioemu/VERSION	Wed May 09 14:17:15 2007 +0100
    10.3 @@ -1,1 +1,1 @@
    10.4 -0.8.2
    10.5 \ No newline at end of file
    10.6 +0.9.0
    10.7 \ No newline at end of file
    11.1 --- a/tools/ioemu/audio/.CVS/Entries	Tue May 08 10:38:06 2007 +0100
    11.2 +++ b/tools/ioemu/audio/.CVS/Entries	Wed May 09 14:17:15 2007 +0100
    11.3 @@ -1,20 +1,20 @@
    11.4 -/alsaaudio.c/1.7/Sun Aug  6 01:03:49 2006//Trelease_0_8_2
    11.5 -/audio.c/1.14/Sun Aug  6 01:03:50 2006//Trelease_0_8_2
    11.6 -/audio.h/1.8/Sun Aug  6 01:03:50 2006//Trelease_0_8_2
    11.7 -/audio_int.h/1.10/Sun Aug  6 01:03:50 2006//Trelease_0_8_2
    11.8 -/audio_template.h/1.8/Sun Aug  6 01:03:50 2006//Trelease_0_8_2
    11.9 -/coreaudio.c/1.7/Sun Aug  6 01:03:50 2006//Trelease_0_8_2
   11.10 -/dsound_template.h/1.4/Sun Aug  6 01:03:50 2006//Trelease_0_8_2
   11.11 -/dsoundaudio.c/1.3/Sun Aug  6 01:03:50 2006//Trelease_0_8_2
   11.12 -/fmodaudio.c/1.7/Sun Aug  6 01:03:50 2006//Trelease_0_8_2
   11.13 -/mixeng.c/1.4/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
   11.14 -/mixeng.h/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
   11.15 -/mixeng_template.h/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
   11.16 -/noaudio.c/1.7/Sun Aug  6 01:03:50 2006//Trelease_0_8_2
   11.17 -/ossaudio.c/1.11/Sun Aug  6 01:03:50 2006//Trelease_0_8_2
   11.18 -/rate_template.h/1.3/Sun Aug  6 01:03:50 2006//Trelease_0_8_2
   11.19 -/sdlaudio.c/1.8/Sun Aug  6 01:03:50 2006//Trelease_0_8_2
   11.20 -/sys-queue.h/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
   11.21 -/wavaudio.c/1.8/Sun Aug  6 01:03:50 2006//Trelease_0_8_2
   11.22 -/wavcapture.c/1.5/Sat Jul 22 17:06:44 2006//Trelease_0_8_2
   11.23 +/alsaaudio.c/1.7/Fri Jan  5 14:34:35 2007//Trelease_0_9_0
   11.24 +/audio.c/1.15/Thu May  3 17:17:59 2007//Trelease_0_9_0
   11.25 +/audio.h/1.8/Fri Jan  5 14:34:35 2007//Trelease_0_9_0
   11.26 +/audio_int.h/1.10/Fri Jan  5 14:34:35 2007//Trelease_0_9_0
   11.27 +/audio_template.h/1.8/Fri Jan  5 14:34:35 2007//Trelease_0_9_0
   11.28 +/coreaudio.c/1.7/Fri Jan  5 14:34:35 2007//Trelease_0_9_0
   11.29 +/dsound_template.h/1.4/Fri Jan  5 14:34:35 2007//Trelease_0_9_0
   11.30 +/dsoundaudio.c/1.3/Fri Jan  5 14:34:35 2007//Trelease_0_9_0
   11.31 +/fmodaudio.c/1.7/Fri Jan  5 14:34:35 2007//Trelease_0_9_0
   11.32 +/mixeng.c/1.4/Wed Oct 18 10:11:20 2006//Trelease_0_9_0
   11.33 +/mixeng.h/1.2/Wed Oct 18 10:11:20 2006//Trelease_0_9_0
   11.34 +/mixeng_template.h/1.2/Wed Oct 18 10:11:20 2006//Trelease_0_9_0
   11.35 +/noaudio.c/1.7/Fri Jan  5 14:34:35 2007//Trelease_0_9_0
   11.36 +/ossaudio.c/1.11/Fri Jan  5 14:34:35 2007//Trelease_0_9_0
   11.37 +/rate_template.h/1.3/Fri Jan  5 14:34:35 2007//Trelease_0_9_0
   11.38 +/sdlaudio.c/1.8/Fri Jan  5 14:34:35 2007//Trelease_0_9_0
   11.39 +/sys-queue.h/1.1/Wed Oct 18 10:11:20 2006//Trelease_0_9_0
   11.40 +/wavaudio.c/1.9/Thu May  3 17:17:59 2007//Trelease_0_9_0
   11.41 +/wavcapture.c/1.7/Thu May  3 17:17:59 2007//Trelease_0_9_0
   11.42  D
    12.1 --- a/tools/ioemu/audio/.CVS/Tag	Tue May 08 10:38:06 2007 +0100
    12.2 +++ b/tools/ioemu/audio/.CVS/Tag	Wed May 09 14:17:15 2007 +0100
    12.3 @@ -1,1 +1,1 @@
    12.4 -Nrelease_0_8_2
    12.5 +Nrelease_0_9_0
    13.1 --- a/tools/ioemu/audio/wavaudio.c	Tue May 08 10:38:06 2007 +0100
    13.2 +++ b/tools/ioemu/audio/wavaudio.c	Wed May 09 14:17:15 2007 +0100
    13.3 @@ -151,7 +151,7 @@ static int wav_init_out (HWVoiceOut *hw,
    13.4      le_store (hdr + 28, hw->info.freq << (bits16 + stereo), 4);
    13.5      le_store (hdr + 32, 1 << (bits16 + stereo), 2);
    13.6  
    13.7 -    wav->f = fopen (conf.wav_path, "wb");
    13.8 +    wav->f = qemu_fopen (conf.wav_path, "wb");
    13.9      if (!wav->f) {
   13.10          dolog ("Failed to open wave file `%s'\nReason: %s\n",
   13.11                 conf.wav_path, strerror (errno));
   13.12 @@ -185,7 +185,7 @@ static void wav_fini_out (HWVoiceOut *hw
   13.13      qemu_fseek (wav->f, 32, SEEK_CUR);
   13.14      qemu_put_buffer (wav->f, dlen, 4);
   13.15  
   13.16 -    fclose (wav->f);
   13.17 +    qemu_fclose (wav->f);
   13.18      wav->f = NULL;
   13.19  
   13.20      qemu_free (wav->pcm_buf);
    14.1 --- a/tools/ioemu/audio/wavcapture.c	Tue May 08 10:38:06 2007 +0100
    14.2 +++ b/tools/ioemu/audio/wavcapture.c	Wed May 09 14:17:15 2007 +0100
    14.3 @@ -34,22 +34,19 @@ static void wav_destroy (void *opaque)
    14.4      uint32_t datalen = wav->bytes;
    14.5      uint32_t rifflen = datalen + 36;
    14.6  
    14.7 -    if (!wav->f) {
    14.8 -        return;
    14.9 +    if (wav->f) {
   14.10 +        le_store (rlen, rifflen, 4);
   14.11 +        le_store (dlen, datalen, 4);
   14.12 +        
   14.13 +        qemu_fseek (wav->f, 4, SEEK_SET);
   14.14 +        qemu_put_buffer (wav->f, rlen, 4);
   14.15 +        
   14.16 +        qemu_fseek (wav->f, 32, SEEK_CUR);
   14.17 +        qemu_put_buffer (wav->f, dlen, 4);
   14.18 +        qemu_fclose (wav->f);
   14.19      }
   14.20 -
   14.21 -    le_store (rlen, rifflen, 4);
   14.22 -    le_store (dlen, datalen, 4);
   14.23 -
   14.24 -    qemu_fseek (wav->f, 4, SEEK_SET);
   14.25 -    qemu_put_buffer (wav->f, rlen, 4);
   14.26 -
   14.27 -    qemu_fseek (wav->f, 32, SEEK_CUR);
   14.28 -    qemu_put_buffer (wav->f, dlen, 4);
   14.29 -    fclose (wav->f);
   14.30 -    if (wav->path) {
   14.31 -        qemu_free (wav->path);
   14.32 -    }
   14.33 +    
   14.34 +    qemu_free (wav->path);
   14.35  }
   14.36  
   14.37  static void wav_capture (void *opaque, void *buf, int size)
   14.38 @@ -135,7 +132,7 @@ int wav_start_capture (CaptureState *s, 
   14.39      le_store (hdr + 28, freq << shift, 4);
   14.40      le_store (hdr + 32, 1 << shift, 2);
   14.41  
   14.42 -    wav->f = fopen (path, "wb");
   14.43 +    wav->f = qemu_fopen (path, "wb");
   14.44      if (!wav->f) {
   14.45          term_printf ("Failed to open wave file `%s'\nReason: %s\n",
   14.46                       path, strerror (errno));
   14.47 @@ -153,6 +150,8 @@ int wav_start_capture (CaptureState *s, 
   14.48      cap = AUD_add_capture (NULL, &as, &ops, wav);
   14.49      if (!cap) {
   14.50          term_printf ("Failed to add audio capture\n");
   14.51 +        qemu_free (wav->path);
   14.52 +        qemu_fclose (wav->f);
   14.53          qemu_free (wav);
   14.54          return -1;
   14.55      }
    15.1 --- a/tools/ioemu/block-bochs.c	Tue May 08 10:38:06 2007 +0100
    15.2 +++ b/tools/ioemu/block-bochs.c	Wed May 09 14:17:15 2007 +0100
    15.3 @@ -28,7 +28,8 @@
    15.4  /**************************************************************/
    15.5  
    15.6  #define HEADER_MAGIC "Bochs Virtual HD Image"
    15.7 -#define HEADER_VERSION 0x00010000
    15.8 +#define HEADER_VERSION 0x00020000
    15.9 +#define HEADER_V1 0x00010000
   15.10  #define HEADER_SIZE 512
   15.11  
   15.12  #define REDOLOG_TYPE "Redolog"
   15.13 @@ -37,6 +38,26 @@
   15.14  // not allocated: 0xffffffff
   15.15  
   15.16  // always little-endian
   15.17 +struct bochs_header_v1 {
   15.18 +    char magic[32]; // "Bochs Virtual HD Image"
   15.19 +    char type[16]; // "Redolog"
   15.20 +    char subtype[16]; // "Undoable" / "Volatile" / "Growing"
   15.21 +    uint32_t version;
   15.22 +    uint32_t header; // size of header
   15.23 +    
   15.24 +    union {
   15.25 +	struct {
   15.26 +	    uint32_t catalog; // num of entries
   15.27 +	    uint32_t bitmap; // bitmap size
   15.28 +	    uint32_t extent; // extent size
   15.29 +	    uint64_t disk; // disk size
   15.30 +	    char padding[HEADER_SIZE - 64 - 8 - 20];
   15.31 +	} redolog;
   15.32 +	char padding[HEADER_SIZE - 64 - 8];
   15.33 +    } extra;
   15.34 +};
   15.35 +
   15.36 +// always little-endian
   15.37  struct bochs_header {
   15.38      char magic[32]; // "Bochs Virtual HD Image"
   15.39      char type[16]; // "Redolog"
   15.40 @@ -49,8 +70,9 @@ struct bochs_header {
   15.41  	    uint32_t catalog; // num of entries
   15.42  	    uint32_t bitmap; // bitmap size
   15.43  	    uint32_t extent; // extent size
   15.44 +	    uint32_t reserved; // for ???
   15.45  	    uint64_t disk; // disk size
   15.46 -	    char padding[HEADER_SIZE - 64 - 8 - 20];
   15.47 +	    char padding[HEADER_SIZE - 64 - 8 - 24];
   15.48  	} redolog;
   15.49  	char padding[HEADER_SIZE - 64 - 8];
   15.50      } extra;
   15.51 @@ -79,21 +101,23 @@ static int bochs_probe(const uint8_t *bu
   15.52      if (!strcmp(bochs->magic, HEADER_MAGIC) &&
   15.53  	!strcmp(bochs->type, REDOLOG_TYPE) &&
   15.54  	!strcmp(bochs->subtype, GROWING_TYPE) &&
   15.55 -	(le32_to_cpu(bochs->version) == HEADER_VERSION))
   15.56 +	((le32_to_cpu(bochs->version) == HEADER_VERSION) ||
   15.57 +	(le32_to_cpu(bochs->version) == HEADER_V1)))
   15.58  	return 100;
   15.59  
   15.60      return 0;
   15.61  }
   15.62  
   15.63 -static int bochs_open(BlockDriverState *bs, const char *filename)
   15.64 +static int bochs_open(BlockDriverState *bs, const char *filename, int flags)
   15.65  {
   15.66      BDRVBochsState *s = bs->opaque;
   15.67      int fd, i;
   15.68      struct bochs_header bochs;
   15.69 +    struct bochs_header_v1 header_v1;
   15.70  
   15.71 -    fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
   15.72 +    fd = open(filename, O_RDWR | O_BINARY);
   15.73      if (fd < 0) {
   15.74 -        fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
   15.75 +        fd = open(filename, O_RDONLY | O_BINARY);
   15.76          if (fd < 0)
   15.77              return -1;
   15.78      }
   15.79 @@ -109,11 +133,17 @@ static int bochs_open(BlockDriverState *
   15.80      if (strcmp(bochs.magic, HEADER_MAGIC) ||
   15.81          strcmp(bochs.type, REDOLOG_TYPE) ||
   15.82          strcmp(bochs.subtype, GROWING_TYPE) ||
   15.83 -	(le32_to_cpu(bochs.version) != HEADER_VERSION)) {
   15.84 +	((le32_to_cpu(bochs.version) != HEADER_VERSION) &&
   15.85 +	(le32_to_cpu(bochs.version) != HEADER_V1))) {
   15.86          goto fail;
   15.87      }
   15.88  
   15.89 -    bs->total_sectors = le64_to_cpu(bochs.extra.redolog.disk) / 512;
   15.90 +    if (le32_to_cpu(bochs.version) == HEADER_V1) {
   15.91 +      memcpy(&header_v1, &bochs, sizeof(bochs));
   15.92 +      bs->total_sectors = le64_to_cpu(header_v1.extra.redolog.disk) / 512;
   15.93 +    } else {
   15.94 +      bs->total_sectors = le64_to_cpu(bochs.extra.redolog.disk) / 512;
   15.95 +    }
   15.96  
   15.97      lseek(s->fd, le32_to_cpu(bochs.header), SEEK_SET);
   15.98  
    16.1 --- a/tools/ioemu/block-cloop.c	Tue May 08 10:38:06 2007 +0100
    16.2 +++ b/tools/ioemu/block-cloop.c	Wed May 09 14:17:15 2007 +0100
    16.3 @@ -50,14 +50,14 @@ static int cloop_probe(const uint8_t *bu
    16.4      return 0;
    16.5  }
    16.6  
    16.7 -static int cloop_open(BlockDriverState *bs, const char *filename)
    16.8 +static int cloop_open(BlockDriverState *bs, const char *filename, int flags)
    16.9  {
   16.10      BDRVCloopState *s = bs->opaque;
   16.11      uint32_t offsets_size,max_compressed_block_size=1,i;
   16.12  
   16.13 -    s->fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
   16.14 +    s->fd = open(filename, O_RDONLY | O_BINARY);
   16.15      if (s->fd < 0)
   16.16 -        return -1;
   16.17 +        return -errno;
   16.18      bs->read_only = 1;
   16.19  
   16.20      /* read header */
    17.1 --- a/tools/ioemu/block-cow.c	Tue May 08 10:38:06 2007 +0100
    17.2 +++ b/tools/ioemu/block-cow.c	Wed May 09 14:17:15 2007 +0100
    17.3 @@ -62,7 +62,7 @@ static int cow_probe(const uint8_t *buf,
    17.4          return 0;
    17.5  }
    17.6  
    17.7 -static int cow_open(BlockDriverState *bs, const char *filename)
    17.8 +static int cow_open(BlockDriverState *bs, const char *filename, int flags)
    17.9  {
   17.10      BDRVCowState *s = bs->opaque;
   17.11      int fd;
   17.12 @@ -93,22 +93,6 @@ static int cow_open(BlockDriverState *bs
   17.13      pstrcpy(bs->backing_file, sizeof(bs->backing_file), 
   17.14              cow_header.backing_file);
   17.15      
   17.16 -#if 0
   17.17 -    if (cow_header.backing_file[0] != '\0') {
   17.18 -        if (stat(cow_header.backing_file, &st) != 0) {
   17.19 -            fprintf(stderr, "%s: could not find original disk image '%s'\n", filename, cow_header.backing_file);
   17.20 -            goto fail;
   17.21 -        }
   17.22 -        if (st.st_mtime != be32_to_cpu(cow_header.mtime)) {
   17.23 -            fprintf(stderr, "%s: original raw disk image '%s' does not match saved timestamp\n", filename, cow_header.backing_file);
   17.24 -            goto fail;
   17.25 -            }
   17.26 -        fd = open(cow_header.backing_file, O_RDONLY | O_LARGEFILE);
   17.27 -        if (fd < 0)
   17.28 -            goto fail;
   17.29 -        bs->fd = fd;
   17.30 -    }
   17.31 -#endif
   17.32      /* mmap the bitmap */
   17.33      s->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
   17.34      s->cow_bitmap_addr = mmap(get_mmap_addr(s->cow_bitmap_size), 
   17.35 @@ -179,8 +163,15 @@ static int cow_read(BlockDriverState *bs
   17.36              if (ret != n * 512) 
   17.37                  return -1;
   17.38          } else {
   17.39 +            if (bs->backing_hd) {
   17.40 +                /* read from the base image */
   17.41 +                ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
   17.42 +                if (ret < 0)
   17.43 +                    return -1;
   17.44 +            } else {
   17.45              memset(buf, 0, n * 512);
   17.46          }
   17.47 +        }
   17.48          nb_sectors -= n;
   17.49          sector_num += n;
   17.50          buf += n * 512;
   17.51 @@ -220,7 +211,7 @@ static int cow_create(const char *filena
   17.52      if (flags)
   17.53          return -ENOTSUP;
   17.54  
   17.55 -    cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 
   17.56 +    cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 
   17.57                0644);
   17.58      if (cow_fd < 0)
   17.59          return -1;
   17.60 @@ -228,18 +219,23 @@ static int cow_create(const char *filena
   17.61      cow_header.magic = cpu_to_be32(COW_MAGIC);
   17.62      cow_header.version = cpu_to_be32(COW_VERSION);
   17.63      if (image_filename) {
   17.64 +        /* Note: if no file, we put a dummy mtime */
   17.65 +        cow_header.mtime = cpu_to_be32(0);
   17.66 +
   17.67          fd = open(image_filename, O_RDONLY | O_BINARY);
   17.68          if (fd < 0) {
   17.69              close(cow_fd);
   17.70 -            return -1;
   17.71 +            goto mtime_fail;
   17.72          }
   17.73          if (fstat(fd, &st) != 0) {
   17.74              close(fd);
   17.75 -            return -1;
   17.76 +            goto mtime_fail;
   17.77          }
   17.78          close(fd);
   17.79          cow_header.mtime = cpu_to_be32(st.st_mtime);
   17.80 -        realpath(image_filename, cow_header.backing_file);
   17.81 +    mtime_fail:
   17.82 +        pstrcpy(cow_header.backing_file, sizeof(cow_header.backing_file),
   17.83 +                image_filename);
   17.84      }
   17.85      cow_header.sectorsize = cpu_to_be32(512);
   17.86      cow_header.size = cpu_to_be64(image_sectors * 512);
    18.1 --- a/tools/ioemu/block-dmg.c	Tue May 08 10:38:06 2007 +0100
    18.2 +++ b/tools/ioemu/block-dmg.c	Wed May 09 14:17:15 2007 +0100
    18.3 @@ -73,16 +73,16 @@ static off_t read_uint32(int fd)
    18.4  	return be32_to_cpu(buffer);
    18.5  }
    18.6  
    18.7 -static int dmg_open(BlockDriverState *bs, const char *filename)
    18.8 +static int dmg_open(BlockDriverState *bs, const char *filename, int flags)
    18.9  {
   18.10      BDRVDMGState *s = bs->opaque;
   18.11      off_t info_begin,info_end,last_in_offset,last_out_offset;
   18.12      uint32_t count;
   18.13      uint32_t max_compressed_size=1,max_sectors_per_chunk=1,i;
   18.14  
   18.15 -    s->fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
   18.16 +    s->fd = open(filename, O_RDONLY | O_BINARY);
   18.17      if (s->fd < 0)
   18.18 -        return -1;
   18.19 +        return -errno;
   18.20      bs->read_only = 1;
   18.21      s->n_chunks = 0;
   18.22      s->offsets = s->lengths = s->sectors = s->sectorcounts = 0;
   18.23 @@ -93,7 +93,7 @@ dmg_close:
   18.24  	close(s->fd);
   18.25  	/* open raw instead */
   18.26  	bs->drv=&bdrv_raw;
   18.27 -	return bs->drv->bdrv_open(bs,filename);
   18.28 +	return bs->drv->bdrv_open(bs, filename, flags);
   18.29      }
   18.30      info_begin=read_off(s->fd);
   18.31      if(info_begin==0)
    19.1 --- a/tools/ioemu/block-qcow.c	Tue May 08 10:38:06 2007 +0100
    19.2 +++ b/tools/ioemu/block-qcow.c	Wed May 09 14:17:15 2007 +0100
    19.3 @@ -1,7 +1,7 @@
    19.4  /*
    19.5   * Block driver for the QCOW format
    19.6   * 
    19.7 - * Copyright (c) 2004 Fabrice Bellard
    19.8 + * Copyright (c) 2004-2006 Fabrice Bellard
    19.9   * 
   19.10   * Permission is hereby granted, free of charge, to any person obtaining a copy
   19.11   * of this software and associated documentation files (the "Software"), to deal
   19.12 @@ -53,7 +53,7 @@ typedef struct QCowHeader {
   19.13  #define L2_CACHE_SIZE 16
   19.14  
   19.15  typedef struct BDRVQcowState {
   19.16 -    int fd;
   19.17 +    BlockDriverState *hd;
   19.18      int cluster_bits;
   19.19      int cluster_size;
   19.20      int cluster_sectors;
   19.21 @@ -89,20 +89,16 @@ static int qcow_probe(const uint8_t *buf
   19.22          return 0;
   19.23  }
   19.24  
   19.25 -static int qcow_open(BlockDriverState *bs, const char *filename)
   19.26 +static int qcow_open(BlockDriverState *bs, const char *filename, int flags)
   19.27  {
   19.28      BDRVQcowState *s = bs->opaque;
   19.29 -    int fd, len, i, shift;
   19.30 +    int len, i, shift, ret;
   19.31      QCowHeader header;
   19.32 -    
   19.33 -    fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
   19.34 -    if (fd < 0) {
   19.35 -        fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
   19.36 -        if (fd < 0)
   19.37 -            return -1;
   19.38 -    }
   19.39 -    s->fd = fd;
   19.40 -    if (read(fd, &header, sizeof(header)) != sizeof(header))
   19.41 +
   19.42 +    ret = bdrv_file_open(&s->hd, filename, flags);
   19.43 +    if (ret < 0)
   19.44 +        return ret;
   19.45 +    if (bdrv_pread(s->hd, 0, &header, sizeof(header)) != sizeof(header))
   19.46          goto fail;
   19.47      be32_to_cpus(&header.magic);
   19.48      be32_to_cpus(&header.version);
   19.49 @@ -138,8 +134,7 @@ static int qcow_open(BlockDriverState *b
   19.50      s->l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
   19.51      if (!s->l1_table)
   19.52          goto fail;
   19.53 -    lseek(fd, s->l1_table_offset, SEEK_SET);
   19.54 -    if (read(fd, s->l1_table, s->l1_size * sizeof(uint64_t)) != 
   19.55 +    if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)) != 
   19.56          s->l1_size * sizeof(uint64_t))
   19.57          goto fail;
   19.58      for(i = 0;i < s->l1_size; i++) {
   19.59 @@ -162,8 +157,7 @@ static int qcow_open(BlockDriverState *b
   19.60          len = header.backing_file_size;
   19.61          if (len > 1023)
   19.62              len = 1023;
   19.63 -        lseek(fd, header.backing_file_offset, SEEK_SET);
   19.64 -        if (read(fd, bs->backing_file, len) != len)
   19.65 +        if (bdrv_pread(s->hd, header.backing_file_offset, bs->backing_file, len) != len)
   19.66              goto fail;
   19.67          bs->backing_file[len] = '\0';
   19.68      }
   19.69 @@ -174,7 +168,7 @@ static int qcow_open(BlockDriverState *b
   19.70      qemu_free(s->l2_cache);
   19.71      qemu_free(s->cluster_cache);
   19.72      qemu_free(s->cluster_data);
   19.73 -    close(fd);
   19.74 +    bdrv_delete(s->hd);
   19.75      return -1;
   19.76  }
   19.77  
   19.78 @@ -276,14 +270,14 @@ static uint64_t get_cluster_offset(Block
   19.79          if (!allocate)
   19.80              return 0;
   19.81          /* allocate a new l2 entry */
   19.82 -        l2_offset = lseek(s->fd, 0, SEEK_END);
   19.83 +        l2_offset = bdrv_getlength(s->hd);
   19.84          /* round to cluster size */
   19.85          l2_offset = (l2_offset + s->cluster_size - 1) & ~(s->cluster_size - 1);
   19.86          /* update the L1 entry */
   19.87          s->l1_table[l1_index] = l2_offset;
   19.88          tmp = cpu_to_be64(l2_offset);
   19.89 -        lseek(s->fd, s->l1_table_offset + l1_index * sizeof(tmp), SEEK_SET);
   19.90 -        if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
   19.91 +        if (bdrv_pwrite(s->hd, s->l1_table_offset + l1_index * sizeof(tmp), 
   19.92 +                        &tmp, sizeof(tmp)) != sizeof(tmp))
   19.93              return 0;
   19.94          new_l2_table = 1;
   19.95      }
   19.96 @@ -309,14 +303,13 @@ static uint64_t get_cluster_offset(Block
   19.97          }
   19.98      }
   19.99      l2_table = s->l2_cache + (min_index << s->l2_bits);
  19.100 -    lseek(s->fd, l2_offset, SEEK_SET);
  19.101      if (new_l2_table) {
  19.102          memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
  19.103 -        if (write(s->fd, l2_table, s->l2_size * sizeof(uint64_t)) !=
  19.104 +        if (bdrv_pwrite(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) !=
  19.105              s->l2_size * sizeof(uint64_t))
  19.106              return 0;
  19.107      } else {
  19.108 -        if (read(s->fd, l2_table, s->l2_size * sizeof(uint64_t)) != 
  19.109 +        if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) != 
  19.110              s->l2_size * sizeof(uint64_t))
  19.111              return 0;
  19.112      }
  19.113 @@ -337,36 +330,35 @@ static uint64_t get_cluster_offset(Block
  19.114                 overwritten */
  19.115              if (decompress_cluster(s, cluster_offset) < 0)
  19.116                  return 0;
  19.117 -            cluster_offset = lseek(s->fd, 0, SEEK_END);
  19.118 +            cluster_offset = bdrv_getlength(s->hd);
  19.119              cluster_offset = (cluster_offset + s->cluster_size - 1) & 
  19.120                  ~(s->cluster_size - 1);
  19.121              /* write the cluster content */
  19.122 -            lseek(s->fd, cluster_offset, SEEK_SET);
  19.123 -            if (write(s->fd, s->cluster_cache, s->cluster_size) != 
  19.124 +            if (bdrv_pwrite(s->hd, cluster_offset, s->cluster_cache, s->cluster_size) != 
  19.125                  s->cluster_size)
  19.126                  return -1;
  19.127          } else {
  19.128 -            cluster_offset = lseek(s->fd, 0, SEEK_END);
  19.129 +            cluster_offset = bdrv_getlength(s->hd);
  19.130              if (allocate == 1) {
  19.131                  /* round to cluster size */
  19.132                  cluster_offset = (cluster_offset + s->cluster_size - 1) & 
  19.133                      ~(s->cluster_size - 1);
  19.134 -                ftruncate(s->fd, cluster_offset + s->cluster_size);
  19.135 +                bdrv_truncate(s->hd, cluster_offset + s->cluster_size);
  19.136                  /* if encrypted, we must initialize the cluster
  19.137                     content which won't be written */
  19.138                  if (s->crypt_method && 
  19.139                      (n_end - n_start) < s->cluster_sectors) {
  19.140                      uint64_t start_sect;
  19.141                      start_sect = (offset & ~(s->cluster_size - 1)) >> 9;
  19.142 -                    memset(s->cluster_data + 512, 0xaa, 512);
  19.143 +                    memset(s->cluster_data + 512, 0x00, 512);
  19.144                      for(i = 0; i < s->cluster_sectors; i++) {
  19.145                          if (i < n_start || i >= n_end) {
  19.146                              encrypt_sectors(s, start_sect + i, 
  19.147                                              s->cluster_data, 
  19.148                                              s->cluster_data + 512, 1, 1,
  19.149                                              &s->aes_encrypt_key);
  19.150 -                            lseek(s->fd, cluster_offset + i * 512, SEEK_SET);
  19.151 -                            if (write(s->fd, s->cluster_data, 512) != 512)
  19.152 +                            if (bdrv_pwrite(s->hd, cluster_offset + i * 512, 
  19.153 +                                            s->cluster_data, 512) != 512)
  19.154                                  return -1;
  19.155                          }
  19.156                      }
  19.157 @@ -379,8 +371,8 @@ static uint64_t get_cluster_offset(Block
  19.158          /* update L2 table */
  19.159          tmp = cpu_to_be64(cluster_offset);
  19.160          l2_table[l2_index] = tmp;
  19.161 -        lseek(s->fd, l2_offset + l2_index * sizeof(tmp), SEEK_SET);
  19.162 -        if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
  19.163 +        if (bdrv_pwrite(s->hd, 
  19.164 +                        l2_offset + l2_index * sizeof(tmp), &tmp, sizeof(tmp)) != sizeof(tmp))
  19.165              return 0;
  19.166      }
  19.167      return cluster_offset;
  19.168 @@ -438,8 +430,7 @@ static int decompress_cluster(BDRVQcowSt
  19.169      if (s->cluster_cache_offset != coffset) {
  19.170          csize = cluster_offset >> (63 - s->cluster_bits);
  19.171          csize &= (s->cluster_size - 1);
  19.172 -        lseek(s->fd, coffset, SEEK_SET);
  19.173 -        ret = read(s->fd, s->cluster_data, csize);
  19.174 +        ret = bdrv_pread(s->hd, coffset, s->cluster_data, csize);
  19.175          if (ret != csize) 
  19.176              return -1;
  19.177          if (decompress_buffer(s->cluster_cache, s->cluster_size,
  19.178 @@ -451,6 +442,8 @@ static int decompress_cluster(BDRVQcowSt
  19.179      return 0;
  19.180  }
  19.181  
  19.182 +#if 0
  19.183 +
  19.184  static int qcow_read(BlockDriverState *bs, int64_t sector_num, 
  19.185                       uint8_t *buf, int nb_sectors)
  19.186  {
  19.187 @@ -465,14 +458,20 @@ static int qcow_read(BlockDriverState *b
  19.188          if (n > nb_sectors)
  19.189              n = nb_sectors;
  19.190          if (!cluster_offset) {
  19.191 -            memset(buf, 0, 512 * n);
  19.192 +            if (bs->backing_hd) {
  19.193 +                /* read from the base image */
  19.194 +                ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
  19.195 +                if (ret < 0)
  19.196 +                    return -1;
  19.197 +            } else {
  19.198 +                memset(buf, 0, 512 * n);
  19.199 +            }
  19.200          } else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
  19.201              if (decompress_cluster(s, cluster_offset) < 0)
  19.202                  return -1;
  19.203              memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n);
  19.204          } else {
  19.205 -            lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
  19.206 -            ret = read(s->fd, buf, n * 512);
  19.207 +            ret = bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512);
  19.208              if (ret != n * 512) 
  19.209                  return -1;
  19.210              if (s->crypt_method) {
  19.211 @@ -486,6 +485,7 @@ static int qcow_read(BlockDriverState *b
  19.212      }
  19.213      return 0;
  19.214  }
  19.215 +#endif
  19.216  
  19.217  static int qcow_write(BlockDriverState *bs, int64_t sector_num, 
  19.218                       const uint8_t *buf, int nb_sectors)
  19.219 @@ -504,13 +504,13 @@ static int qcow_write(BlockDriverState *
  19.220                                              index_in_cluster + n);
  19.221          if (!cluster_offset)
  19.222              return -1;
  19.223 -        lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
  19.224          if (s->crypt_method) {
  19.225              encrypt_sectors(s, sector_num, s->cluster_data, buf, n, 1,
  19.226                              &s->aes_encrypt_key);
  19.227 -            ret = write(s->fd, s->cluster_data, n * 512);
  19.228 +            ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, 
  19.229 +                              s->cluster_data, n * 512);
  19.230          } else {
  19.231 -            ret = write(s->fd, buf, n * 512);
  19.232 +            ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512);
  19.233          }
  19.234          if (ret != n * 512) 
  19.235              return -1;
  19.236 @@ -522,6 +522,209 @@ static int qcow_write(BlockDriverState *
  19.237      return 0;
  19.238  }
  19.239  
  19.240 +typedef struct QCowAIOCB {
  19.241 +    BlockDriverAIOCB common;
  19.242 +    int64_t sector_num;
  19.243 +    uint8_t *buf;
  19.244 +    int nb_sectors;
  19.245 +    int n;
  19.246 +    uint64_t cluster_offset;
  19.247 +    uint8_t *cluster_data; 
  19.248 +    BlockDriverAIOCB *hd_aiocb;
  19.249 +} QCowAIOCB;
  19.250 +
  19.251 +static void qcow_aio_read_cb(void *opaque, int ret)
  19.252 +{
  19.253 +    QCowAIOCB *acb = opaque;
  19.254 +    BlockDriverState *bs = acb->common.bs;
  19.255 +    BDRVQcowState *s = bs->opaque;
  19.256 +    int index_in_cluster;
  19.257 +
  19.258 +    acb->hd_aiocb = NULL;
  19.259 +    if (ret < 0) {
  19.260 +    fail:
  19.261 +        acb->common.cb(acb->common.opaque, ret);
  19.262 +        qemu_aio_release(acb);
  19.263 +        return;
  19.264 +    }
  19.265 +
  19.266 + redo:
  19.267 +    /* post process the read buffer */
  19.268 +    if (!acb->cluster_offset) {
  19.269 +        /* nothing to do */
  19.270 +    } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
  19.271 +        /* nothing to do */
  19.272 +    } else {
  19.273 +        if (s->crypt_method) {
  19.274 +            encrypt_sectors(s, acb->sector_num, acb->buf, acb->buf, 
  19.275 +                            acb->n, 0, 
  19.276 +                            &s->aes_decrypt_key);
  19.277 +        }
  19.278 +    }
  19.279 +
  19.280 +    acb->nb_sectors -= acb->n;
  19.281 +    acb->sector_num += acb->n;
  19.282 +    acb->buf += acb->n * 512;
  19.283 +
  19.284 +    if (acb->nb_sectors == 0) {
  19.285 +        /* request completed */
  19.286 +        acb->common.cb(acb->common.opaque, 0);
  19.287 +        qemu_aio_release(acb);
  19.288 +        return;
  19.289 +    }
  19.290 +    
  19.291 +    /* prepare next AIO request */
  19.292 +    acb->cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, 
  19.293 +                                             0, 0, 0, 0);
  19.294 +    index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
  19.295 +    acb->n = s->cluster_sectors - index_in_cluster;
  19.296 +    if (acb->n > acb->nb_sectors)
  19.297 +        acb->n = acb->nb_sectors;
  19.298 +
  19.299 +    if (!acb->cluster_offset) {
  19.300 +        if (bs->backing_hd) {
  19.301 +            /* read from the base image */
  19.302 +            acb->hd_aiocb = bdrv_aio_read(bs->backing_hd,
  19.303 +                acb->sector_num, acb->buf, acb->n, qcow_aio_read_cb, acb);
  19.304 +            if (acb->hd_aiocb == NULL)
  19.305 +                goto fail;
  19.306 +        } else {
  19.307 +            /* Note: in this case, no need to wait */
  19.308 +            memset(acb->buf, 0, 512 * acb->n);
  19.309 +            goto redo;
  19.310 +        }
  19.311 +    } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
  19.312 +        /* add AIO support for compressed blocks ? */
  19.313 +        if (decompress_cluster(s, acb->cluster_offset) < 0)
  19.314 +            goto fail;
  19.315 +        memcpy(acb->buf, 
  19.316 +               s->cluster_cache + index_in_cluster * 512, 512 * acb->n);
  19.317 +        goto redo;
  19.318 +    } else {
  19.319 +        if ((acb->cluster_offset & 511) != 0) {
  19.320 +            ret = -EIO;
  19.321 +            goto fail;
  19.322 +        }
  19.323 +        acb->hd_aiocb = bdrv_aio_read(s->hd,
  19.324 +                            (acb->cluster_offset >> 9) + index_in_cluster, 
  19.325 +                            acb->buf, acb->n, qcow_aio_read_cb, acb);
  19.326 +        if (acb->hd_aiocb == NULL)
  19.327 +            goto fail;
  19.328 +    }
  19.329 +}
  19.330 +
  19.331 +static BlockDriverAIOCB *qcow_aio_read(BlockDriverState *bs,
  19.332 +        int64_t sector_num, uint8_t *buf, int nb_sectors,
  19.333 +        BlockDriverCompletionFunc *cb, void *opaque)
  19.334 +{
  19.335 +    QCowAIOCB *acb;
  19.336 +
  19.337 +    acb = qemu_aio_get(bs, cb, opaque);
  19.338 +    if (!acb)
  19.339 +        return NULL;
  19.340 +    acb->hd_aiocb = NULL;
  19.341 +    acb->sector_num = sector_num;
  19.342 +    acb->buf = buf;
  19.343 +    acb->nb_sectors = nb_sectors;
  19.344 +    acb->n = 0;
  19.345 +    acb->cluster_offset = 0;    
  19.346 +
  19.347 +    qcow_aio_read_cb(acb, 0);
  19.348 +    return &acb->common;
  19.349 +}
  19.350 +
  19.351 +static void qcow_aio_write_cb(void *opaque, int ret)
  19.352 +{
  19.353 +    QCowAIOCB *acb = opaque;
  19.354 +    BlockDriverState *bs = acb->common.bs;
  19.355 +    BDRVQcowState *s = bs->opaque;
  19.356 +    int index_in_cluster;
  19.357 +    uint64_t cluster_offset;
  19.358 +    const uint8_t *src_buf;
  19.359 +
  19.360 +    acb->hd_aiocb = NULL;
  19.361 +
  19.362 +    if (ret < 0) {
  19.363 +    fail:
  19.364 +        acb->common.cb(acb->common.opaque, ret);
  19.365 +        qemu_aio_release(acb);
  19.366 +        return;
  19.367 +    }
  19.368 +
  19.369 +    acb->nb_sectors -= acb->n;
  19.370 +    acb->sector_num += acb->n;
  19.371 +    acb->buf += acb->n * 512;
  19.372 +
  19.373 +    if (acb->nb_sectors == 0) {
  19.374 +        /* request completed */
  19.375 +        acb->common.cb(acb->common.opaque, 0);
  19.376 +        qemu_aio_release(acb);
  19.377 +        return;
  19.378 +    }
  19.379 +    
  19.380 +    index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
  19.381 +    acb->n = s->cluster_sectors - index_in_cluster;
  19.382 +    if (acb->n > acb->nb_sectors)
  19.383 +        acb->n = acb->nb_sectors;
  19.384 +    cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, 1, 0, 
  19.385 +                                        index_in_cluster, 
  19.386 +                                        index_in_cluster + acb->n);
  19.387 +    if (!cluster_offset || (cluster_offset & 511) != 0) {
  19.388 +        ret = -EIO;
  19.389 +        goto fail;
  19.390 +    }
  19.391 +    if (s->crypt_method) {
  19.392 +        if (!acb->cluster_data) {
  19.393 +            acb->cluster_data = qemu_mallocz(s->cluster_size);
  19.394 +            if (!acb->cluster_data) {
  19.395 +                ret = -ENOMEM;
  19.396 +                goto fail;
  19.397 +            }
  19.398 +        }
  19.399 +        encrypt_sectors(s, acb->sector_num, acb->cluster_data, acb->buf, 
  19.400 +                        acb->n, 1, &s->aes_encrypt_key);
  19.401 +        src_buf = acb->cluster_data;
  19.402 +    } else {
  19.403 +        src_buf = acb->buf;
  19.404 +    }
  19.405 +    acb->hd_aiocb = bdrv_aio_write(s->hd,
  19.406 +                                   (cluster_offset >> 9) + index_in_cluster, 
  19.407 +                                   src_buf, acb->n, 
  19.408 +                                   qcow_aio_write_cb, acb);
  19.409 +    if (acb->hd_aiocb == NULL)
  19.410 +        goto fail;
  19.411 +}
  19.412 +
  19.413 +static BlockDriverAIOCB *qcow_aio_write(BlockDriverState *bs,
  19.414 +        int64_t sector_num, const uint8_t *buf, int nb_sectors,
  19.415 +        BlockDriverCompletionFunc *cb, void *opaque)
  19.416 +{
  19.417 +    BDRVQcowState *s = bs->opaque;
  19.418 +    QCowAIOCB *acb;
  19.419 +    
  19.420 +    s->cluster_cache_offset = -1; /* disable compressed cache */
  19.421 +
  19.422 +    acb = qemu_aio_get(bs, cb, opaque);
  19.423 +    if (!acb)
  19.424 +        return NULL;
  19.425 +    acb->hd_aiocb = NULL;
  19.426 +    acb->sector_num = sector_num;
  19.427 +    acb->buf = (uint8_t *)buf;
  19.428 +    acb->nb_sectors = nb_sectors;
  19.429 +    acb->n = 0;
  19.430 +    
  19.431 +    qcow_aio_write_cb(acb, 0);
  19.432 +    return &acb->common;
  19.433 +}
  19.434 +
  19.435 +static void qcow_aio_cancel(BlockDriverAIOCB *blockacb)
  19.436 +{
  19.437 +    QCowAIOCB *acb = (QCowAIOCB *)blockacb;
  19.438 +    if (acb->hd_aiocb)
  19.439 +        bdrv_aio_cancel(acb->hd_aiocb);
  19.440 +    qemu_aio_release(acb);
  19.441 +}
  19.442 +
  19.443  static void qcow_close(BlockDriverState *bs)
  19.444  {
  19.445      BDRVQcowState *s = bs->opaque;
  19.446 @@ -529,7 +732,7 @@ static void qcow_close(BlockDriverState 
  19.447      qemu_free(s->l2_cache);
  19.448      qemu_free(s->cluster_cache);
  19.449      qemu_free(s->cluster_data);
  19.450 -    close(s->fd);
  19.451 +    bdrv_delete(s->hd);
  19.452  }
  19.453  
  19.454  static int qcow_create(const char *filename, int64_t total_size,
  19.455 @@ -537,12 +740,9 @@ static int qcow_create(const char *filen
  19.456  {
  19.457      int fd, header_size, backing_filename_len, l1_size, i, shift;
  19.458      QCowHeader header;
  19.459 -    char backing_filename[1024];
  19.460      uint64_t tmp;
  19.461 -    struct stat st;
  19.462  
  19.463 -    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 
  19.464 -              0644);
  19.465 +    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
  19.466      if (fd < 0)
  19.467          return -1;
  19.468      memset(&header, 0, sizeof(header));
  19.469 @@ -552,28 +752,11 @@ static int qcow_create(const char *filen
  19.470      header_size = sizeof(header);
  19.471      backing_filename_len = 0;
  19.472      if (backing_file) {
  19.473 -	if (strcmp(backing_file, "fat:")) {
  19.474 -	    const char *p;
  19.475 -	    /* XXX: this is a hack: we do not attempt to check for URL
  19.476 -	       like syntax */
  19.477 -	    p = strchr(backing_file, ':');
  19.478 -	    if (p && (p - backing_file) >= 2) {
  19.479 -		/* URL like but exclude "c:" like filenames */
  19.480 -		pstrcpy(backing_filename, sizeof(backing_filename),
  19.481 -			backing_file);
  19.482 -	    } else {
  19.483 -		realpath(backing_file, backing_filename);
  19.484 -		if (stat(backing_filename, &st) != 0) {
  19.485 -		    return -1;
  19.486 -		}
  19.487 -	    }
  19.488 -	    header.backing_file_offset = cpu_to_be64(header_size);
  19.489 -	    backing_filename_len = strlen(backing_filename);
  19.490 -	    header.backing_file_size = cpu_to_be32(backing_filename_len);
  19.491 -	    header_size += backing_filename_len;
  19.492 -	} else
  19.493 -	    backing_file = NULL;
  19.494 -        header.mtime = cpu_to_be32(st.st_mtime);
  19.495 +        header.backing_file_offset = cpu_to_be64(header_size);
  19.496 +        backing_filename_len = strlen(backing_file);
  19.497 +        header.backing_file_size = cpu_to_be32(backing_filename_len);
  19.498 +        header_size += backing_filename_len;
  19.499 +        header.mtime = cpu_to_be32(0);
  19.500          header.cluster_bits = 9; /* 512 byte cluster to avoid copying
  19.501                                      unmodifyed sectors */
  19.502          header.l2_bits = 12; /* 32 KB L2 tables */
  19.503 @@ -595,7 +778,7 @@ static int qcow_create(const char *filen
  19.504      /* write all the data */
  19.505      write(fd, &header, sizeof(header));
  19.506      if (backing_file) {
  19.507 -        write(fd, backing_filename, backing_filename_len);
  19.508 +        write(fd, backing_file, backing_filename_len);
  19.509      }
  19.510      lseek(fd, header_size, SEEK_SET);
  19.511      tmp = 0;
  19.512 @@ -606,16 +789,18 @@ static int qcow_create(const char *filen
  19.513      return 0;
  19.514  }
  19.515  
  19.516 -int qcow_make_empty(BlockDriverState *bs)
  19.517 +static int qcow_make_empty(BlockDriverState *bs)
  19.518  {
  19.519      BDRVQcowState *s = bs->opaque;
  19.520      uint32_t l1_length = s->l1_size * sizeof(uint64_t);
  19.521 +    int ret;
  19.522  
  19.523      memset(s->l1_table, 0, l1_length);
  19.524 -    lseek(s->fd, s->l1_table_offset, SEEK_SET);
  19.525 -    if (write(s->fd, s->l1_table, l1_length) < 0)
  19.526 +    if (bdrv_pwrite(s->hd, s->l1_table_offset, s->l1_table, l1_length) < 0)
  19.527  	return -1;
  19.528 -    ftruncate(s->fd, s->l1_table_offset + l1_length);
  19.529 +    ret = bdrv_truncate(s->hd, s->l1_table_offset + l1_length);
  19.530 +    if (ret < 0)
  19.531 +        return ret;
  19.532  
  19.533      memset(s->l2_cache, 0, s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
  19.534      memset(s->l2_cache_offsets, 0, L2_CACHE_SIZE * sizeof(uint64_t));
  19.535 @@ -624,18 +809,10 @@ int qcow_make_empty(BlockDriverState *bs
  19.536      return 0;
  19.537  }
  19.538  
  19.539 -int qcow_get_cluster_size(BlockDriverState *bs)
  19.540 -{
  19.541 -    BDRVQcowState *s = bs->opaque;
  19.542 -    if (bs->drv != &bdrv_qcow)
  19.543 -        return -1;
  19.544 -    return s->cluster_size;
  19.545 -}
  19.546 -
  19.547  /* XXX: put compressed sectors first, then all the cluster aligned
  19.548     tables to avoid losing bytes in alignment */
  19.549 -int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num, 
  19.550 -                          const uint8_t *buf)
  19.551 +static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, 
  19.552 +                                 const uint8_t *buf, int nb_sectors)
  19.553  {
  19.554      BDRVQcowState *s = bs->opaque;
  19.555      z_stream strm;
  19.556 @@ -643,8 +820,8 @@ int qcow_compress_cluster(BlockDriverSta
  19.557      uint8_t *out_buf;
  19.558      uint64_t cluster_offset;
  19.559  
  19.560 -    if (bs->drv != &bdrv_qcow)
  19.561 -        return -1;
  19.562 +    if (nb_sectors != s->cluster_sectors)
  19.563 +        return -EINVAL;
  19.564  
  19.565      out_buf = qemu_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);
  19.566      if (!out_buf)
  19.567 @@ -682,8 +859,7 @@ int qcow_compress_cluster(BlockDriverSta
  19.568          cluster_offset = get_cluster_offset(bs, sector_num << 9, 2, 
  19.569                                              out_len, 0, 0);
  19.570          cluster_offset &= s->cluster_offset_mask;
  19.571 -        lseek(s->fd, cluster_offset, SEEK_SET);
  19.572 -        if (write(s->fd, out_buf, out_len) != out_len) {
  19.573 +        if (bdrv_pwrite(s->hd, cluster_offset, out_buf, out_len) != out_len) {
  19.574              qemu_free(out_buf);
  19.575              return -1;
  19.576          }
  19.577 @@ -696,7 +872,14 @@ int qcow_compress_cluster(BlockDriverSta
  19.578  static void qcow_flush(BlockDriverState *bs)
  19.579  {
  19.580      BDRVQcowState *s = bs->opaque;
  19.581 -    fsync(s->fd);
  19.582 +    bdrv_flush(s->hd);
  19.583 +}
  19.584 +
  19.585 +static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
  19.586 +{
  19.587 +    BDRVQcowState *s = bs->opaque;
  19.588 +    bdi->cluster_size = s->cluster_size;
  19.589 +    return 0;
  19.590  }
  19.591  
  19.592  BlockDriver bdrv_qcow = {
  19.593 @@ -704,14 +887,19 @@ BlockDriver bdrv_qcow = {
  19.594      sizeof(BDRVQcowState),
  19.595      qcow_probe,
  19.596      qcow_open,
  19.597 -    qcow_read,
  19.598 -    qcow_write,
  19.599 +    NULL,
  19.600 +    NULL,
  19.601      qcow_close,
  19.602      qcow_create,
  19.603      qcow_flush,
  19.604      qcow_is_allocated,
  19.605      qcow_set_key,
  19.606 -    qcow_make_empty
  19.607 +    qcow_make_empty,
  19.608 +
  19.609 +    .bdrv_aio_read = qcow_aio_read,
  19.610 +    .bdrv_aio_write = qcow_aio_write,
  19.611 +    .bdrv_aio_cancel = qcow_aio_cancel,
  19.612 +    .aiocb_size = sizeof(QCowAIOCB),
  19.613 +    .bdrv_write_compressed = qcow_write_compressed,
  19.614 +    .bdrv_get_info = qcow_get_info,
  19.615  };
  19.616 -
  19.617 -
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/tools/ioemu/block-qcow2.c	Wed May 09 14:17:15 2007 +0100
    20.3 @@ -0,0 +1,2246 @@
    20.4 +/*
    20.5 + * Block driver for the QCOW version 2 format
    20.6 + * 
    20.7 + * Copyright (c) 2004-2006 Fabrice Bellard
    20.8 + * 
    20.9 + * Permission is hereby granted, free of charge, to any person obtaining a copy
   20.10 + * of this software and associated documentation files (the "Software"), to deal
   20.11 + * in the Software without restriction, including without limitation the rights
   20.12 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   20.13 + * copies of the Software, and to permit persons to whom the Software is
   20.14 + * furnished to do so, subject to the following conditions:
   20.15 + *
   20.16 + * The above copyright notice and this permission notice shall be included in
   20.17 + * all copies or substantial portions of the Software.
   20.18 + *
   20.19 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   20.20 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   20.21 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   20.22 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   20.23 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   20.24 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   20.25 + * THE SOFTWARE.
   20.26 + */
   20.27 +#include "vl.h"
   20.28 +#include "block_int.h"
   20.29 +#include <zlib.h>
   20.30 +#include "aes.h"
   20.31 +#include <assert.h>
   20.32 +
   20.33 +/*
   20.34 +  Differences with QCOW:
   20.35 +
   20.36 +  - Support for multiple incremental snapshots.
   20.37 +  - Memory management by reference counts.
   20.38 +  - Clusters which have a reference count of one have the bit
   20.39 +    QCOW_OFLAG_COPIED to optimize write performance.
   20.40 +  - Size of compressed clusters is stored in sectors to reduce bit usage 
   20.41 +    in the cluster offsets.
   20.42 +  - Support for storing additional data (such as the VM state) in the
   20.43 +    snapshots.  
   20.44 +  - If a backing store is used, the cluster size is not constrained
   20.45 +    (could be backported to QCOW).
   20.46 +  - L2 tables have always a size of one cluster.
   20.47 +*/
   20.48 +
   20.49 +//#define DEBUG_ALLOC
   20.50 +//#define DEBUG_ALLOC2
   20.51 + 
   20.52 +#define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb)
   20.53 +#define QCOW_VERSION 2
   20.54 +
   20.55 +#define QCOW_CRYPT_NONE 0
   20.56 +#define QCOW_CRYPT_AES  1
   20.57 +
   20.58 +/* indicate that the refcount of the referenced cluster is exactly one. */
   20.59 +#define QCOW_OFLAG_COPIED     (1LL << 63)
   20.60 +/* indicate that the cluster is compressed (they never have the copied flag) */
   20.61 +#define QCOW_OFLAG_COMPRESSED (1LL << 62)
   20.62 +
   20.63 +#define REFCOUNT_SHIFT 1 /* refcount size is 2 bytes */
   20.64 +
   20.65 +#ifndef offsetof
   20.66 +#define offsetof(type, field) ((size_t) &((type *)0)->field)
   20.67 +#endif
   20.68 +
   20.69 +typedef struct QCowHeader {
   20.70 +    uint32_t magic;
   20.71 +    uint32_t version;
   20.72 +    uint64_t backing_file_offset;
   20.73 +    uint32_t backing_file_size;
   20.74 +    uint32_t cluster_bits;
   20.75 +    uint64_t size; /* in bytes */
   20.76 +    uint32_t crypt_method;
   20.77 +    uint32_t l1_size; /* XXX: save number of clusters instead ? */
   20.78 +    uint64_t l1_table_offset;
   20.79 +    uint64_t refcount_table_offset;
   20.80 +    uint32_t refcount_table_clusters;
   20.81 +    uint32_t nb_snapshots;
   20.82 +    uint64_t snapshots_offset;
   20.83 +} QCowHeader;
   20.84 +
   20.85 +typedef struct __attribute__((packed)) QCowSnapshotHeader {
   20.86 +    /* header is 8 byte aligned */
   20.87 +    uint64_t l1_table_offset;
   20.88 +
   20.89 +    uint32_t l1_size;
   20.90 +    uint16_t id_str_size;
   20.91 +    uint16_t name_size;
   20.92 +
   20.93 +    uint32_t date_sec;
   20.94 +    uint32_t date_nsec;
   20.95 +
   20.96 +    uint64_t vm_clock_nsec;
   20.97 +
   20.98 +    uint32_t vm_state_size;
   20.99 +    uint32_t extra_data_size; /* for extension */
  20.100 +    /* extra data follows */
  20.101 +    /* id_str follows */
  20.102 +    /* name follows  */
  20.103 +} QCowSnapshotHeader;
  20.104 +
  20.105 +#define L2_CACHE_SIZE 16
  20.106 +
  20.107 +typedef struct QCowSnapshot {
  20.108 +    uint64_t l1_table_offset;
  20.109 +    uint32_t l1_size;
  20.110 +    char *id_str;
  20.111 +    char *name;
  20.112 +    uint32_t vm_state_size;
  20.113 +    uint32_t date_sec;
  20.114 +    uint32_t date_nsec;
  20.115 +    uint64_t vm_clock_nsec;
  20.116 +} QCowSnapshot;
  20.117 +
  20.118 +typedef struct BDRVQcowState {
  20.119 +    BlockDriverState *hd;
  20.120 +    int cluster_bits;
  20.121 +    int cluster_size;
  20.122 +    int cluster_sectors;
  20.123 +    int l2_bits;
  20.124 +    int l2_size;
  20.125 +    int l1_size;
  20.126 +    int l1_vm_state_index;
  20.127 +    int csize_shift;
  20.128 +    int csize_mask;
  20.129 +    uint64_t cluster_offset_mask;
  20.130 +    uint64_t l1_table_offset;
  20.131 +    uint64_t *l1_table;
  20.132 +    uint64_t *l2_cache;
  20.133 +    uint64_t l2_cache_offsets[L2_CACHE_SIZE];
  20.134 +    uint32_t l2_cache_counts[L2_CACHE_SIZE];
  20.135 +    uint8_t *cluster_cache;
  20.136 +    uint8_t *cluster_data;
  20.137 +    uint64_t cluster_cache_offset;
  20.138 +
  20.139 +    uint64_t *refcount_table;
  20.140 +    uint64_t refcount_table_offset;
  20.141 +    uint32_t refcount_table_size;
  20.142 +    uint64_t refcount_block_cache_offset;
  20.143 +    uint16_t *refcount_block_cache;
  20.144 +    int64_t free_cluster_index;
  20.145 +    int64_t free_byte_offset;
  20.146 +
  20.147 +    uint32_t crypt_method; /* current crypt method, 0 if no key yet */
  20.148 +    uint32_t crypt_method_header;
  20.149 +    AES_KEY aes_encrypt_key;
  20.150 +    AES_KEY aes_decrypt_key;
  20.151 +    uint64_t snapshots_offset;
  20.152 +    int snapshots_size;
  20.153 +    int nb_snapshots;
  20.154 +    QCowSnapshot *snapshots;
  20.155 +} BDRVQcowState;
  20.156 +
  20.157 +static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset);
  20.158 +static int qcow_read(BlockDriverState *bs, int64_t sector_num, 
  20.159 +                     uint8_t *buf, int nb_sectors);
  20.160 +static int qcow_read_snapshots(BlockDriverState *bs);
  20.161 +static void qcow_free_snapshots(BlockDriverState *bs);
  20.162 +static int refcount_init(BlockDriverState *bs);
  20.163 +static void refcount_close(BlockDriverState *bs);
  20.164 +static int get_refcount(BlockDriverState *bs, int64_t cluster_index);
  20.165 +static int update_cluster_refcount(BlockDriverState *bs, 
  20.166 +                                   int64_t cluster_index,
  20.167 +                                   int addend);
  20.168 +static void update_refcount(BlockDriverState *bs, 
  20.169 +                            int64_t offset, int64_t length, 
  20.170 +                            int addend);
  20.171 +static int64_t alloc_clusters(BlockDriverState *bs, int64_t size);
  20.172 +static int64_t alloc_bytes(BlockDriverState *bs, int size);
  20.173 +static void free_clusters(BlockDriverState *bs, 
  20.174 +                          int64_t offset, int64_t size);
  20.175 +#ifdef DEBUG_ALLOC
  20.176 +static void check_refcounts(BlockDriverState *bs);
  20.177 +#endif
  20.178 +
  20.179 +static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
  20.180 +{
  20.181 +    const QCowHeader *cow_header = (const void *)buf;
  20.182 +    
  20.183 +    if (buf_size >= sizeof(QCowHeader) &&
  20.184 +        be32_to_cpu(cow_header->magic) == QCOW_MAGIC &&
  20.185 +        be32_to_cpu(cow_header->version) == QCOW_VERSION) 
  20.186 +        return 100;
  20.187 +    else
  20.188 +        return 0;
  20.189 +}
  20.190 +
  20.191 +static int qcow_open(BlockDriverState *bs, const char *filename, int flags)
  20.192 +{
  20.193 +    BDRVQcowState *s = bs->opaque;
  20.194 +    int len, i, shift, ret;
  20.195 +    QCowHeader header;
  20.196 +
  20.197 +    ret = bdrv_file_open(&s->hd, filename, flags);
  20.198 +    if (ret < 0)
  20.199 +        return ret;
  20.200 +    if (bdrv_pread(s->hd, 0, &header, sizeof(header)) != sizeof(header))
  20.201 +        goto fail;
  20.202 +    be32_to_cpus(&header.magic);
  20.203 +    be32_to_cpus(&header.version);
  20.204 +    be64_to_cpus(&header.backing_file_offset);
  20.205 +    be32_to_cpus(&header.backing_file_size);
  20.206 +    be64_to_cpus(&header.size);
  20.207 +    be32_to_cpus(&header.cluster_bits);
  20.208 +    be32_to_cpus(&header.crypt_method);
  20.209 +    be64_to_cpus(&header.l1_table_offset);
  20.210 +    be32_to_cpus(&header.l1_size);
  20.211 +    be64_to_cpus(&header.refcount_table_offset);
  20.212 +    be32_to_cpus(&header.refcount_table_clusters);
  20.213 +    be64_to_cpus(&header.snapshots_offset);
  20.214 +    be32_to_cpus(&header.nb_snapshots);
  20.215 +    
  20.216 +    if (header.magic != QCOW_MAGIC || header.version != QCOW_VERSION)
  20.217 +        goto fail;
  20.218 +    if (header.size <= 1 || 
  20.219 +        header.cluster_bits < 9 || 
  20.220 +        header.cluster_bits > 16)
  20.221 +        goto fail;
  20.222 +    if (header.crypt_method > QCOW_CRYPT_AES)
  20.223 +        goto fail;
  20.224 +    s->crypt_method_header = header.crypt_method;
  20.225 +    if (s->crypt_method_header)
  20.226 +        bs->encrypted = 1;
  20.227 +    s->cluster_bits = header.cluster_bits;
  20.228 +    s->cluster_size = 1 << s->cluster_bits;
  20.229 +    s->cluster_sectors = 1 << (s->cluster_bits - 9);
  20.230 +    s->l2_bits = s->cluster_bits - 3; /* L2 is always one cluster */
  20.231 +    s->l2_size = 1 << s->l2_bits;
  20.232 +    bs->total_sectors = header.size / 512;
  20.233 +    s->csize_shift = (62 - (s->cluster_bits - 8));
  20.234 +    s->csize_mask = (1 << (s->cluster_bits - 8)) - 1;
  20.235 +    s->cluster_offset_mask = (1LL << s->csize_shift) - 1;
  20.236 +    s->refcount_table_offset = header.refcount_table_offset;
  20.237 +    s->refcount_table_size = 
  20.238 +        header.refcount_table_clusters << (s->cluster_bits - 3);
  20.239 +
  20.240 +    s->snapshots_offset = header.snapshots_offset;
  20.241 +    s->nb_snapshots = header.nb_snapshots;
  20.242 +
  20.243 +    /* read the level 1 table */
  20.244 +    s->l1_size = header.l1_size;
  20.245 +    shift = s->cluster_bits + s->l2_bits;
  20.246 +    s->l1_vm_state_index = (header.size + (1LL << shift) - 1) >> shift;
  20.247 +    /* the L1 table must contain at least enough entries to put
  20.248 +       header.size bytes */
  20.249 +    if (s->l1_size < s->l1_vm_state_index)
  20.250 +        goto fail;
  20.251 +    s->l1_table_offset = header.l1_table_offset;
  20.252 +    s->l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
  20.253 +    if (!s->l1_table)
  20.254 +        goto fail;
  20.255 +    if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)) != 
  20.256 +        s->l1_size * sizeof(uint64_t))
  20.257 +        goto fail;
  20.258 +    for(i = 0;i < s->l1_size; i++) {
  20.259 +        be64_to_cpus(&s->l1_table[i]);
  20.260 +    }
  20.261 +    /* alloc L2 cache */
  20.262 +    s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
  20.263 +    if (!s->l2_cache)
  20.264 +        goto fail;
  20.265 +    s->cluster_cache = qemu_malloc(s->cluster_size);
  20.266 +    if (!s->cluster_cache)
  20.267 +        goto fail;
  20.268 +    /* one more sector for decompressed data alignment */
  20.269 +    s->cluster_data = qemu_malloc(s->cluster_size + 512);
  20.270 +    if (!s->cluster_data)
  20.271 +        goto fail;
  20.272 +    s->cluster_cache_offset = -1;
  20.273 +    
  20.274 +    if (refcount_init(bs) < 0)
  20.275 +        goto fail;
  20.276 +
  20.277 +    /* read the backing file name */
  20.278 +    if (header.backing_file_offset != 0) {
  20.279 +        len = header.backing_file_size;
  20.280 +        if (len > 1023)
  20.281 +            len = 1023;
  20.282 +        if (bdrv_pread(s->hd, header.backing_file_offset, bs->backing_file, len) != len)
  20.283 +            goto fail;
  20.284 +        bs->backing_file[len] = '\0';
  20.285 +    }
  20.286 +    if (qcow_read_snapshots(bs) < 0)
  20.287 +        goto fail;
  20.288 +
  20.289 +#ifdef DEBUG_ALLOC
  20.290 +    check_refcounts(bs);
  20.291 +#endif
  20.292 +    return 0;
  20.293 +
  20.294 + fail:
  20.295 +    qcow_free_snapshots(bs);
  20.296 +    refcount_close(bs);
  20.297 +    qemu_free(s->l1_table);
  20.298 +    qemu_free(s->l2_cache);
  20.299 +    qemu_free(s->cluster_cache);
  20.300 +    qemu_free(s->cluster_data);
  20.301 +    bdrv_delete(s->hd);
  20.302 +    return -1;
  20.303 +}
  20.304 +
  20.305 +static int qcow_set_key(BlockDriverState *bs, const char *key)
  20.306 +{
  20.307 +    BDRVQcowState *s = bs->opaque;
  20.308 +    uint8_t keybuf[16];
  20.309 +    int len, i;
  20.310 +    
  20.311 +    memset(keybuf, 0, 16);
  20.312 +    len = strlen(key);
  20.313 +    if (len > 16)
  20.314 +        len = 16;
  20.315 +    /* XXX: we could compress the chars to 7 bits to increase
  20.316 +       entropy */
  20.317 +    for(i = 0;i < len;i++) {
  20.318 +        keybuf[i] = key[i];
  20.319 +    }
  20.320 +    s->crypt_method = s->crypt_method_header;
  20.321 +
  20.322 +    if (AES_set_encrypt_key(keybuf, 128, &s->aes_encrypt_key) != 0)
  20.323 +        return -1;
  20.324 +    if (AES_set_decrypt_key(keybuf, 128, &s->aes_decrypt_key) != 0)
  20.325 +        return -1;
  20.326 +#if 0
  20.327 +    /* test */
  20.328 +    {
  20.329 +        uint8_t in[16];
  20.330 +        uint8_t out[16];
  20.331 +        uint8_t tmp[16];
  20.332 +        for(i=0;i<16;i++)
  20.333 +            in[i] = i;
  20.334 +        AES_encrypt(in, tmp, &s->aes_encrypt_key);
  20.335 +        AES_decrypt(tmp, out, &s->aes_decrypt_key);
  20.336 +        for(i = 0; i < 16; i++)
  20.337 +            printf(" %02x", tmp[i]);
  20.338 +        printf("\n");
  20.339 +        for(i = 0; i < 16; i++)
  20.340 +            printf(" %02x", out[i]);
  20.341 +        printf("\n");
  20.342 +    }
  20.343 +#endif
  20.344 +    return 0;
  20.345 +}
  20.346 +
  20.347 +/* The crypt function is compatible with the linux cryptoloop
  20.348 +   algorithm for < 4 GB images. NOTE: out_buf == in_buf is
  20.349 +   supported */
  20.350 +static void encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
  20.351 +                            uint8_t *out_buf, const uint8_t *in_buf,
  20.352 +                            int nb_sectors, int enc,
  20.353 +                            const AES_KEY *key)
  20.354 +{
  20.355 +    union {
  20.356 +        uint64_t ll[2];
  20.357 +        uint8_t b[16];
  20.358 +    } ivec;
  20.359 +    int i;
  20.360 +
  20.361 +    for(i = 0; i < nb_sectors; i++) {
  20.362 +        ivec.ll[0] = cpu_to_le64(sector_num);
  20.363 +        ivec.ll[1] = 0;
  20.364 +        AES_cbc_encrypt(in_buf, out_buf, 512, key, 
  20.365 +                        ivec.b, enc);
  20.366 +        sector_num++;
  20.367 +        in_buf += 512;
  20.368 +        out_buf += 512;
  20.369 +    }
  20.370 +}
  20.371 +
  20.372 +static int copy_sectors(BlockDriverState *bs, uint64_t start_sect,
  20.373 +                        uint64_t cluster_offset, int n_start, int n_end)
  20.374 +{
  20.375 +    BDRVQcowState *s = bs->opaque;
  20.376 +    int n, ret;
  20.377 +
  20.378 +    n = n_end - n_start;
  20.379 +    if (n <= 0)
  20.380 +        return 0;
  20.381 +    ret = qcow_read(bs, start_sect + n_start, s->cluster_data, n);
  20.382 +    if (ret < 0)
  20.383 +        return ret;
  20.384 +    if (s->crypt_method) {
  20.385 +        encrypt_sectors(s, start_sect + n_start, 
  20.386 +                        s->cluster_data, 
  20.387 +                        s->cluster_data, n, 1,
  20.388 +                        &s->aes_encrypt_key);
  20.389 +    }
  20.390 +    ret = bdrv_write(s->hd, (cluster_offset >> 9) + n_start, 
  20.391 +                     s->cluster_data, n);
  20.392 +    if (ret < 0)
  20.393 +        return ret;
  20.394 +    return 0;
  20.395 +}
  20.396 +
  20.397 +static void l2_cache_reset(BlockDriverState *bs)
  20.398 +{
  20.399 +    BDRVQcowState *s = bs->opaque;
  20.400 +
  20.401 +    memset(s->l2_cache, 0, s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
  20.402 +    memset(s->l2_cache_offsets, 0, L2_CACHE_SIZE * sizeof(uint64_t));
  20.403 +    memset(s->l2_cache_counts, 0, L2_CACHE_SIZE * sizeof(uint32_t));
  20.404 +}
  20.405 +
  20.406 +static inline int l2_cache_new_entry(BlockDriverState *bs)
  20.407 +{
  20.408 +    BDRVQcowState *s = bs->opaque;
  20.409 +    uint32_t min_count;
  20.410 +    int min_index, i;
  20.411 +
  20.412 +    /* find a new entry in the least used one */
  20.413 +    min_index = 0;
  20.414 +    min_count = 0xffffffff;
  20.415 +    for(i = 0; i < L2_CACHE_SIZE; i++) {
  20.416 +        if (s->l2_cache_counts[i] < min_count) {
  20.417 +            min_count = s->l2_cache_counts[i];
  20.418 +            min_index = i;
  20.419 +        }
  20.420 +    }
  20.421 +    return min_index;
  20.422 +}
  20.423 +
  20.424 +static int64_t align_offset(int64_t offset, int n)
  20.425 +{
  20.426 +    offset = (offset + n - 1) & ~(n - 1);
  20.427 +    return offset;
  20.428 +}
  20.429 +
  20.430 +static int grow_l1_table(BlockDriverState *bs, int min_size)
  20.431 +{
  20.432 +    BDRVQcowState *s = bs->opaque;
  20.433 +    int new_l1_size, new_l1_size2, ret, i;
  20.434 +    uint64_t *new_l1_table;
  20.435 +    uint64_t new_l1_table_offset;
  20.436 +    uint64_t data64;
  20.437 +    uint32_t data32;
  20.438 +
  20.439 +    new_l1_size = s->l1_size;
  20.440 +    if (min_size <= new_l1_size)
  20.441 +        return 0;
  20.442 +    while (min_size > new_l1_size) {
  20.443 +        new_l1_size = (new_l1_size * 3 + 1) / 2;
  20.444 +    }
  20.445 +#ifdef DEBUG_ALLOC2
  20.446 +    printf("grow l1_table from %d to %d\n", s->l1_size, new_l1_size);
  20.447 +#endif
  20.448 +
  20.449 +    new_l1_size2 = sizeof(uint64_t) * new_l1_size;
  20.450 +    new_l1_table = qemu_mallocz(new_l1_size2);
  20.451 +    if (!new_l1_table)
  20.452 +        return -ENOMEM;
  20.453 +    memcpy(new_l1_table, s->l1_table, s->l1_size * sizeof(uint64_t));
  20.454 +
  20.455 +    /* write new table (align to cluster) */
  20.456 +    new_l1_table_offset = alloc_clusters(bs, new_l1_size2);
  20.457 +    
  20.458 +    for(i = 0; i < s->l1_size; i++)
  20.459 +        new_l1_table[i] = cpu_to_be64(new_l1_table[i]);
  20.460 +    ret = bdrv_pwrite(s->hd, new_l1_table_offset, new_l1_table, new_l1_size2);
  20.461 +    if (ret != new_l1_size2)
  20.462 +        goto fail;
  20.463 +    for(i = 0; i < s->l1_size; i++)
  20.464 +        new_l1_table[i] = be64_to_cpu(new_l1_table[i]);
  20.465 +    
  20.466 +    /* set new table */
  20.467 +    data64 = cpu_to_be64(new_l1_table_offset);
  20.468 +    if (bdrv_pwrite(s->hd, offsetof(QCowHeader, l1_table_offset),
  20.469 +                    &data64, sizeof(data64)) != sizeof(data64))
  20.470 +        goto fail;
  20.471 +    data32 = cpu_to_be32(new_l1_size);
  20.472 +    if (bdrv_pwrite(s->hd, offsetof(QCowHeader, l1_size),
  20.473 +                    &data32, sizeof(data32)) != sizeof(data32))
  20.474 +        goto fail;
  20.475 +    qemu_free(s->l1_table);
  20.476 +    free_clusters(bs, s->l1_table_offset, s->l1_size * sizeof(uint64_t));
  20.477 +    s->l1_table_offset = new_l1_table_offset;
  20.478 +    s->l1_table = new_l1_table;
  20.479 +    s->l1_size = new_l1_size;
  20.480 +    return 0;
  20.481 + fail:
  20.482 +    qemu_free(s->l1_table);
  20.483 +    return -EIO;
  20.484 +}
  20.485 +
  20.486 +/* 'allocate' is:
  20.487 + *
  20.488 + * 0 not to allocate.
  20.489 + *
  20.490 + * 1 to allocate a normal cluster (for sector indexes 'n_start' to
  20.491 + * 'n_end')
  20.492 + *
  20.493 + * 2 to allocate a compressed cluster of size
  20.494 + * 'compressed_size'. 'compressed_size' must be > 0 and <
  20.495 + * cluster_size 
  20.496 + *
  20.497 + * return 0 if not allocated.
  20.498 + */
  20.499 +static uint64_t get_cluster_offset(BlockDriverState *bs,
  20.500 +                                   uint64_t offset, int allocate,
  20.501 +                                   int compressed_size,
  20.502 +                                   int n_start, int n_end)
  20.503 +{
  20.504 +    BDRVQcowState *s = bs->opaque;
  20.505 +    int min_index, i, j, l1_index, l2_index, ret;
  20.506 +    uint64_t l2_offset, *l2_table, cluster_offset, tmp, old_l2_offset;
  20.507 +    
  20.508 +    l1_index = offset >> (s->l2_bits + s->cluster_bits);
  20.509 +    if (l1_index >= s->l1_size) {
  20.510 +        /* outside l1 table is allowed: we grow the table if needed */
  20.511 +        if (!allocate)
  20.512 +            return 0;
  20.513 +        if (grow_l1_table(bs, l1_index + 1) < 0)
  20.514 +            return 0;
  20.515 +    }
  20.516 +    l2_offset = s->l1_table[l1_index];
  20.517 +    if (!l2_offset) {
  20.518 +        if (!allocate)
  20.519 +            return 0;
  20.520 +    l2_allocate:
  20.521 +        old_l2_offset = l2_offset;
  20.522 +        /* allocate a new l2 entry */
  20.523 +        l2_offset = alloc_clusters(bs, s->l2_size * sizeof(uint64_t));
  20.524 +        /* update the L1 entry */
  20.525 +        s->l1_table[l1_index] = l2_offset | QCOW_OFLAG_COPIED;
  20.526 +        tmp = cpu_to_be64(l2_offset | QCOW_OFLAG_COPIED);
  20.527 +        if (bdrv_pwrite(s->hd, s->l1_table_offset + l1_index * sizeof(tmp), 
  20.528 +                        &tmp, sizeof(tmp)) != sizeof(tmp))
  20.529 +            return 0;
  20.530 +        min_index = l2_cache_new_entry(bs);
  20.531 +        l2_table = s->l2_cache + (min_index << s->l2_bits);
  20.532 +
  20.533 +        if (old_l2_offset == 0) {
  20.534 +            memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
  20.535 +        } else {
  20.536 +            if (bdrv_pread(s->hd, old_l2_offset, 
  20.537 +                           l2_table, s->l2_size * sizeof(uint64_t)) !=
  20.538 +                s->l2_size * sizeof(uint64_t))
  20.539 +                return 0;
  20.540 +        }
  20.541 +        if (bdrv_pwrite(s->hd, l2_offset, 
  20.542 +                        l2_table, s->l2_size * sizeof(uint64_t)) !=
  20.543 +            s->l2_size * sizeof(uint64_t))
  20.544 +            return 0;
  20.545 +    } else {
  20.546 +        if (!(l2_offset & QCOW_OFLAG_COPIED)) {
  20.547 +            if (allocate) {
  20.548 +                free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t));
  20.549 +                goto l2_allocate;
  20.550 +            }
  20.551 +        } else {
  20.552 +            l2_offset &= ~QCOW_OFLAG_COPIED;
  20.553 +        }
  20.554 +        for(i = 0; i < L2_CACHE_SIZE; i++) {
  20.555 +            if (l2_offset == s->l2_cache_offsets[i]) {
  20.556 +                /* increment the hit count */
  20.557 +                if (++s->l2_cache_counts[i] == 0xffffffff) {
  20.558 +                    for(j = 0; j < L2_CACHE_SIZE; j++) {
  20.559 +                        s->l2_cache_counts[j] >>= 1;
  20.560 +                    }
  20.561 +                }
  20.562 +                l2_table = s->l2_cache + (i << s->l2_bits);
  20.563 +                goto found;
  20.564 +            }
  20.565 +        }
  20.566 +        /* not found: load a new entry in the least used one */
  20.567 +        min_index = l2_cache_new_entry(bs);
  20.568 +        l2_table = s->l2_cache + (min_index << s->l2_bits);
  20.569 +        if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) != 
  20.570 +            s->l2_size * sizeof(uint64_t))
  20.571 +            return 0;
  20.572 +    }
  20.573 +    s->l2_cache_offsets[min_index] = l2_offset;
  20.574 +    s->l2_cache_counts[min_index] = 1;
  20.575 + found:
  20.576 +    l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);
  20.577 +    cluster_offset = be64_to_cpu(l2_table[l2_index]);
  20.578 +    if (!cluster_offset) {
  20.579 +        if (!allocate)
  20.580 +            return cluster_offset;
  20.581 +    } else if (!(cluster_offset & QCOW_OFLAG_COPIED)) {
  20.582 +        if (!allocate)
  20.583 +            return cluster_offset;
  20.584 +        /* free the cluster */
  20.585 +        if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
  20.586 +            int nb_csectors;
  20.587 +            nb_csectors = ((cluster_offset >> s->csize_shift) & 
  20.588 +                           s->csize_mask) + 1;
  20.589 +            free_clusters(bs, (cluster_offset & s->cluster_offset_mask) & ~511,
  20.590 +                          nb_csectors * 512);
  20.591 +        } else {
  20.592 +            free_clusters(bs, cluster_offset, s->cluster_size);
  20.593 +        }
  20.594 +    } else {
  20.595 +        cluster_offset &= ~QCOW_OFLAG_COPIED;
  20.596 +        return cluster_offset;
  20.597 +    }
  20.598 +    if (allocate == 1) {
  20.599 +        /* allocate a new cluster */
  20.600 +        cluster_offset = alloc_clusters(bs, s->cluster_size);
  20.601 +
  20.602 +        /* we must initialize the cluster content which won't be
  20.603 +           written */
  20.604 +        if ((n_end - n_start) < s->cluster_sectors) {
  20.605 +            uint64_t start_sect;
  20.606 +            
  20.607 +            start_sect = (offset & ~(s->cluster_size - 1)) >> 9;
  20.608 +            ret = copy_sectors(bs, start_sect,
  20.609 +                               cluster_offset, 0, n_start);
  20.610 +            if (ret < 0)
  20.611 +                return 0;
  20.612 +            ret = copy_sectors(bs, start_sect,
  20.613 +                               cluster_offset, n_end, s->cluster_sectors);
  20.614 +            if (ret < 0)
  20.615 +                return 0;
  20.616 +        }
  20.617 +        tmp = cpu_to_be64(cluster_offset | QCOW_OFLAG_COPIED);
  20.618 +    } else {
  20.619 +        int nb_csectors;
  20.620 +        cluster_offset = alloc_bytes(bs, compressed_size);
  20.621 +        nb_csectors = ((cluster_offset + compressed_size - 1) >> 9) - 
  20.622 +            (cluster_offset >> 9);
  20.623 +        cluster_offset |= QCOW_OFLAG_COMPRESSED | 
  20.624 +            ((uint64_t)nb_csectors << s->csize_shift);
  20.625 +        /* compressed clusters never have the copied flag */
  20.626 +        tmp = cpu_to_be64(cluster_offset);
  20.627 +    }
  20.628 +    /* update L2 table */
  20.629 +    l2_table[l2_index] = tmp;
  20.630 +    if (bdrv_pwrite(s->hd, 
  20.631 +                    l2_offset + l2_index * sizeof(tmp), &tmp, sizeof(tmp)) != sizeof(tmp))
  20.632 +        return 0;
  20.633 +    return cluster_offset;
  20.634 +}
  20.635 +
  20.636 +static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num, 
  20.637 +                             int nb_sectors, int *pnum)
  20.638 +{
  20.639 +    BDRVQcowState *s = bs->opaque;
  20.640 +    int index_in_cluster, n;
  20.641 +    uint64_t cluster_offset;
  20.642 +
  20.643 +    cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0);
  20.644 +    index_in_cluster = sector_num & (s->cluster_sectors - 1);
  20.645 +    n = s->cluster_sectors - index_in_cluster;
  20.646 +    if (n > nb_sectors)
  20.647 +        n = nb_sectors;
  20.648 +    *pnum = n;
  20.649 +    return (cluster_offset != 0);
  20.650 +}
  20.651 +
  20.652 +static int decompress_buffer(uint8_t *out_buf, int out_buf_size,
  20.653 +                             const uint8_t *buf, int buf_size)
  20.654 +{
  20.655 +    z_stream strm1, *strm = &strm1;
  20.656 +    int ret, out_len;
  20.657 +
  20.658 +    memset(strm, 0, sizeof(*strm));
  20.659 +
  20.660 +    strm->next_in = (uint8_t *)buf;
  20.661 +    strm->avail_in = buf_size;
  20.662 +    strm->next_out = out_buf;
  20.663 +    strm->avail_out = out_buf_size;
  20.664 +
  20.665 +    ret = inflateInit2(strm, -12);
  20.666 +    if (ret != Z_OK)
  20.667 +        return -1;
  20.668 +    ret = inflate(strm, Z_FINISH);
  20.669 +    out_len = strm->next_out - out_buf;
  20.670 +    if ((ret != Z_STREAM_END && ret != Z_BUF_ERROR) ||
  20.671 +        out_len != out_buf_size) {
  20.672 +        inflateEnd(strm);
  20.673 +        return -1;
  20.674 +    }
  20.675 +    inflateEnd(strm);
  20.676 +    return 0;
  20.677 +}
  20.678 +                              
  20.679 +static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset)
  20.680 +{
  20.681 +    int ret, csize, nb_csectors, sector_offset;
  20.682 +    uint64_t coffset;
  20.683 +
  20.684 +    coffset = cluster_offset & s->cluster_offset_mask;
  20.685 +    if (s->cluster_cache_offset != coffset) {
  20.686 +        nb_csectors = ((cluster_offset >> s->csize_shift) & s->csize_mask) + 1;
  20.687 +        sector_offset = coffset & 511;
  20.688 +        csize = nb_csectors * 512 - sector_offset;
  20.689 +        ret = bdrv_read(s->hd, coffset >> 9, s->cluster_data, nb_csectors);
  20.690 +        if (ret < 0) {
  20.691 +            return -1;
  20.692 +        }
  20.693 +        if (decompress_buffer(s->cluster_cache, s->cluster_size,
  20.694 +                              s->cluster_data + sector_offset, csize) < 0) {
  20.695 +            return -1;
  20.696 +        }
  20.697 +        s->cluster_cache_offset = coffset;
  20.698 +    }
  20.699 +    return 0;
  20.700 +}
  20.701 +
  20.702 +/* handle reading after the end of the backing file */
  20.703 +static int backing_read1(BlockDriverState *bs, 
  20.704 +                         int64_t sector_num, uint8_t *buf, int nb_sectors)
  20.705 +{
  20.706 +    int n1;
  20.707 +    if ((sector_num + nb_sectors) <= bs->total_sectors)
  20.708 +        return nb_sectors;
  20.709 +    if (sector_num >= bs->total_sectors)
  20.710 +        n1 = 0;
  20.711 +    else
  20.712 +        n1 = bs->total_sectors - sector_num;
  20.713 +    memset(buf + n1 * 512, 0, 512 * (nb_sectors - n1));
  20.714 +    return n1;
  20.715 +}
  20.716 +
  20.717 +static int qcow_read(BlockDriverState *bs, int64_t sector_num, 
  20.718 +                     uint8_t *buf, int nb_sectors)
  20.719 +{
  20.720 +    BDRVQcowState *s = bs->opaque;
  20.721 +    int ret, index_in_cluster, n, n1;
  20.722 +    uint64_t cluster_offset;
  20.723 +    
  20.724 +    while (nb_sectors > 0) {
  20.725 +        cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0);
  20.726 +        index_in_cluster = sector_num & (s->cluster_sectors - 1);
  20.727 +        n = s->cluster_sectors - index_in_cluster;
  20.728 +        if (n > nb_sectors)
  20.729 +            n = nb_sectors;
  20.730 +        if (!cluster_offset) {
  20.731 +            if (bs->backing_hd) {
  20.732 +                /* read from the base image */
  20.733 +                n1 = backing_read1(bs->backing_hd, sector_num, buf, n);
  20.734 +                if (n1 > 0) {
  20.735 +                    ret = bdrv_read(bs->backing_hd, sector_num, buf, n1);
  20.736 +                    if (ret < 0)
  20.737 +                        return -1;
  20.738 +                }
  20.739 +            } else {
  20.740 +                memset(buf, 0, 512 * n);
  20.741 +            }
  20.742 +        } else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
  20.743 +            if (decompress_cluster(s, cluster_offset) < 0)
  20.744 +                return -1;
  20.745 +            memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n);
  20.746 +        } else {
  20.747 +            ret = bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512);
  20.748 +            if (ret != n * 512) 
  20.749 +                return -1;
  20.750 +            if (s->crypt_method) {
  20.751 +                encrypt_sectors(s, sector_num, buf, buf, n, 0, 
  20.752 +                                &s->aes_decrypt_key);
  20.753 +            }
  20.754 +        }
  20.755 +        nb_sectors -= n;
  20.756 +        sector_num += n;
  20.757 +        buf += n * 512;
  20.758 +    }
  20.759 +    return 0;
  20.760 +}
  20.761 +
  20.762 +static int qcow_write(BlockDriverState *bs, int64_t sector_num, 
  20.763 +                     const uint8_t *buf, int nb_sectors)
  20.764 +{
  20.765 +    BDRVQcowState *s = bs->opaque;
  20.766 +    int ret, index_in_cluster, n;
  20.767 +    uint64_t cluster_offset;
  20.768 +    
  20.769 +    while (nb_sectors > 0) {
  20.770 +        index_in_cluster = sector_num & (s->cluster_sectors - 1);
  20.771 +        n = s->cluster_sectors - index_in_cluster;
  20.772 +        if (n > nb_sectors)
  20.773 +            n = nb_sectors;
  20.774 +        cluster_offset = get_cluster_offset(bs, sector_num << 9, 1, 0, 
  20.775 +                                            index_in_cluster, 
  20.776 +                                            index_in_cluster + n);
  20.777 +        if (!cluster_offset)
  20.778 +            return -1;
  20.779 +        if (s->crypt_method) {
  20.780 +            encrypt_sectors(s, sector_num, s->cluster_data, buf, n, 1,
  20.781 +                            &s->aes_encrypt_key);
  20.782 +            ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, 
  20.783 +                              s->cluster_data, n * 512);
  20.784 +        } else {
  20.785 +            ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512);
  20.786 +        }
  20.787 +        if (ret != n * 512) 
  20.788 +            return -1;
  20.789 +        nb_sectors -= n;
  20.790 +        sector_num += n;
  20.791 +        buf += n * 512;
  20.792 +    }
  20.793 +    s->cluster_cache_offset = -1; /* disable compressed cache */
  20.794 +    return 0;
  20.795 +}
  20.796 +
  20.797 +typedef struct QCowAIOCB {
  20.798 +    BlockDriverAIOCB common;
  20.799 +    int64_t sector_num;
  20.800 +    uint8_t *buf;
  20.801 +    int nb_sectors;
  20.802 +    int n;
  20.803 +    uint64_t cluster_offset;
  20.804 +    uint8_t *cluster_data; 
  20.805 +    BlockDriverAIOCB *hd_aiocb;
  20.806 +} QCowAIOCB;
  20.807 +
  20.808 +static void qcow_aio_read_cb(void *opaque, int ret)
  20.809 +{
  20.810 +    QCowAIOCB *acb = opaque;
  20.811 +    BlockDriverState *bs = acb->common.bs;
  20.812 +    BDRVQcowState *s = bs->opaque;
  20.813 +    int index_in_cluster, n1;
  20.814 +
  20.815 +    acb->hd_aiocb = NULL;
  20.816 +    if (ret < 0) {
  20.817 +    fail:
  20.818 +        acb->common.cb(acb->common.opaque, ret);
  20.819 +        qemu_aio_release(acb);
  20.820 +        return;
  20.821 +    }
  20.822 +
  20.823 + redo:
  20.824 +    /* post process the read buffer */
  20.825 +    if (!acb->cluster_offset) {
  20.826 +        /* nothing to do */
  20.827 +    } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
  20.828 +        /* nothing to do */
  20.829 +    } else {
  20.830 +        if (s->crypt_method) {
  20.831 +            encrypt_sectors(s, acb->sector_num, acb->buf, acb->buf, 
  20.832 +                            acb->n, 0, 
  20.833 +                            &s->aes_decrypt_key);
  20.834 +        }
  20.835 +    }
  20.836 +
  20.837 +    acb->nb_sectors -= acb->n;
  20.838 +    acb->sector_num += acb->n;
  20.839 +    acb->buf += acb->n * 512;
  20.840 +
  20.841 +    if (acb->nb_sectors == 0) {
  20.842 +        /* request completed */
  20.843 +        acb->common.cb(acb->common.opaque, 0);
  20.844 +        qemu_aio_release(acb);
  20.845 +        return;
  20.846 +    }
  20.847 +    
  20.848 +    /* prepare next AIO request */
  20.849 +    acb->cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, 
  20.850 +                                             0, 0, 0, 0);
  20.851 +    index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
  20.852 +    acb->n = s->cluster_sectors - index_in_cluster;
  20.853 +    if (acb->n > acb->nb_sectors)
  20.854 +        acb->n = acb->nb_sectors;
  20.855 +
  20.856 +    if (!acb->cluster_offset) {
  20.857 +        if (bs->backing_hd) {
  20.858 +            /* read from the base image */
  20.859 +            n1 = backing_read1(bs->backing_hd, acb->sector_num, 
  20.860 +                               acb->buf, acb->n);
  20.861 +            if (n1 > 0) {
  20.862 +                acb->hd_aiocb = bdrv_aio_read(bs->backing_hd, acb->sector_num, 
  20.863 +                                    acb->buf, acb->n, qcow_aio_read_cb, acb);
  20.864 +                if (acb->hd_aiocb == NULL)
  20.865 +                    goto fail;
  20.866 +            } else {
  20.867 +                goto redo;
  20.868 +            }
  20.869 +        } else {
  20.870 +            /* Note: in this case, no need to wait */
  20.871 +            memset(acb->buf, 0, 512 * acb->n);
  20.872 +            goto redo;
  20.873 +        }
  20.874 +    } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
  20.875 +        /* add AIO support for compressed blocks ? */
  20.876 +        if (decompress_cluster(s, acb->cluster_offset) < 0)
  20.877 +            goto fail;
  20.878 +        memcpy(acb->buf, 
  20.879 +               s->cluster_cache + index_in_cluster * 512, 512 * acb->n);
  20.880 +        goto redo;
  20.881 +    } else {
  20.882 +        if ((acb->cluster_offset & 511) != 0) {
  20.883 +            ret = -EIO;
  20.884 +            goto fail;
  20.885 +        }
  20.886 +        acb->hd_aiocb = bdrv_aio_read(s->hd,
  20.887 +                            (acb->cluster_offset >> 9) + index_in_cluster, 
  20.888 +                            acb->buf, acb->n, qcow_aio_read_cb, acb);
  20.889 +        if (acb->hd_aiocb == NULL)
  20.890 +            goto fail;
  20.891 +    }
  20.892 +}
  20.893 +
  20.894 +static QCowAIOCB *qcow_aio_setup(BlockDriverState *bs,
  20.895 +        int64_t sector_num, uint8_t *buf, int nb_sectors,
  20.896 +        BlockDriverCompletionFunc *cb, void *opaque)
  20.897 +{
  20.898 +    QCowAIOCB *acb;
  20.899 +
  20.900 +    acb = qemu_aio_get(bs, cb, opaque);
  20.901 +    if (!acb)
  20.902 +        return NULL;
  20.903 +    acb->hd_aiocb = NULL;
  20.904 +    acb->sector_num = sector_num;
  20.905 +    acb->buf = buf;
  20.906 +    acb->nb_sectors = nb_sectors;
  20.907 +    acb->n = 0;
  20.908 +    acb->cluster_offset = 0;
  20.909 +    return acb;
  20.910 +}
  20.911 +
  20.912 +static BlockDriverAIOCB *qcow_aio_read(BlockDriverState *bs,
  20.913 +        int64_t sector_num, uint8_t *buf, int nb_sectors,
  20.914 +        BlockDriverCompletionFunc *cb, void *opaque)
  20.915 +{
  20.916 +    QCowAIOCB *acb;
  20.917 +
  20.918 +    acb = qcow_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
  20.919 +    if (!acb)
  20.920 +        return NULL;
  20.921 +
  20.922 +    qcow_aio_read_cb(acb, 0);
  20.923 +    return &acb->common;
  20.924 +}
  20.925 +
  20.926 +static void qcow_aio_write_cb(void *opaque, int ret)
  20.927 +{
  20.928 +    QCowAIOCB *acb = opaque;
  20.929 +    BlockDriverState *bs = acb->common.bs;
  20.930 +    BDRVQcowState *s = bs->opaque;
  20.931 +    int index_in_cluster;
  20.932 +    uint64_t cluster_offset;
  20.933 +    const uint8_t *src_buf;
  20.934 +
  20.935 +    acb->hd_aiocb = NULL;
  20.936 +
  20.937 +    if (ret < 0) {
  20.938 +    fail:
  20.939 +        acb->common.cb(acb->common.opaque, ret);
  20.940 +        qemu_aio_release(acb);
  20.941 +        return;
  20.942 +    }
  20.943 +
  20.944 +    acb->nb_sectors -= acb->n;
  20.945 +    acb->sector_num += acb->n;
  20.946 +    acb->buf += acb->n * 512;
  20.947 +
  20.948 +    if (acb->nb_sectors == 0) {
  20.949 +        /* request completed */
  20.950 +        acb->common.cb(acb->common.opaque, 0);
  20.951 +        qemu_aio_release(acb);
  20.952 +        return;
  20.953 +    }
  20.954 +    
  20.955 +    index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
  20.956 +    acb->n = s->cluster_sectors - index_in_cluster;
  20.957 +    if (acb->n > acb->nb_sectors)
  20.958 +        acb->n = acb->nb_sectors;
  20.959 +    cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, 1, 0, 
  20.960 +                                        index_in_cluster, 
  20.961 +                                        index_in_cluster + acb->n);
  20.962 +    if (!cluster_offset || (cluster_offset & 511) != 0) {
  20.963 +        ret = -EIO;
  20.964 +        goto fail;
  20.965 +    }
  20.966 +    if (s->crypt_method) {
  20.967 +        if (!acb->cluster_data) {
  20.968 +            acb->cluster_data = qemu_mallocz(s->cluster_size);
  20.969 +            if (!acb->cluster_data) {
  20.970 +                ret = -ENOMEM;
  20.971 +                goto fail;
  20.972 +            }
  20.973 +        }
  20.974 +        encrypt_sectors(s, acb->sector_num, acb->cluster_data, acb->buf, 
  20.975 +                        acb->n, 1, &s->aes_encrypt_key);
  20.976 +        src_buf = acb->cluster_data;
  20.977 +    } else {
  20.978 +        src_buf = acb->buf;
  20.979 +    }
  20.980 +    acb->hd_aiocb = bdrv_aio_write(s->hd,
  20.981 +                                   (cluster_offset >> 9) + index_in_cluster, 
  20.982 +                                   src_buf, acb->n, 
  20.983 +                                   qcow_aio_write_cb, acb);
  20.984 +    if (acb->hd_aiocb == NULL)
  20.985 +        goto fail;
  20.986 +}
  20.987 +
  20.988 +static BlockDriverAIOCB *qcow_aio_write(BlockDriverState *bs,
  20.989 +        int64_t sector_num, const uint8_t *buf, int nb_sectors,
  20.990 +        BlockDriverCompletionFunc *cb, void *opaque)
  20.991 +{
  20.992 +    BDRVQcowState *s = bs->opaque;
  20.993 +    QCowAIOCB *acb;
  20.994 +    
  20.995 +    s->cluster_cache_offset = -1; /* disable compressed cache */
  20.996 +
  20.997 +    acb = qcow_aio_setup(bs, sector_num, (uint8_t*)buf, nb_sectors, cb, opaque);
  20.998 +    if (!acb)
  20.999 +        return NULL;
 20.1000 +    
 20.1001 +    qcow_aio_write_cb(acb, 0);
 20.1002 +    return &acb->common;
 20.1003 +}
 20.1004 +
 20.1005 +static void qcow_aio_cancel(BlockDriverAIOCB *blockacb)
 20.1006 +{
 20.1007 +    QCowAIOCB *acb = (QCowAIOCB *)blockacb;
 20.1008 +    if (acb->hd_aiocb)
 20.1009 +        bdrv_aio_cancel(acb->hd_aiocb);
 20.1010 +    qemu_aio_release(acb);
 20.1011 +}
 20.1012 +
 20.1013 +static void qcow_close(BlockDriverState *bs)
 20.1014 +{
 20.1015 +    BDRVQcowState *s = bs->opaque;
 20.1016 +    qemu_free(s->l1_table);
 20.1017 +    qemu_free(s->l2_cache);
 20.1018 +    qemu_free(s->cluster_cache);
 20.1019 +    qemu_free(s->cluster_data);
 20.1020 +    refcount_close(bs);
 20.1021 +    bdrv_delete(s->hd);
 20.1022 +}
 20.1023 +
 20.1024 +/* XXX: use std qcow open function ? */
 20.1025 +typedef struct QCowCreateState {
 20.1026 +    int cluster_size;
 20.1027 +    int cluster_bits;
 20.1028 +    uint16_t *refcount_block;
 20.1029 +    uint64_t *refcount_table;
 20.1030 +    int64_t l1_table_offset;
 20.1031 +    int64_t refcount_table_offset;
 20.1032 +    int64_t refcount_block_offset;
 20.1033 +} QCowCreateState;
 20.1034 +
 20.1035 +static void create_refcount_update(QCowCreateState *s,
 20.1036 +                                   int64_t offset, int64_t size)
 20.1037 +{
 20.1038 +    int refcount;
 20.1039 +    int64_t start, last, cluster_offset;
 20.1040 +    uint16_t *p;
 20.1041 +
 20.1042 +    start = offset & ~(s->cluster_size - 1);
 20.1043 +    last = (offset + size - 1)  & ~(s->cluster_size - 1);
 20.1044 +    for(cluster_offset = start; cluster_offset <= last; 
 20.1045 +        cluster_offset += s->cluster_size) {
 20.1046 +        p = &s->refcount_block[cluster_offset >> s->cluster_bits];
 20.1047 +        refcount = be16_to_cpu(*p);
 20.1048 +        refcount++;
 20.1049 +        *p = cpu_to_be16(refcount);
 20.1050 +    }
 20.1051 +}
 20.1052 +
 20.1053 +static int qcow_create(const char *filename, int64_t total_size,
 20.1054 +                      const char *backing_file, int flags)
 20.1055 +{
 20.1056 +    int fd, header_size, backing_filename_len, l1_size, i, shift, l2_bits;
 20.1057 +    QCowHeader header;
 20.1058 +    uint64_t tmp, offset;
 20.1059 +    QCowCreateState s1, *s = &s1;
 20.1060 +    
 20.1061 +    memset(s, 0, sizeof(*s));
 20.1062 +
 20.1063 +    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
 20.1064 +    if (fd < 0)
 20.1065 +        return -1;
 20.1066 +    memset(&header, 0, sizeof(header));
 20.1067 +    header.magic = cpu_to_be32(QCOW_MAGIC);
 20.1068 +    header.version = cpu_to_be32(QCOW_VERSION);
 20.1069 +    header.size = cpu_to_be64(total_size * 512);
 20.1070 +    header_size = sizeof(header);
 20.1071 +    backing_filename_len = 0;
 20.1072 +    if (backing_file) {
 20.1073 +        header.backing_file_offset = cpu_to_be64(header_size);
 20.1074 +        backing_filename_len = strlen(backing_file);
 20.1075 +        header.backing_file_size = cpu_to_be32(backing_filename_len);
 20.1076 +        header_size += backing_filename_len;
 20.1077 +    }
 20.1078 +    s->cluster_bits = 12;  /* 4 KB clusters */
 20.1079 +    s->cluster_size = 1 << s->cluster_bits;
 20.1080 +    header.cluster_bits = cpu_to_be32(s->cluster_bits);
 20.1081 +    header_size = (header_size + 7) & ~7;
 20.1082 +    if (flags) {
 20.1083 +        header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES);
 20.1084 +    } else {
 20.1085 +        header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
 20.1086 +    }
 20.1087 +    l2_bits = s->cluster_bits - 3;
 20.1088 +    shift = s->cluster_bits + l2_bits;
 20.1089 +    l1_size = (((total_size * 512) + (1LL << shift) - 1) >> shift);
 20.1090 +    offset = align_offset(header_size, s->cluster_size);
 20.1091 +    s->l1_table_offset = offset;
 20.1092 +    header.l1_table_offset = cpu_to_be64(s->l1_table_offset);
 20.1093 +    header.l1_size = cpu_to_be32(l1_size);
 20.1094 +    offset += align_offset(l1_size * sizeof(uint64_t), s->cluster_size);
 20.1095 +
 20.1096 +    s->refcount_table = qemu_mallocz(s->cluster_size);
 20.1097 +    if (!s->refcount_table)
 20.1098 +        goto fail;
 20.1099 +    s->refcount_block = qemu_mallocz(s->cluster_size);
 20.1100 +    if (!s->refcount_block)
 20.1101 +        goto fail;
 20.1102 +    
 20.1103 +    s->refcount_table_offset = offset;
 20.1104 +    header.refcount_table_offset = cpu_to_be64(offset);
 20.1105 +    header.refcount_table_clusters = cpu_to_be32(1);
 20.1106 +    offset += s->cluster_size;
 20.1107 +
 20.1108 +    s->refcount_table[0] = cpu_to_be64(offset);
 20.1109 +    s->refcount_block_offset = offset;
 20.1110 +    offset += s->cluster_size;
 20.1111 +
 20.1112 +    /* update refcounts */
 20.1113 +    create_refcount_update(s, 0, header_size);
 20.1114 +    create_refcount_update(s, s->l1_table_offset, l1_size * sizeof(uint64_t));
 20.1115 +    create_refcount_update(s, s->refcount_table_offset, s->cluster_size);
 20.1116 +    create_refcount_update(s, s->refcount_block_offset, s->cluster_size);
 20.1117 +    
 20.1118 +    /* write all the data */
 20.1119 +    write(fd, &header, sizeof(header));
 20.1120 +    if (backing_file) {
 20.1121 +        write(fd, backing_file, backing_filename_len);
 20.1122 +    }
 20.1123 +    lseek(fd, s->l1_table_offset, SEEK_SET);
 20.1124 +    tmp = 0;
 20.1125 +    for(i = 0;i < l1_size; i++) {
 20.1126 +        write(fd, &tmp, sizeof(tmp));
 20.1127 +    }
 20.1128 +    lseek(fd, s->refcount_table_offset, SEEK_SET);
 20.1129 +    write(fd, s->refcount_table, s->cluster_size);
 20.1130 +    
 20.1131 +    lseek(fd, s->refcount_block_offset, SEEK_SET);
 20.1132 +    write(fd, s->refcount_block, s->cluster_size);
 20.1133 +
 20.1134 +    qemu_free(s->refcount_table);
 20.1135 +    qemu_free(s->refcount_block);
 20.1136 +    close(fd);
 20.1137 +    return 0;
 20.1138 + fail:
 20.1139 +    qemu_free(s->refcount_table);
 20.1140 +    qemu_free(s->refcount_block);
 20.1141 +    close(fd);
 20.1142 +    return -ENOMEM;
 20.1143 +}
 20.1144 +
 20.1145 +static int qcow_make_empty(BlockDriverState *bs)
 20.1146 +{
 20.1147 +#if 0
 20.1148 +    /* XXX: not correct */
 20.1149 +    BDRVQcowState *s = bs->opaque;
 20.1150 +    uint32_t l1_length = s->l1_size * sizeof(uint64_t);
 20.1151 +    int ret;
 20.1152 +
 20.1153 +    memset(s->l1_table, 0, l1_length);
 20.1154 +    if (bdrv_pwrite(s->hd, s->l1_table_offset, s->l1_table, l1_length) < 0)
 20.1155 +	return -1;
 20.1156 +    ret = bdrv_truncate(s->hd, s->l1_table_offset + l1_length);
 20.1157 +    if (ret < 0)
 20.1158 +        return ret;
 20.1159 +    
 20.1160 +    l2_cache_reset(bs);
 20.1161 +#endif
 20.1162 +    return 0;
 20.1163 +}
 20.1164 +
 20.1165 +/* XXX: put compressed sectors first, then all the cluster aligned
 20.1166 +   tables to avoid losing bytes in alignment */
 20.1167 +static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, 
 20.1168 +                                 const uint8_t *buf, int nb_sectors)
 20.1169 +{
 20.1170 +    BDRVQcowState *s = bs->opaque;
 20.1171 +    z_stream strm;
 20.1172 +    int ret, out_len;
 20.1173 +    uint8_t *out_buf;
 20.1174 +    uint64_t cluster_offset;
 20.1175 +
 20.1176 +    if (nb_sectors == 0) {
 20.1177 +        /* align end of file to a sector boundary to ease reading with
 20.1178 +           sector based I/Os */
 20.1179 +        cluster_offset = bdrv_getlength(s->hd);
 20.1180 +        cluster_offset = (cluster_offset + 511) & ~511;
 20.1181 +        bdrv_truncate(s->hd, cluster_offset);
 20.1182 +        return 0;
 20.1183 +    }
 20.1184 +
 20.1185 +    if (nb_sectors != s->cluster_sectors)
 20.1186 +        return -EINVAL;
 20.1187 +
 20.1188 +    out_buf = qemu_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);
 20.1189 +    if (!out_buf)
 20.1190 +        return -ENOMEM;
 20.1191 +
 20.1192 +    /* best compression, small window, no zlib header */
 20.1193 +    memset(&strm, 0, sizeof(strm));
 20.1194 +    ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION,
 20.1195 +                       Z_DEFLATED, -12, 
 20.1196 +                       9, Z_DEFAULT_STRATEGY);
 20.1197 +    if (ret != 0) {
 20.1198 +        qemu_free(out_buf);
 20.1199 +        return -1;
 20.1200 +    }
 20.1201 +
 20.1202 +    strm.avail_in = s->cluster_size;
 20.1203 +    strm.next_in = (uint8_t *)buf;
 20.1204 +    strm.avail_out = s->cluster_size;
 20.1205 +    strm.next_out = out_buf;
 20.1206 +
 20.1207 +    ret = deflate(&strm, Z_FINISH);
 20.1208 +    if (ret != Z_STREAM_END && ret != Z_OK) {
 20.1209 +        qemu_free(out_buf);
 20.1210 +        deflateEnd(&strm);
 20.1211 +        return -1;
 20.1212 +    }
 20.1213 +    out_len = strm.next_out - out_buf;
 20.1214 +
 20.1215 +    deflateEnd(&strm);
 20.1216 +
 20.1217 +    if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
 20.1218 +        /* could not compress: write normal cluster */
 20.1219 +        qcow_write(bs, sector_num, buf, s->cluster_sectors);
 20.1220 +    } else {
 20.1221 +        cluster_offset = get_cluster_offset(bs, sector_num << 9, 2, 
 20.1222 +                                            out_len, 0, 0);
 20.1223 +        cluster_offset &= s->cluster_offset_mask;
 20.1224 +        if (bdrv_pwrite(s->hd, cluster_offset, out_buf, out_len) != out_len) {
 20.1225 +            qemu_free(out_buf);
 20.1226 +            return -1;
 20.1227 +        }
 20.1228 +    }
 20.1229 +    
 20.1230 +    qemu_free(out_buf);
 20.1231 +    return 0;
 20.1232 +}
 20.1233 +
 20.1234 +static void qcow_flush(BlockDriverState *bs)
 20.1235 +{
 20.1236 +    BDRVQcowState *s = bs->opaque;
 20.1237 +    bdrv_flush(s->hd);
 20.1238 +}
 20.1239 +
 20.1240 +static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
 20.1241 +{
 20.1242 +    BDRVQcowState *s = bs->opaque;
 20.1243 +    bdi->cluster_size = s->cluster_size;
 20.1244 +    bdi->vm_state_offset = (int64_t)s->l1_vm_state_index << 
 20.1245 +        (s->cluster_bits + s->l2_bits);
 20.1246 +    return 0;
 20.1247 +}
 20.1248 +
 20.1249 +/*********************************************************/
 20.1250 +/* snapshot support */
 20.1251 +
 20.1252 +/* update the refcounts of snapshots and the copied flag */
 20.1253 +static int update_snapshot_refcount(BlockDriverState *bs, 
 20.1254 +                                    int64_t l1_table_offset,
 20.1255 +                                    int l1_size,
 20.1256 +                                    int addend)
 20.1257 +{
 20.1258 +    BDRVQcowState *s = bs->opaque;
 20.1259 +    uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2, l1_allocated;
 20.1260 +    int64_t old_offset, old_l2_offset;
 20.1261 +    int l2_size, i, j, l1_modified, l2_modified, nb_csectors, refcount;
 20.1262 +    
 20.1263 +    l2_cache_reset(bs);
 20.1264 +
 20.1265 +    l2_table = NULL;
 20.1266 +    l1_table = NULL;
 20.1267 +    l1_size2 = l1_size * sizeof(uint64_t);
 20.1268 +    l1_allocated = 0;
 20.1269 +    if (l1_table_offset != s->l1_table_offset) {
 20.1270 +        l1_table = qemu_malloc(l1_size2);
 20.1271 +        if (!l1_table)
 20.1272 +            goto fail;
 20.1273 +        l1_allocated = 1;
 20.1274 +        if (bdrv_pread(s->hd, l1_table_offset, 
 20.1275 +                       l1_table, l1_size2) != l1_size2)
 20.1276 +            goto fail;
 20.1277 +        for(i = 0;i < l1_size; i++)
 20.1278 +            be64_to_cpus(&l1_table[i]);
 20.1279 +    } else {
 20.1280 +        assert(l1_size == s->l1_size);
 20.1281 +        l1_table = s->l1_table;
 20.1282 +        l1_allocated = 0;
 20.1283 +    }
 20.1284 +    
 20.1285 +    l2_size = s->l2_size * sizeof(uint64_t);
 20.1286 +    l2_table = qemu_malloc(l2_size);
 20.1287 +    if (!l2_table)
 20.1288 +        goto fail;
 20.1289 +    l1_modified = 0;
 20.1290 +    for(i = 0; i < l1_size; i++) {
 20.1291 +        l2_offset = l1_table[i];
 20.1292 +        if (l2_offset) {
 20.1293 +            old_l2_offset = l2_offset;
 20.1294 +            l2_offset &= ~QCOW_OFLAG_COPIED;
 20.1295 +            l2_modified = 0;
 20.1296 +            if (bdrv_pread(s->hd, l2_offset, l2_table, l2_size) != l2_size)
 20.1297 +                goto fail;
 20.1298 +            for(j = 0; j < s->l2_size; j++) {
 20.1299 +                offset = be64_to_cpu(l2_table[j]);
 20.1300 +                if (offset != 0) {
 20.1301 +                    old_offset = offset;
 20.1302 +                    offset &= ~QCOW_OFLAG_COPIED;
 20.1303 +                    if (offset & QCOW_OFLAG_COMPRESSED) {
 20.1304 +                        nb_csectors = ((offset >> s->csize_shift) & 
 20.1305 +                                       s->csize_mask) + 1;
 20.1306 +                        if (addend != 0)
 20.1307 +                            update_refcount(bs, (offset & s->cluster_offset_mask) & ~511,
 20.1308 +                                            nb_csectors * 512, addend);
 20.1309 +                        /* compressed clusters are never modified */
 20.1310 +                        refcount = 2; 
 20.1311 +                    } else {
 20.1312 +                        if (addend != 0) {
 20.1313 +                            refcount = update_cluster_refcount(bs, offset >> s->cluster_bits, addend);
 20.1314 +                        } else {
 20.1315 +                            refcount = get_refcount(bs, offset >> s->cluster_bits);
 20.1316 +                        }
 20.1317 +                    }
 20.1318 +
 20.1319 +                    if (refcount == 1) {
 20.1320 +                        offset |= QCOW_OFLAG_COPIED;
 20.1321 +                    }
 20.1322 +                    if (offset != old_offset) {
 20.1323 +                        l2_table[j] = cpu_to_be64(offset);
 20.1324 +                        l2_modified = 1;
 20.1325 +                    }
 20.1326 +                }
 20.1327 +            }
 20.1328 +            if (l2_modified) {
 20.1329 +                if (bdrv_pwrite(s->hd, 
 20.1330 +                                l2_offset, l2_table, l2_size) != l2_size)
 20.1331 +                    goto fail;
 20.1332 +            }
 20.1333 +
 20.1334 +            if (addend != 0) {
 20.1335 +                refcount = update_cluster_refcount(bs, l2_offset >> s->cluster_bits, addend);
 20.1336 +            } else {
 20.1337 +                refcount = get_refcount(bs, l2_offset >> s->cluster_bits);
 20.1338 +            }
 20.1339 +            if (refcount == 1) {
 20.1340 +                l2_offset |= QCOW_OFLAG_COPIED;
 20.1341 +            }
 20.1342 +            if (l2_offset != old_l2_offset) {
 20.1343 +                l1_table[i] = l2_offset;
 20.1344 +                l1_modified = 1;
 20.1345 +            }
 20.1346 +        }
 20.1347 +    }
 20.1348 +    if (l1_modified) {
 20.1349 +        for(i = 0; i < l1_size; i++)
 20.1350 +            cpu_to_be64s(&l1_table[i]);
 20.1351 +        if (bdrv_pwrite(s->hd, l1_table_offset, l1_table, 
 20.1352 +                        l1_size2) != l1_size2)
 20.1353 +            goto fail;
 20.1354 +        for(i = 0; i < l1_size; i++)
 20.1355 +            be64_to_cpus(&l1_table[i]);
 20.1356 +    }
 20.1357 +    if (l1_allocated)
 20.1358 +        qemu_free(l1_table);
 20.1359 +    qemu_free(l2_table);
 20.1360 +    return 0;
 20.1361 + fail:
 20.1362 +    if (l1_allocated)
 20.1363 +        qemu_free(l1_table);
 20.1364 +    qemu_free(l2_table);
 20.1365 +    return -EIO;
 20.1366 +}
 20.1367 +
 20.1368 +static void qcow_free_snapshots(BlockDriverState *bs)
 20.1369 +{
 20.1370 +    BDRVQcowState *s = bs->opaque;
 20.1371 +    int i;
 20.1372 +
 20.1373 +    for(i = 0; i < s->nb_snapshots; i++) {
 20.1374 +        qemu_free(s->snapshots[i].name);
 20.1375 +        qemu_free(s->snapshots[i].id_str);
 20.1376 +    }
 20.1377 +    qemu_free(s->snapshots);
 20.1378 +    s->snapshots = NULL;
 20.1379 +    s->nb_snapshots = 0;
 20.1380 +}
 20.1381 +
 20.1382 +static int qcow_read_snapshots(BlockDriverState *bs)
 20.1383 +{
 20.1384 +    BDRVQcowState *s = bs->opaque;
 20.1385 +    QCowSnapshotHeader h;
 20.1386 +    QCowSnapshot *sn;
 20.1387 +    int i, id_str_size, name_size;
 20.1388 +    int64_t offset;
 20.1389 +    uint32_t extra_data_size;
 20.1390 +
 20.1391 +    offset = s->snapshots_offset;
 20.1392 +    s->snapshots = qemu_mallocz(s->nb_snapshots * sizeof(QCowSnapshot));
 20.1393 +    if (!s->snapshots)
 20.1394 +        goto fail;
 20.1395 +    for(i = 0; i < s->nb_snapshots; i++) {
 20.1396 +        offset = align_offset(offset, 8);
 20.1397 +        if (bdrv_pread(s->hd, offset, &h, sizeof(h)) != sizeof(h))
 20.1398 +            goto fail;
 20.1399 +        offset += sizeof(h);
 20.1400 +        sn = s->snapshots + i;
 20.1401 +        sn->l1_table_offset = be64_to_cpu(h.l1_table_offset);
 20.1402 +        sn->l1_size = be32_to_cpu(h.l1_size);
 20.1403 +        sn->vm_state_size = be32_to_cpu(h.vm_state_size);
 20.1404 +        sn->date_sec = be32_to_cpu(h.date_sec);
 20.1405 +        sn->date_nsec = be32_to_cpu(h.date_nsec);
 20.1406 +        sn->vm_clock_nsec = be64_to_cpu(h.vm_clock_nsec);
 20.1407 +        extra_data_size = be32_to_cpu(h.extra_data_size);
 20.1408 +
 20.1409 +        id_str_size = be16_to_cpu(h.id_str_size);
 20.1410 +        name_size = be16_to_cpu(h.name_size);
 20.1411 +
 20.1412 +        offset += extra_data_size;
 20.1413 +
 20.1414 +        sn->id_str = qemu_malloc(id_str_size + 1);
 20.1415 +        if (!sn->id_str)
 20.1416 +            goto fail;
 20.1417 +        if (bdrv_pread(s->hd, offset, sn->id_str, id_str_size) != id_str_size)
 20.1418 +            goto fail;
 20.1419 +        offset += id_str_size;
 20.1420 +        sn->id_str[id_str_size] = '\0';
 20.1421 +
 20.1422 +        sn->name = qemu_malloc(name_size + 1);
 20.1423 +        if (!sn->name)
 20.1424 +            goto fail;
 20.1425 +        if (bdrv_pread(s->hd, offset, sn->name, name_size) != name_size)
 20.1426 +            goto fail;
 20.1427 +        offset += name_size;
 20.1428 +        sn->name[name_size] = '\0';
 20.1429 +    }
 20.1430 +    s->snapshots_size = offset - s->snapshots_offset;
 20.1431 +    return 0;
 20.1432 + fail:
 20.1433 +    qcow_free_snapshots(bs);
 20.1434 +    return -1;
 20.1435 +}
 20.1436 +
 20.1437 +/* add at the end of the file a new list of snapshots */
 20.1438 +static int qcow_write_snapshots(BlockDriverState *bs)
 20.1439 +{
 20.1440 +    BDRVQcowState *s = bs->opaque;
 20.1441 +    QCowSnapshot *sn;
 20.1442 +    QCowSnapshotHeader h;
 20.1443 +    int i, name_size, id_str_size, snapshots_size;
 20.1444 +    uint64_t data64;
 20.1445 +    uint32_t data32;
 20.1446 +    int64_t offset, snapshots_offset;
 20.1447 +
 20.1448 +    /* compute the size of the snapshots */
 20.1449 +    offset = 0;
 20.1450 +    for(i = 0; i < s->nb_snapshots; i++) {
 20.1451 +        sn = s->snapshots + i;
 20.1452 +        offset = align_offset(offset, 8);
 20.1453 +        offset += sizeof(h);
 20.1454 +        offset += strlen(sn->id_str);
 20.1455 +        offset += strlen(sn->name);
 20.1456 +    }
 20.1457 +    snapshots_size = offset;
 20.1458 +
 20.1459 +    snapshots_offset = alloc_clusters(bs, snapshots_size);
 20.1460 +    offset = snapshots_offset;
 20.1461 +    
 20.1462 +    for(i = 0; i < s->nb_snapshots; i++) {
 20.1463 +        sn = s->snapshots + i;
 20.1464 +        memset(&h, 0, sizeof(h));
 20.1465 +        h.l1_table_offset = cpu_to_be64(sn->l1_table_offset);
 20.1466 +        h.l1_size = cpu_to_be32(sn->l1_size);
 20.1467 +        h.vm_state_size = cpu_to_be32(sn->vm_state_size);
 20.1468 +        h.date_sec = cpu_to_be32(sn->date_sec);
 20.1469 +        h.date_nsec = cpu_to_be32(sn->date_nsec);
 20.1470 +        h.vm_clock_nsec = cpu_to_be64(sn->vm_clock_nsec);
 20.1471 +        
 20.1472 +        id_str_size = strlen(sn->id_str);
 20.1473 +        name_size = strlen(sn->name);
 20.1474 +        h.id_str_size = cpu_to_be16(id_str_size);
 20.1475 +        h.name_size = cpu_to_be16(name_size);
 20.1476 +        offset = align_offset(offset, 8);
 20.1477 +        if (bdrv_pwrite(s->hd, offset, &h, sizeof(h)) != sizeof(h))
 20.1478 +            goto fail;
 20.1479 +        offset += sizeof(h);
 20.1480 +        if (bdrv_pwrite(s->hd, offset, sn->id_str, id_str_size) != id_str_size)
 20.1481 +            goto fail;
 20.1482 +        offset += id_str_size;
 20.1483 +        if (bdrv_pwrite(s->hd, offset, sn->name, name_size) != name_size)
 20.1484 +            goto fail;
 20.1485 +        offset += name_size;
 20.1486 +    }
 20.1487 +
 20.1488 +    /* update the various header fields */
 20.1489 +    data64 = cpu_to_be64(snapshots_offset);
 20.1490 +    if (bdrv_pwrite(s->hd, offsetof(QCowHeader, snapshots_offset),
 20.1491 +                    &data64, sizeof(data64)) != sizeof(data64))
 20.1492 +        goto fail;
 20.1493 +    data32 = cpu_to_be32(s->nb_snapshots);
 20.1494 +    if (bdrv_pwrite(s->hd, offsetof(QCowHeader, nb_snapshots),
 20.1495 +                    &data32, sizeof(data32)) != sizeof(data32))
 20.1496 +        goto fail;
 20.1497 +
 20.1498 +    /* free the old snapshot table */
 20.1499 +    free_clusters(bs, s->snapshots_offset, s->snapshots_size);
 20.1500 +    s->snapshots_offset = snapshots_offset;
 20.1501 +    s->snapshots_size = snapshots_size;
 20.1502 +    return 0;
 20.1503 + fail:
 20.1504 +    return -1;
 20.1505 +}
 20.1506 +
 20.1507 +static void find_new_snapshot_id(BlockDriverState *bs,
 20.1508 +                                 char *id_str, int id_str_size)
 20.1509 +{
 20.1510 +    BDRVQcowState *s = bs->opaque;
 20.1511 +    QCowSnapshot *sn;
 20.1512 +    int i, id, id_max = 0;
 20.1513 +
 20.1514 +    for(i = 0; i < s->nb_snapshots; i++) {
 20.1515 +        sn = s->snapshots + i;
 20.1516 +        id = strtoul(sn->id_str, NULL, 10);
 20.1517 +        if (id > id_max)
 20.1518 +            id_max = id;
 20.1519 +    }
 20.1520 +    snprintf(id_str, id_str_size, "%d", id_max + 1);
 20.1521 +}
 20.1522 +
 20.1523 +static int find_snapshot_by_id(BlockDriverState *bs, const char *id_str)
 20.1524 +{
 20.1525 +    BDRVQcowState *s = bs->opaque;
 20.1526 +    int i;
 20.1527 +
 20.1528 +    for(i = 0; i < s->nb_snapshots; i++) {
 20.1529 +        if (!strcmp(s->snapshots[i].id_str, id_str))
 20.1530 +            return i;
 20.1531 +    }
 20.1532 +    return -1;
 20.1533 +}
 20.1534 +
 20.1535 +static int find_snapshot_by_id_or_name(BlockDriverState *bs, const char *name)
 20.1536 +{
 20.1537 +    BDRVQcowState *s = bs->opaque;
 20.1538 +    int i, ret;
 20.1539 +    
 20.1540 +    ret = find_snapshot_by_id(bs, name);
 20.1541 +    if (ret >= 0)
 20.1542 +        return ret;
 20.1543 +    for(i = 0; i < s->nb_snapshots; i++) {
 20.1544 +        if (!strcmp(s->snapshots[i].name, name))
 20.1545 +            return i;
 20.1546 +    }
 20.1547 +    return -1;
 20.1548 +}
 20.1549 +
 20.1550 +/* if no id is provided, a new one is constructed */
 20.1551 +static int qcow_snapshot_create(BlockDriverState *bs, 
 20.1552 +                                QEMUSnapshotInfo *sn_info)
 20.1553 +{
 20.1554 +    BDRVQcowState *s = bs->opaque;
 20.1555 +    QCowSnapshot *snapshots1, sn1, *sn = &sn1;
 20.1556 +    int i, ret;
 20.1557 +    uint64_t *l1_table = NULL;
 20.1558 +    
 20.1559 +    memset(sn, 0, sizeof(*sn));
 20.1560 +
 20.1561 +    if (sn_info->id_str[0] == '\0') {
 20.1562 +        /* compute a new id */
 20.1563 +        find_new_snapshot_id(bs, sn_info->id_str, sizeof(sn_info->id_str));
 20.1564 +    }
 20.1565 +
 20.1566 +    /* check that the ID is unique */
 20.1567 +    if (find_snapshot_by_id(bs, sn_info->id_str) >= 0)
 20.1568 +        return -ENOENT;
 20.1569 +
 20.1570 +    sn->id_str = qemu_strdup(sn_info->id_str);
 20.1571 +    if (!sn->id_str)
 20.1572 +        goto fail;
 20.1573 +    sn->name = qemu_strdup(sn_info->name);
 20.1574 +    if (!sn->name)
 20.1575 +        goto fail;
 20.1576 +    sn->vm_state_size = sn_info->vm_state_size;
 20.1577 +    sn->date_sec = sn_info->date_sec;
 20.1578 +    sn->date_nsec = sn_info->date_nsec;
 20.1579 +    sn->vm_clock_nsec = sn_info->vm_clock_nsec;
 20.1580 +
 20.1581 +    ret = update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1);
 20.1582 +    if (ret < 0)
 20.1583 +        goto fail;
 20.1584 +
 20.1585 +    /* create the L1 table of the snapshot */
 20.1586 +    sn->l1_table_offset = alloc_clusters(bs, s->l1_size * sizeof(uint64_t));
 20.1587 +    sn->l1_size = s->l1_size;
 20.1588 +
 20.1589 +    l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
 20.1590 +    if (!l1_table)
 20.1591 +        goto fail;
 20.1592 +    for(i = 0; i < s->l1_size; i++) {
 20.1593 +        l1_table[i] = cpu_to_be64(s->l1_table[i]);
 20.1594 +    }
 20.1595 +    if (bdrv_pwrite(s->hd, sn->l1_table_offset,
 20.1596 +                    l1_table, s->l1_size * sizeof(uint64_t)) != 
 20.1597 +        (s->l1_size * sizeof(uint64_t)))
 20.1598 +        goto fail;
 20.1599 +    qemu_free(l1_table);
 20.1600 +    l1_table = NULL;
 20.1601 +
 20.1602 +    snapshots1 = qemu_malloc((s->nb_snapshots + 1) * sizeof(QCowSnapshot));
 20.1603 +    if (!snapshots1)
 20.1604 +        goto fail;
 20.1605 +    memcpy(snapshots1, s->snapshots, s->nb_snapshots * sizeof(QCowSnapshot));
 20.1606 +    s->snapshots = snapshots1;
 20.1607 +    s->snapshots[s->nb_snapshots++] = *sn;
 20.1608 +
 20.1609 +    if (qcow_write_snapshots(bs) < 0)
 20.1610 +        goto fail;
 20.1611 +#ifdef DEBUG_ALLOC
 20.1612 +    check_refcounts(bs);
 20.1613 +#endif
 20.1614 +    return 0;
 20.1615 + fail:
 20.1616 +    qemu_free(sn->name);
 20.1617 +    qemu_free(l1_table);
 20.1618 +    return -1;
 20.1619 +}
 20.1620 +
 20.1621 +/* copy the snapshot 'snapshot_name' into the current disk image */
 20.1622 +static int qcow_snapshot_goto(BlockDriverState *bs, 
 20.1623 +                              const char *snapshot_id)
 20.1624 +{
 20.1625 +    BDRVQcowState *s = bs->opaque;
 20.1626 +    QCowSnapshot *sn;
 20.1627 +    int i, snapshot_index, l1_size2;
 20.1628 +
 20.1629 +    snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
 20.1630 +    if (snapshot_index < 0)
 20.1631 +        return -ENOENT;
 20.1632 +    sn = &s->snapshots[snapshot_index];
 20.1633 +
 20.1634 +    if (update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, -1) < 0)
 20.1635 +        goto fail;
 20.1636 +
 20.1637 +    if (grow_l1_table(bs, sn->l1_size) < 0)
 20.1638 +        goto fail;
 20.1639 +
 20.1640 +    s->l1_size = sn->l1_size;
 20.1641 +    l1_size2 = s->l1_size * sizeof(uint64_t);
 20.1642 +    /* copy the snapshot l1 table to the current l1 table */
 20.1643 +    if (bdrv_pread(s->hd, sn->l1_table_offset, 
 20.1644 +                   s->l1_table, l1_size2) != l1_size2)
 20.1645 +        goto fail;
 20.1646 +    if (bdrv_pwrite(s->hd, s->l1_table_offset,
 20.1647 +                    s->l1_table, l1_size2) != l1_size2)
 20.1648 +        goto fail;
 20.1649 +    for(i = 0;i < s->l1_size; i++) {
 20.1650 +        be64_to_cpus(&s->l1_table[i]);
 20.1651 +    }
 20.1652 +
 20.1653 +    if (update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1) < 0)
 20.1654 +        goto fail;
 20.1655 +
 20.1656 +#ifdef DEBUG_ALLOC
 20.1657 +    check_refcounts(bs);
 20.1658 +#endif
 20.1659 +    return 0;
 20.1660 + fail:
 20.1661 +    return -EIO;
 20.1662 +}
 20.1663 +
 20.1664 +static int qcow_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
 20.1665 +{
 20.1666 +    BDRVQcowState *s = bs->opaque;
 20.1667 +    QCowSnapshot *sn;
 20.1668 +    int snapshot_index, ret;
 20.1669 +    
 20.1670 +    snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
 20.1671 +    if (snapshot_index < 0)
 20.1672 +        return -ENOENT;
 20.1673 +    sn = &s->snapshots[snapshot_index];
 20.1674 +
 20.1675 +    ret = update_snapshot_refcount(bs, sn->l1_table_offset, sn->l1_size, -1);
 20.1676 +    if (ret < 0)
 20.1677 +        return ret;
 20.1678 +    /* must update the copied flag on the current cluster offsets */
 20.1679 +    ret = update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 0);
 20.1680 +    if (ret < 0)
 20.1681 +        return ret;
 20.1682 +    free_clusters(bs, sn->l1_table_offset, sn->l1_size * sizeof(uint64_t));
 20.1683 +
 20.1684 +    qemu_free(sn->id_str);
 20.1685 +    qemu_free(sn->name);
 20.1686 +    memmove(sn, sn + 1, (s->nb_snapshots - snapshot_index - 1) * sizeof(*sn));
 20.1687 +    s->nb_snapshots--;
 20.1688 +    ret = qcow_write_snapshots(bs);
 20.1689 +    if (ret < 0) {
 20.1690 +        /* XXX: restore snapshot if error ? */
 20.1691 +        return ret;
 20.1692 +    }
 20.1693 +#ifdef DEBUG_ALLOC
 20.1694 +    check_refcounts(bs);
 20.1695 +#endif
 20.1696 +    return 0;
 20.1697 +}
 20.1698 +
 20.1699 +static int qcow_snapshot_list(BlockDriverState *bs, 
 20.1700 +                              QEMUSnapshotInfo **psn_tab)
 20.1701 +{
 20.1702 +    BDRVQcowState *s = bs->opaque;
 20.1703 +    QEMUSnapshotInfo *sn_tab, *sn_info;
 20.1704 +    QCowSnapshot *sn;
 20.1705 +    int i;
 20.1706 +
 20.1707 +    sn_tab = qemu_mallocz(s->nb_snapshots * sizeof(QEMUSnapshotInfo));
 20.1708 +    if (!sn_tab)
 20.1709 +        goto fail;
 20.1710 +    for(i = 0; i < s->nb_snapshots; i++) {
 20.1711 +        sn_info = sn_tab + i;
 20.1712 +        sn = s->snapshots + i;
 20.1713 +        pstrcpy(sn_info->id_str, sizeof(sn_info->id_str),
 20.1714 +                sn->id_str);
 20.1715 +        pstrcpy(sn_info->name, sizeof(sn_info->name),
 20.1716 +                sn->name);
 20.1717 +        sn_info->vm_state_size = sn->vm_state_size;
 20.1718 +        sn_info->date_sec = sn->date_sec;
 20.1719 +        sn_info->date_nsec = sn->date_nsec;
 20.1720 +        sn_info->vm_clock_nsec = sn->vm_clock_nsec;
 20.1721 +    }
 20.1722 +    *psn_tab = sn_tab;
 20.1723 +    return s->nb_snapshots;
 20.1724 + fail:
 20.1725 +    qemu_free(sn_tab);
 20.1726 +    *psn_tab = NULL;
 20.1727 +    return -ENOMEM;
 20.1728 +}
 20.1729 +
 20.1730 +/*********************************************************/
 20.1731 +/* refcount handling */
 20.1732 +
 20.1733 +static int refcount_init(BlockDriverState *bs)
 20.1734 +{
 20.1735 +    BDRVQcowState *s = bs->opaque;
 20.1736 +    int ret, refcount_table_size2, i;
 20.1737 +    
 20.1738 +    s->refcount_block_cache = qemu_malloc(s->cluster_size);
 20.1739 +    if (!s->refcount_block_cache)
 20.1740 +        goto fail;
 20.1741 +    refcount_table_size2 = s->refcount_table_size * sizeof(uint64_t);
 20.1742 +    s->refcount_table = qemu_malloc(refcount_table_size2);
 20.1743 +    if (!s->refcount_table)
 20.1744 +        goto fail;
 20.1745 +    if (s->refcount_table_size > 0) {
 20.1746 +        ret = bdrv_pread(s->hd, s->refcount_table_offset,
 20.1747 +                         s->refcount_table, refcount_table_size2);
 20.1748 +        if (ret != refcount_table_size2)
 20.1749 +            goto fail;
 20.1750 +        for(i = 0; i < s->refcount_table_size; i++)
 20.1751 +            be64_to_cpus(&s->refcount_table[i]);
 20.1752 +    }
 20.1753 +    return 0;
 20.1754 + fail:
 20.1755 +    return -ENOMEM;
 20.1756 +}
 20.1757 +
 20.1758 +static void refcount_close(BlockDriverState *bs)
 20.1759 +{
 20.1760 +    BDRVQcowState *s = bs->opaque;
 20.1761 +    qemu_free(s->refcount_block_cache);
 20.1762 +    qemu_free(s->refcount_table);
 20.1763 +}
 20.1764 +
 20.1765 +
 20.1766 +static int load_refcount_block(BlockDriverState *bs, 
 20.1767 +                               int64_t refcount_block_offset)
 20.1768 +{
 20.1769 +    BDRVQcowState *s = bs->opaque;
 20.1770 +    int ret;
 20.1771 +    ret = bdrv_pread(s->hd, refcount_block_offset, s->refcount_block_cache, 
 20.1772 +                     s->cluster_size);
 20.1773 +    if (ret != s->cluster_size)
 20.1774 +        return -EIO;
 20.1775 +    s->refcount_block_cache_offset = refcount_block_offset;
 20.1776 +    return 0;
 20.1777 +}
 20.1778 +
 20.1779 +static int get_refcount(BlockDriverState *bs, int64_t cluster_index)
 20.1780 +{
 20.1781 +    BDRVQcowState *s = bs->opaque;
 20.1782 +    int refcount_table_index, block_index;
 20.1783 +    int64_t refcount_block_offset;
 20.1784 +
 20.1785 +    refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
 20.1786 +    if (refcount_table_index >= s->refcount_table_size)
 20.1787 +        return 0;
 20.1788 +    refcount_block_offset = s->refcount_table[refcount_table_index];
 20.1789 +    if (!refcount_block_offset)
 20.1790 +        return 0;
 20.1791 +    if (refcount_block_offset != s->refcount_block_cache_offset) {
 20.1792 +        /* better than nothing: return allocated if read error */
 20.1793 +        if (load_refcount_block(bs, refcount_block_offset) < 0)
 20.1794 +            return 1;
 20.1795 +    }
 20.1796 +    block_index = cluster_index & 
 20.1797 +        ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
 20.1798 +    return be16_to_cpu(s->refcount_block_cache[block_index]);
 20.1799 +}
 20.1800 +
 20.1801 +/* return < 0 if error */
 20.1802 +static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size)
 20.1803 +{
 20.1804 +    BDRVQcowState *s = bs->opaque;
 20.1805 +    int i, nb_clusters;
 20.1806 +
 20.1807 +    nb_clusters = (size + s->cluster_size - 1) >> s->cluster_bits;
 20.1808 +    for(;;) {
 20.1809 +        if (get_refcount(bs, s->free_cluster_index) == 0) {
 20.1810 +            s->free_cluster_index++;
 20.1811 +            for(i = 1; i < nb_clusters; i++) {
 20.1812 +                if (get_refcount(bs, s->free_cluster_index) != 0)
 20.1813 +                    goto not_found;
 20.1814 +                s->free_cluster_index++;
 20.1815 +            }
 20.1816 +#ifdef DEBUG_ALLOC2
 20.1817 +            printf("alloc_clusters: size=%lld -> %lld\n",
 20.1818 +                   size, 
 20.1819 +                   (s->free_cluster_index - nb_clusters) << s->cluster_bits);
 20.1820 +#endif
 20.1821 +            return (s->free_cluster_index - nb_clusters) << s->cluster_bits;
 20.1822 +        } else {
 20.1823 +        not_found:
 20.1824 +            s->free_cluster_index++;
 20.1825 +        }
 20.1826 +    }
 20.1827 +}
 20.1828 +
 20.1829 +static int64_t alloc_clusters(BlockDriverState *bs, int64_t size)
 20.1830 +{
 20.1831 +    int64_t offset;
 20.1832 +
 20.1833 +    offset = alloc_clusters_noref(bs, size);
 20.1834 +    update_refcount(bs, offset, size, 1);
 20.1835 +    return offset;
 20.1836 +}
 20.1837 +
 20.1838 +/* only used to allocate compressed sectors. We try to allocate
 20.1839 +   contiguous sectors. size must be <= cluster_size */
 20.1840 +static int64_t alloc_bytes(BlockDriverState *bs, int size)
 20.1841 +{
 20.1842 +    BDRVQcowState *s = bs->opaque;
 20.1843 +    int64_t offset, cluster_offset;
 20.1844 +    int free_in_cluster;
 20.1845 +    
 20.1846 +    assert(size > 0 && size <= s->cluster_size);
 20.1847 +    if (s->free_byte_offset == 0) {
 20.1848 +        s->free_byte_offset = alloc_clusters(bs, s->cluster_size);
 20.1849 +    }
 20.1850 + redo:
 20.1851 +    free_in_cluster = s->cluster_size - 
 20.1852 +        (s->free_byte_offset & (s->cluster_size - 1));
 20.1853 +    if (size <= free_in_cluster) {
 20.1854 +        /* enough space in current cluster */
 20.1855 +        offset = s->free_byte_offset;
 20.1856 +        s->free_byte_offset += size;
 20.1857 +        free_in_cluster -= size;
 20.1858 +        if (free_in_cluster == 0)
 20.1859 +            s->free_byte_offset = 0;
 20.1860 +        if ((offset & (s->cluster_size - 1)) != 0)
 20.1861 +            update_cluster_refcount(bs, offset >> s->cluster_bits, 1);
 20.1862 +    } else {
 20.1863 +        offset = alloc_clusters(bs, s->cluster_size);
 20.1864 +        cluster_offset = s->free_byte_offset & ~(s->cluster_size - 1);
 20.1865 +        if ((cluster_offset + s->cluster_size) == offset) {
 20.1866 +            /* we are lucky: contiguous data */
 20.1867 +            offset = s->free_byte_offset;
 20.1868 +            update_cluster_refcount(bs, offset >> s->cluster_bits, 1);
 20.1869 +            s->free_byte_offset += size;
 20.1870 +        } else {
 20.1871 +            s->free_byte_offset = offset;
 20.1872 +            goto redo;
 20.1873 +        }
 20.1874 +    }
 20.1875 +    return offset;
 20.1876 +}
 20.1877 +
 20.1878 +static void free_clusters(BlockDriverState *bs, 
 20.1879 +                          int64_t offset, int64_t size)
 20.1880 +{
 20.1881 +    update_refcount(bs, offset, size, -1);
 20.1882 +}
 20.1883 +
 20.1884 +static int grow_refcount_table(BlockDriverState *bs, int min_size)
 20.1885 +{
 20.1886 +    BDRVQcowState *s = bs->opaque;
 20.1887 +    int new_table_size, new_table_size2, refcount_table_clusters, i, ret;
 20.1888 +    uint64_t *new_table;
 20.1889 +    int64_t table_offset;
 20.1890 +    uint64_t data64;
 20.1891 +    uint32_t data32;
 20.1892 +
 20.1893 +    if (min_size <= s->refcount_table_size)
 20.1894 +        return 0;
 20.1895 +    /* compute new table size */
 20.1896 +    refcount_table_clusters = s->refcount_table_size >> (s->cluster_bits - 3);
 20.1897 +    for(;;) {
 20.1898 +        if (refcount_table_clusters == 0) {
 20.1899 +            refcount_table_clusters = 1;
 20.1900 +        } else {
 20.1901 +            refcount_table_clusters = (refcount_table_clusters * 3 + 1) / 2;
 20.1902 +        }
 20.1903 +        new_table_size = refcount_table_clusters << (s->cluster_bits - 3);
 20.1904 +        if (min_size <= new_table_size)
 20.1905 +            break;
 20.1906 +    }
 20.1907 +#ifdef DEBUG_ALLOC2
 20.1908 +    printf("grow_refcount_table from %d to %d\n",
 20.1909 +           s->refcount_table_size,
 20.1910 +           new_table_size);
 20.1911 +#endif
 20.1912 +    new_table_size2 = new_table_size * sizeof(uint64_t);
 20.1913 +    new_table = qemu_mallocz(new_table_size2);
 20.1914 +    if (!new_table)
 20.1915 +        return -ENOMEM;
 20.1916 +    memcpy(new_table, s->refcount_table, 
 20.1917 +           s->refcount_table_size * sizeof(uint64_t));
 20.1918 +    for(i = 0; i < s->refcount_table_size; i++)
 20.1919 +        cpu_to_be64s(&new_table[i]);
 20.1920 +    /* Note: we cannot update the refcount now to avoid recursion */
 20.1921 +    table_offset = alloc_clusters_noref(bs, new_table_size2);
 20.1922 +    ret = bdrv_pwrite(s->hd, table_offset, new_table, new_table_size2);
 20.1923 +    if (ret != new_table_size2) 
 20.1924 +        goto fail;
 20.1925 +    for(i = 0; i < s->refcount_table_size; i++)
 20.1926 +        be64_to_cpus(&new_table[i]);
 20.1927 +
 20.1928 +    data64 = cpu_to_be64(table_offset);
 20.1929 +    if (bdrv_pwrite(s->hd, offsetof(QCowHeader, refcount_table_offset),
 20.1930 +                    &data64, sizeof(data64)) != sizeof(data64))
 20.1931 +        goto fail;
 20.1932 +    data32 = cpu_to_be32(refcount_table_clusters);
 20.1933 +    if (bdrv_pwrite(s->hd, offsetof(QCowHeader, refcount_table_clusters),
 20.1934 +                    &data32, sizeof(data32)) != sizeof(data32))
 20.1935 +        goto fail;
 20.1936 +    qemu_free(s->refcount_table);
 20.1937 +    s->refcount_table = new_table;
 20.1938 +    s->refcount_table_size = new_table_size;
 20.1939 +
 20.1940 +    update_refcount(bs, table_offset, new_table_size2, 1);
 20.1941 +    return 0;
 20.1942 + fail:
 20.1943 +    free_clusters(bs, table_offset, new_table_size2);
 20.1944 +    qemu_free(new_table);
 20.1945 +    return -EIO;
 20.1946 +}
 20.1947 +
 20.1948 +/* addend must be 1 or -1 */
 20.1949 +/* XXX: cache several refcount block clusters ? */
 20.1950 +static int update_cluster_refcount(BlockDriverState *bs, 
 20.1951 +                                   int64_t cluster_index,
 20.1952 +                                   int addend)
 20.1953 +{
 20.1954 +    BDRVQcowState *s = bs->opaque;
 20.1955 +    int64_t offset, refcount_block_offset;
 20.1956 +    int ret, refcount_table_index, block_index, refcount;
 20.1957 +    uint64_t data64;
 20.1958 +
 20.1959 +    refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
 20.1960 +    if (refcount_table_index >= s->refcount_table_size) {
 20.1961 +        if (addend < 0)
 20.1962 +            return -EINVAL;
 20.1963 +        ret = grow_refcount_table(bs, refcount_table_index + 1);
 20.1964 +        if (ret < 0)
 20.1965 +            return ret;
 20.1966 +    }
 20.1967 +    refcount_block_offset = s->refcount_table[refcount_table_index];
 20.1968 +    if (!refcount_block_offset) {
 20.1969 +        if (addend < 0)
 20.1970 +            return -EINVAL;
 20.1971 +        /* create a new refcount block */
 20.1972 +        /* Note: we cannot update the refcount now to avoid recursion */
 20.1973 +        offset = alloc_clusters_noref(bs, s->cluster_size);
 20.1974 +        memset(s->refcount_block_cache, 0, s->cluster_size);
 20.1975 +        ret = bdrv_pwrite(s->hd, offset, s->refcount_block_cache, s->cluster_size);
 20.1976 +        if (ret != s->cluster_size)
 20.1977 +            return -EINVAL;
 20.1978 +        s->refcount_table[refcount_table_index] = offset;
 20.1979 +        data64 = cpu_to_be64(offset);
 20.1980 +        ret = bdrv_pwrite(s->hd, s->refcount_table_offset + 
 20.1981 +                          refcount_table_index * sizeof(uint64_t), 
 20.1982 +                          &data64, sizeof(data64));
 20.1983 +        if (ret != sizeof(data64))
 20.1984 +            return -EINVAL;
 20.1985 +
 20.1986 +        refcount_block_offset = offset;
 20.1987 +        s->refcount_block_cache_offset = offset;
 20.1988 +        update_refcount(bs, offset, s->cluster_size, 1);
 20.1989 +    } else {
 20.1990 +        if (refcount_block_offset != s->refcount_block_cache_offset) {
 20.1991 +            if (load_refcount_block(bs, refcount_block_offset) < 0)
 20.1992 +                return -EIO;
 20.1993 +        }
 20.1994 +    }
 20.1995 +    /* we can update the count and save it */
 20.1996 +    block_index = cluster_index & 
 20.1997 +        ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
 20.1998 +    refcount = be16_to_cpu(s->refcount_block_cache[block_index]);
 20.1999 +    refcount += addend;
 20.2000 +    if (refcount < 0 || refcount > 0xffff)
 20.2001 +        return -EINVAL;
 20.2002 +    if (refcount == 0 && cluster_index < s->free_cluster_index) {
 20.2003 +        s->free_cluster_index = cluster_index;
 20.2004 +    }
 20.2005 +    s->refcount_block_cache[block_index] = cpu_to_be16(refcount);
 20.2006 +    if (bdrv_pwrite(s->hd, 
 20.2007 +                    refcount_block_offset + (block_index << REFCOUNT_SHIFT), 
 20.2008 +                    &s->refcount_block_cache[block_index], 2) != 2)
 20.2009 +        return -EIO;
 20.2010 +    return refcount;
 20.2011 +}
 20.2012 +
 20.2013 +static void update_refcount(BlockDriverState *bs, 
 20.2014 +                            int64_t offset, int64_t length, 
 20.2015 +                            int addend)
 20.2016 +{
 20.2017 +    BDRVQcowState *s = bs->opaque;
 20.2018 +    int64_t start, last, cluster_offset;
 20.2019 +
 20.2020 +#ifdef DEBUG_ALLOC2
 20.2021 +    printf("update_refcount: offset=%lld size=%lld addend=%d\n", 
 20.2022 +           offset, length, addend);
 20.2023 +#endif
 20.2024 +    if (length <= 0)
 20.2025 +        return;
 20.2026 +    start = offset & ~(s->cluster_size - 1);
 20.2027 +    last = (offset + length - 1) & ~(s->cluster_size - 1);
 20.2028 +    for(cluster_offset = start; cluster_offset <= last; 
 20.2029 +        cluster_offset += s->cluster_size) {
 20.2030 +        update_cluster_refcount(bs, cluster_offset >> s->cluster_bits, addend);
 20.2031 +    }
 20.2032 +}
 20.2033 +
 20.2034 +#ifdef DEBUG_ALLOC
 20.2035 +static void inc_refcounts(BlockDriverState *bs, 
 20.2036 +                          uint16_t *refcount_table, 
 20.2037 +                          int refcount_table_size,
 20.2038 +                          int64_t offset, int64_t size)
 20.2039 +{
 20.2040 +    BDRVQcowState *s = bs->opaque;
 20.2041 +    int64_t start, last, cluster_offset;
 20.2042 +    int k;
 20.2043 +    
 20.2044 +    if (size <= 0)
 20.2045 +        return;
 20.2046 +
 20.2047 +    start = offset & ~(s->cluster_size - 1);
 20.2048 +    last = (offset + size - 1) & ~(s->cluster_size - 1);
 20.2049 +    for(cluster_offset = start; cluster_offset <= last; 
 20.2050 +        cluster_offset += s->cluster_size) {
 20.2051 +        k = cluster_offset >> s->cluster_bits;
 20.2052 +        if (k < 0 || k >= refcount_table_size) {
 20.2053 +            printf("ERROR: invalid cluster offset=0x%llx\n", cluster_offset);
 20.2054 +        } else {
 20.2055 +            if (++refcount_table[k] == 0) {
 20.2056 +                printf("ERROR: overflow cluster offset=0x%llx\n", cluster_offset);
 20.2057 +            }
 20.2058 +        }
 20.2059 +    }
 20.2060 +}
 20.2061 +
 20.2062 +static int check_refcounts_l1(BlockDriverState *bs, 
 20.2063 +                              uint16_t *refcount_table, 
 20.2064 +                              int refcount_table_size,
 20.2065 +                              int64_t l1_table_offset, int l1_size,
 20.2066 +                              int check_copied)
 20.2067 +{
 20.2068 +    BDRVQcowState *s = bs->opaque;
 20.2069 +    uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2;
 20.2070 +    int l2_size, i, j, nb_csectors, refcount;
 20.2071 +
 20.2072 +    l2_table = NULL;
 20.2073 +    l1_size2 = l1_size * sizeof(uint64_t);
 20.2074 +
 20.2075 +    inc_refcounts(bs, refcount_table, refcount_table_size,
 20.2076 +                  l1_table_offset, l1_size2);
 20.2077 +
 20.2078 +    l1_table = qemu_malloc(l1_size2);
 20.2079 +    if (!l1_table)
 20.2080 +        goto fail;
 20.2081 +    if (bdrv_pread(s->hd, l1_table_offset, 
 20.2082 +                   l1_table, l1_size2) != l1_size2)
 20.2083 +        goto fail;
 20.2084 +    for(i = 0;i < l1_size; i++)
 20.2085 +        be64_to_cpus(&l1_table[i]);
 20.2086 +    
 20.2087 +    l2_size = s->l2_size * sizeof(uint64_t);
 20.2088 +    l2_table = qemu_malloc(l2_size);
 20.2089 +    if (!l2_table)
 20.2090 +        goto fail;
 20.2091 +    for(i = 0; i < l1_size; i++) {
 20.2092 +        l2_offset = l1_table[i];
 20.2093 +        if (l2_offset) {
 20.2094 +            if (check_copied) {
 20.2095 +                refcount = get_refcount(bs, (l2_offset & ~QCOW_OFLAG_COPIED) >> s->cluster_bits);
 20.2096 +                if ((refcount == 1) != ((l2_offset & QCOW_OFLAG_COPIED) != 0)) {
 20.2097 +                    printf("ERROR OFLAG_COPIED: l2_offset=%llx refcount=%d\n",
 20.2098 +                           l2_offset, refcount);
 20.2099 +                }
 20.2100 +            }
 20.2101 +            l2_offset &= ~QCOW_OFLAG_COPIED;
 20.2102 +            if (bdrv_pread(s->hd, l2_offset, l2_table, l2_size) != l2_size)
 20.2103 +                goto fail;
 20.2104 +            for(j = 0; j < s->l2_size; j++) {
 20.2105 +                offset = be64_to_cpu(l2_table[j]);
 20.2106 +                if (offset != 0) {
 20.2107 +                    if (offset & QCOW_OFLAG_COMPRESSED) {
 20.2108 +                        if (offset & QCOW_OFLAG_COPIED) {
 20.2109 +                            printf("ERROR: cluster %lld: copied flag must never be set for compressed clusters\n",
 20.2110 +                                   offset >> s->cluster_bits);
 20.2111 +                            offset &= ~QCOW_OFLAG_COPIED;
 20.2112 +                        }
 20.2113 +                        nb_csectors = ((offset >> s->csize_shift) & 
 20.2114 +                                       s->csize_mask) + 1;
 20.2115 +                        offset &= s->cluster_offset_mask;
 20.2116 +                        inc_refcounts(bs, refcount_table, 
 20.2117 +                                      refcount_table_size,
 20.2118 +                                      offset & ~511, nb_csectors * 512);
 20.2119 +                    } else {
 20.2120 +                        if (check_copied) {
 20.2121 +                            refcount = get_refcount(bs, (offset & ~QCOW_OFLAG_COPIED) >> s->cluster_bits);
 20.2122 +                            if ((refcount == 1) != ((offset & QCOW_OFLAG_COPIED) != 0)) {
 20.2123 +                                printf("ERROR OFLAG_COPIED: offset=%llx refcount=%d\n",
 20.2124 +                                       offset, refcount);
 20.2125 +                            }
 20.2126 +                        }
 20.2127 +                        offset &= ~QCOW_OFLAG_COPIED;
 20.2128 +                        inc_refcounts(bs, refcount_table, 
 20.2129 +                                      refcount_table_size,
 20.2130 +                                      offset, s->cluster_size);
 20.2131 +                    }
 20.2132 +                }
 20.2133 +            }
 20.2134 +            inc_refcounts(bs, refcount_table, 
 20.2135 +                          refcount_table_size,
 20.2136 +                          l2_offset,
 20.2137 +                          s->cluster_size);
 20.2138 +        }
 20.2139 +    }
 20.2140 +    qemu_free(l1_table);
 20.2141 +    qemu_free(l2_table);
 20.2142 +    return 0;
 20.2143 + fail:
 20.2144 +    printf("ERROR: I/O error in check_refcounts_l1\n");
 20.2145 +    qemu_free(l1_table);
 20.2146 +    qemu_free(l2_table);
 20.2147 +    return -EIO;
 20.2148 +}
 20.2149 +
 20.2150 +static void check_refcounts(BlockDriverState *bs)
 20.2151 +{
 20.2152 +    BDRVQcowState *s = bs->opaque;
 20.2153 +    int64_t size;
 20.2154 +    int nb_clusters, refcount1, refcount2, i;
 20.2155 +    QCowSnapshot *sn;
 20.2156 +    uint16_t *refcount_table;
 20.2157 +
 20.2158 +    size = bdrv_getlength(s->hd);
 20.2159 +    nb_clusters = (size + s->cluster_size - 1) >> s->cluster_bits;
 20.2160 +    refcount_table = qemu_mallocz(nb_clusters * sizeof(uint16_t));
 20.2161 +
 20.2162 +    /* header */
 20.2163 +    inc_refcounts(bs, refcount_table, nb_clusters,
 20.2164 +                  0, s->cluster_size);
 20.2165 +    
 20.2166 +    check_refcounts_l1(bs, refcount_table, nb_clusters,
 20.2167 +                       s->l1_table_offset, s->l1_size, 1);
 20.2168 +
 20.2169 +    /* snapshots */
 20.2170 +    for(i = 0; i < s->nb_snapshots; i++) {
 20.2171 +        sn = s->snapshots + i;
 20.2172 +        check_refcounts_l1(bs, refcount_table, nb_clusters,
 20.2173 +                           sn->l1_table_offset, sn->l1_size, 0);
 20.2174 +    }
 20.2175 +    inc_refcounts(bs, refcount_table, nb_clusters,
 20.2176 +                  s->snapshots_offset, s->snapshots_size);
 20.2177 +
 20.2178 +    /* refcount data */
 20.2179 +    inc_refcounts(bs, refcount_table, nb_clusters,
 20.2180 +                  s->refcount_table_offset, 
 20.2181 +                  s->refcount_table_size * sizeof(uint64_t));
 20.2182 +    for(i = 0; i < s->refcount_table_size; i++) {
 20.2183 +        int64_t offset;
 20.2184 +        offset = s->refcount_table[i];
 20.2185 +        if (offset != 0) {
 20.2186 +            inc_refcounts(bs, refcount_table, nb_clusters,
 20.2187 +                          offset, s->cluster_size);
 20.2188 +        }
 20.2189 +    }
 20.2190 +
 20.2191 +    /* compare ref counts */
 20.2192 +    for(i = 0; i < nb_clusters; i++) {
 20.2193 +        refcount1 = get_refcount(bs, i);
 20.2194 +        refcount2 = refcount_table[i];
 20.2195 +        if (refcount1 != refcount2)
 20.2196 +            printf("ERROR cluster %d refcount=%d reference=%d\n",
 20.2197 +                   i, refcount1, refcount2);
 20.2198 +    }
 20.2199 +
 20.2200 +    qemu_free(refcount_table);
 20.2201 +}
 20.2202 +
 20.2203 +#if 0
 20.2204 +static void dump_refcounts(BlockDriverState *bs)
 20.2205 +{
 20.2206 +    BDRVQcowState *s = bs->opaque;
 20.2207 +    int64_t nb_clusters, k, k1, size;
 20.2208 +    int refcount;
 20.2209 +
 20.2210 +    size = bdrv_getlength(s->hd);
 20.2211 +    nb_clusters = (size + s->cluster_size - 1) >> s->cluster_bits;
 20.2212 +    for(k = 0; k < nb_clusters;) {
 20.2213 +        k1 = k;
 20.2214 +        refcount = get_refcount(bs, k);
 20.2215 +        k++;
 20.2216 +        while (k < nb_clusters && get_refcount(bs, k) == refcount)
 20.2217 +            k++;
 20.2218 +        printf("%lld: refcount=%d nb=%lld\n", k, refcount, k - k1);
 20.2219 +    }
 20.2220 +}
 20.2221 +#endif
 20.2222 +#endif
 20.2223 +
 20.2224 +BlockDriver bdrv_qcow2 = {
 20.2225 +    "qcow2",
 20.2226 +    sizeof(BDRVQcowState),
 20.2227 +    qcow_probe,
 20.2228 +    qcow_open,
 20.2229 +    NULL,
 20.2230 +    NULL,
 20.2231 +    qcow_close,
 20.2232 +    qcow_create,
 20.2233 +    qcow_flush,
 20.2234 +    qcow_is_allocated,
 20.2235 +    qcow_set_key,
 20.2236 +    qcow_make_empty,
 20.2237 +
 20.2238 +    .bdrv_aio_read = qcow_aio_read,
 20.2239 +    .bdrv_aio_write = qcow_aio_write,
 20.2240 +    .bdrv_aio_cancel = qcow_aio_cancel,
 20.2241 +    .aiocb_size = sizeof(QCowAIOCB),
 20.2242 +    .bdrv_write_compressed = qcow_write_compressed,
 20.2243 +
 20.2244 +    .bdrv_snapshot_create = qcow_snapshot_create,
 20.2245 +    .bdrv_snapshot_goto = qcow_snapshot_goto,
 20.2246 +    .bdrv_snapshot_delete = qcow_snapshot_delete,
 20.2247 +    .bdrv_snapshot_list = qcow_snapshot_list,
 20.2248 +    .bdrv_get_info = qcow_get_info,
 20.2249 +};
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/tools/ioemu/block-raw.c	Wed May 09 14:17:15 2007 +0100
    21.3 @@ -0,0 +1,1353 @@
    21.4 +/*
    21.5 + * Block driver for RAW files
    21.6 + * 
    21.7 + * Copyright (c) 2006 Fabrice Bellard
    21.8 + * 
    21.9 + * Permission is hereby granted, free of charge, to any person obtaining a copy
   21.10 + * of this software and associated documentation files (the "Software"), to deal
   21.11 + * in the Software without restriction, including without limitation the rights
   21.12 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   21.13 + * copies of the Software, and to permit persons to whom the Software is
   21.14 + * furnished to do so, subject to the following conditions:
   21.15 + *
   21.16 + * The above copyright notice and this permission notice shall be included in
   21.17 + * all copies or substantial portions of the Software.
   21.18 + *
   21.19 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   21.20 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   21.21 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   21.22 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   21.23 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   21.24 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   21.25 + * THE SOFTWARE.
   21.26 + */
   21.27 +#include "vl.h"
   21.28 +#include "block_int.h"
   21.29 +#include <assert.h>
   21.30 +#ifndef _WIN32
   21.31 +#include <aio.h>
   21.32 +
   21.33 +#ifndef QEMU_TOOL
   21.34 +#include "exec-all.h"
   21.35 +#endif
   21.36 +
   21.37 +#ifdef CONFIG_COCOA
   21.38 +#include <paths.h>
   21.39 +#include <sys/param.h>
   21.40 +#include <IOKit/IOKitLib.h>
   21.41 +#include <IOKit/IOBSD.h>
   21.42 +#include <IOKit/storage/IOMediaBSDClient.h>
   21.43 +#include <IOKit/storage/IOMedia.h>
   21.44 +#include <IOKit/storage/IOCDMedia.h>
   21.45 +//#include <IOKit/storage/IOCDTypes.h>
   21.46 +#include <CoreFoundation/CoreFoundation.h>
   21.47 +#endif
   21.48 +
   21.49 +#ifdef __sun__
   21.50 +#define _POSIX_PTHREAD_SEMANTICS 1
   21.51 +#include <signal.h>
   21.52 +#include <sys/dkio.h>
   21.53 +#endif
   21.54 +#ifdef __linux__
   21.55 +#include <sys/ioctl.h>
   21.56 +#include <linux/cdrom.h>
   21.57 +#include <linux/fd.h>
   21.58 +#endif
   21.59 +#ifdef __FreeBSD__
   21.60 +#include <sys/disk.h>
   21.61 +#endif
   21.62 +
   21.63 +//#define DEBUG_FLOPPY
   21.64 +
   21.65 +#define FTYPE_FILE   0
   21.66 +#define FTYPE_CD     1
   21.67 +#define FTYPE_FD     2
   21.68 +
   21.69 +/* if the FD is not accessed during that time (in ms), we try to
   21.70 +   reopen it to see if the disk has been changed */
   21.71 +#define FD_OPEN_TIMEOUT 1000
   21.72 +
   21.73 +typedef struct BDRVRawState {
   21.74 +    int fd;
   21.75 +    int type;
   21.76 +#if defined(__linux__)
   21.77 +    /* linux floppy specific */
   21.78 +    int fd_open_flags;
   21.79 +    int64_t fd_open_time;
   21.80 +    int64_t fd_error_time;
   21.81 +    int fd_got_error;
   21.82 +    int fd_media_changed;
   21.83 +#endif
   21.84 +} BDRVRawState;
   21.85 +
   21.86 +static int fd_open(BlockDriverState *bs);
   21.87 +
   21.88 +static int raw_open(BlockDriverState *bs, const char *filename, int flags)
   21.89 +{
   21.90 +    BDRVRawState *s = bs->opaque;
   21.91 +    int fd, open_flags, ret;
   21.92 +
   21.93 +    open_flags = O_BINARY;
   21.94 +    if ((flags & BDRV_O_ACCESS) == O_RDWR) {
   21.95 +        open_flags |= O_RDWR;
   21.96 +    } else {
   21.97 +        open_flags |= O_RDONLY;
   21.98 +        bs->read_only = 1;
   21.99 +    }
  21.100 +    if (flags & BDRV_O_CREAT)
  21.101 +        open_flags |= O_CREAT | O_TRUNC;
  21.102 +
  21.103 +    s->type = FTYPE_FILE;
  21.104 +
  21.105 +    fd = open(filename, open_flags, 0644);
  21.106 +    if (fd < 0) {
  21.107 +        ret = -errno;
  21.108 +        if (ret == -EROFS)
  21.109 +            ret = -EACCES;
  21.110 +        return ret;
  21.111 +    }
  21.112 +    s->fd = fd;
  21.113 +    return 0;
  21.114 +}
  21.115 +
  21.116 +/* XXX: use host sector size if necessary with:
  21.117 +#ifdef DIOCGSECTORSIZE
  21.118 +        {
  21.119 +            unsigned int sectorsize = 512;
  21.120 +            if (!ioctl(fd, DIOCGSECTORSIZE, &sectorsize) &&
  21.121 +                sectorsize > bufsize)
  21.122 +                bufsize = sectorsize;
  21.123 +        }
  21.124 +#endif
  21.125 +#ifdef CONFIG_COCOA
  21.126 +        u_int32_t   blockSize = 512;
  21.127 +        if ( !ioctl( fd, DKIOCGETBLOCKSIZE, &blockSize ) && blockSize > bufsize) {
  21.128 +            bufsize = blockSize;
  21.129 +        }
  21.130 +#endif
  21.131 +*/
  21.132 +
  21.133 +static int raw_pread(BlockDriverState *bs, int64_t offset, 
  21.134 +                     uint8_t *buf, int count)
  21.135 +{
  21.136 +    BDRVRawState *s = bs->opaque;
  21.137 +    int ret;
  21.138 +    
  21.139 +    ret = fd_open(bs);
  21.140 +    if (ret < 0)
  21.141 +        return ret;
  21.142 +
  21.143 +    lseek(s->fd, offset, SEEK_SET);
  21.144 +    ret = read(s->fd, buf, count);
  21.145 +    return ret;
  21.146 +}
  21.147 +
  21.148 +static int raw_pwrite(BlockDriverState *bs, int64_t offset, 
  21.149 +                      const uint8_t *buf, int count)
  21.150 +{
  21.151 +    BDRVRawState *s = bs->opaque;
  21.152 +    int ret;
  21.153 +    
  21.154 +    ret = fd_open(bs);
  21.155 +    if (ret < 0)
  21.156 +        return ret;
  21.157 +
  21.158 +    lseek(s->fd, offset, SEEK_SET);
  21.159 +    ret = write(s->fd, buf, count);
  21.160 +    return ret;
  21.161 +}
  21.162 +
  21.163 +/***********************************************************/
  21.164 +/* Unix AIO using POSIX AIO */
  21.165 +
  21.166 +typedef struct RawAIOCB {
  21.167 +    BlockDriverAIOCB common;
  21.168 +    struct aiocb aiocb;
  21.169 +    struct RawAIOCB *next;
  21.170 +} RawAIOCB;
  21.171 +
  21.172 +static int aio_sig_num = SIGUSR2;
  21.173 +static RawAIOCB *first_aio; /* AIO issued */
  21.174 +static int aio_initialized = 0;
  21.175 +
  21.176 +static void aio_signal_handler(int signum)
  21.177 +{
  21.178 +#ifndef QEMU_TOOL
  21.179 +    CPUState *env = cpu_single_env;
  21.180 +    if (env) {
  21.181 +        /* stop the currently executing cpu because a timer occured */
  21.182 +        cpu_interrupt(env, CPU_INTERRUPT_EXIT);
  21.183 +#ifdef USE_KQEMU
  21.184 +        if (env->kqemu_enabled) {
  21.185 +            kqemu_cpu_interrupt(env);
  21.186 +        }
  21.187 +#endif
  21.188 +    }
  21.189 +#endif
  21.190 +}
  21.191 +
  21.192 +void qemu_aio_init(void)
  21.193 +{
  21.194 +    struct sigaction act;
  21.195 +
  21.196 +    aio_initialized = 1;
  21.197 +    
  21.198 +    sigfillset(&act.sa_mask);
  21.199 +    act.sa_flags = 0; /* do not restart syscalls to interrupt select() */
  21.200 +    act.sa_handler = aio_signal_handler;
  21.201 +    sigaction(aio_sig_num, &act, NULL);
  21.202 +
  21.203 +#if defined(__GLIBC__) && defined(__linux__)
  21.204 +    {
  21.205 +        /* XXX: aio thread exit seems to hang on RedHat 9 and this init
  21.206 +           seems to fix the problem. */
  21.207 +        struct aioinit ai;
  21.208 +        memset(&ai, 0, sizeof(ai));
  21.209 +        ai.aio_threads = 1;
  21.210 +        ai.aio_num = 1;
  21.211 +        ai.aio_idle_time = 365 * 100000;
  21.212 +        aio_init(&ai);
  21.213 +    }
  21.214 +#endif
  21.215 +}
  21.216 +
  21.217 +void qemu_aio_poll(void)
  21.218 +{
  21.219 +    RawAIOCB *acb, **pacb;
  21.220 +    int ret;
  21.221 +
  21.222 +    for(;;) {
  21.223 +        pacb = &first_aio;
  21.224 +        for(;;) {
  21.225 +            acb = *pacb;
  21.226 +            if (!acb)
  21.227 +                goto the_end;
  21.228 +            ret = aio_error(&acb->aiocb);
  21.229 +            if (ret == ECANCELED) {
  21.230 +                /* remove the request */
  21.231 +                *pacb = acb->next;
  21.232 +                qemu_aio_release(acb);
  21.233 +            } else if (ret != EINPROGRESS) {
  21.234 +                /* end of aio */
  21.235 +                if (ret == 0) {
  21.236 +                    ret = aio_return(&acb->aiocb);
  21.237 +                    if (ret == acb->aiocb.aio_nbytes)
  21.238 +                        ret = 0;
  21.239 +                    else
  21.240 +                        ret = -EINVAL;
  21.241 +                } else {
  21.242 +                    ret = -ret;
  21.243 +                }
  21.244 +                /* remove the request */
  21.245 +                *pacb = acb->next;
  21.246 +                /* call the callback */
  21.247 +                acb->common.cb(acb->common.opaque, ret);
  21.248 +                qemu_aio_release(acb);
  21.249 +                break;
  21.250 +            } else {
  21.251 +                pacb = &acb->next;
  21.252 +            }
  21.253 +        }
  21.254 +    }
  21.255 + the_end: ;
  21.256 +}
  21.257 +
  21.258 +/* Wait for all IO requests to complete.  */
  21.259 +void qemu_aio_flush(void)
  21.260 +{
  21.261 +    qemu_aio_wait_start();
  21.262 +    qemu_aio_poll();
  21.263 +    while (first_aio) {
  21.264 +        qemu_aio_wait();
  21.265 +    }
  21.266 +    qemu_aio_wait_end();
  21.267 +}
  21.268 +
  21.269 +/* wait until at least one AIO was handled */
  21.270 +static sigset_t wait_oset;
  21.271 +
  21.272 +void qemu_aio_wait_start(void)
  21.273 +{
  21.274 +    sigset_t set;
  21.275 +
  21.276 +    if (!aio_initialized)
  21.277 +        qemu_aio_init();
  21.278 +    sigemptyset(&set);
  21.279 +    sigaddset(&set, aio_sig_num);
  21.280 +    sigprocmask(SIG_BLOCK, &set, &wait_oset);
  21.281 +}
  21.282 +
  21.283 +void qemu_aio_wait(void)
  21.284 +{
  21.285 +    sigset_t set;
  21.286 +    int nb_sigs;
  21.287 +
  21.288 +#ifndef QEMU_TOOL
  21.289 +    if (qemu_bh_poll())
  21.290 +        return;
  21.291 +#endif
  21.292 +    sigemptyset(&set);
  21.293 +    sigaddset(&set, aio_sig_num);
  21.294 +    sigwait(&set, &nb_sigs);
  21.295 +    qemu_aio_poll();
  21.296 +}
  21.297 +
  21.298 +void qemu_aio_wait_end(void)
  21.299 +{
  21.300 +    sigprocmask(SIG_SETMASK, &wait_oset, NULL);
  21.301 +}
  21.302 +
  21.303 +static RawAIOCB *raw_aio_setup(BlockDriverState *bs,
  21.304 +        int64_t sector_num, uint8_t *buf, int nb_sectors,
  21.305 +        BlockDriverCompletionFunc *cb, void *opaque)
  21.306 +{
  21.307 +    BDRVRawState *s = bs->opaque;
  21.308 +    RawAIOCB *acb;
  21.309 +
  21.310 +    if (fd_open(bs) < 0)
  21.311 +        return NULL;
  21.312 +
  21.313 +    acb = qemu_aio_get(bs, cb, opaque);
  21.314 +    if (!acb)
  21.315 +        return NULL;
  21.316 +    acb->aiocb.aio_fildes = s->fd;
  21.317 +    acb->aiocb.aio_sigevent.sigev_signo = aio_sig_num;
  21.318 +    acb->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
  21.319 +    acb->aiocb.aio_buf = buf;
  21.320 +    acb->aiocb.aio_nbytes = nb_sectors * 512;
  21.321 +    acb->aiocb.aio_offset = sector_num * 512;
  21.322 +    acb->next = first_aio;
  21.323 +    first_aio = acb;
  21.324 +    return acb;
  21.325 +}
  21.326 +
  21.327 +static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs,
  21.328 +        int64_t sector_num, uint8_t *buf, int nb_sectors,
  21.329 +        BlockDriverCompletionFunc *cb, void *opaque)
  21.330 +{
  21.331 +    RawAIOCB *acb;
  21.332 +
  21.333 +    acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
  21.334 +    if (!acb)
  21.335 +        return NULL;
  21.336 +    if (aio_read(&acb->aiocb) < 0) {
  21.337 +        qemu_aio_release(acb);
  21.338 +        return NULL;
  21.339 +    } 
  21.340 +    return &acb->common;
  21.341 +}
  21.342 +
  21.343 +static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs,
  21.344 +        int64_t sector_num, const uint8_t *buf, int nb_sectors,
  21.345 +        BlockDriverCompletionFunc *cb, void *opaque)
  21.346 +{
  21.347 +    RawAIOCB *acb;
  21.348 +
  21.349 +    acb = raw_aio_setup(bs, sector_num, (uint8_t*)buf, nb_sectors, cb, opaque);
  21.350 +    if (!acb)
  21.351 +        return NULL;
  21.352 +    if (aio_write(&acb->aiocb) < 0) {
  21.353 +        qemu_aio_release(acb);
  21.354 +        return NULL;
  21.355 +    } 
  21.356 +    return &acb->common;
  21.357 +}
  21.358 +
  21.359 +static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
  21.360 +{
  21.361 +    int ret;
  21.362 +    RawAIOCB *acb = (RawAIOCB *)blockacb;
  21.363 +    RawAIOCB **pacb;
  21.364 +
  21.365 +    ret = aio_cancel(acb->aiocb.aio_fildes, &acb->aiocb);
  21.366 +    if (ret == AIO_NOTCANCELED) {
  21.367 +        /* fail safe: if the aio could not be canceled, we wait for
  21.368 +           it */
  21.369 +        while (aio_error(&acb->aiocb) == EINPROGRESS);
  21.370 +    }
  21.371 +
  21.372 +    /* remove the callback from the queue */
  21.373 +    pacb = &first_aio;
  21.374 +    for(;;) {
  21.375 +        if (*pacb == NULL) {
  21.376 +            break;
  21.377 +        } else if (*pacb == acb) {
  21.378 +            *pacb = acb->next;
  21.379 +            qemu_aio_release(acb);
  21.380 +            break;
  21.381 +        }
  21.382 +        pacb = &acb->next;
  21.383 +    }
  21.384 +}
  21.385 +
  21.386 +static void raw_close(BlockDriverState *bs)
  21.387 +{
  21.388 +    BDRVRawState *s = bs->opaque;
  21.389 +    bs->total_sectors = 0;
  21.390 +    if (s->fd >= 0) {
  21.391 +        close(s->fd);
  21.392 +        s->fd = -1;
  21.393 +    }
  21.394 +}
  21.395 +
  21.396 +static int raw_truncate(BlockDriverState *bs, int64_t offset)
  21.397 +{
  21.398 +    BDRVRawState *s = bs->opaque;
  21.399 +    if (s->type != FTYPE_FILE)
  21.400 +        return -ENOTSUP;
  21.401 +    if (ftruncate(s->fd, offset) < 0)
  21.402 +        return -errno;
  21.403 +    return 0;
  21.404 +}
  21.405 +
  21.406 +static int64_t  raw_getlength(BlockDriverState *bs)
  21.407 +{
  21.408 +    BDRVRawState *s = bs->opaque;
  21.409 +    int fd = s->fd;
  21.410 +    int64_t size;
  21.411 +#ifdef _BSD
  21.412 +    struct stat sb;
  21.413 +#endif
  21.414 +#ifdef __sun__
  21.415 +    struct dk_minfo minfo;
  21.416 +    int rv;
  21.417 +#endif
  21.418 +    int ret;
  21.419 +
  21.420 +    ret = fd_open(bs);
  21.421 +    if (ret < 0)
  21.422 +        return ret;
  21.423 +
  21.424 +#ifdef _BSD
  21.425 +    if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) {
  21.426 +#ifdef DIOCGMEDIASIZE
  21.427 +	if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size))
  21.428 +#endif
  21.429 +#ifdef CONFIG_COCOA
  21.430 +        size = LONG_LONG_MAX;
  21.431 +#else
  21.432 +        size = lseek(fd, 0LL, SEEK_END);
  21.433 +#endif
  21.434 +    } else
  21.435 +#endif
  21.436 +#ifdef __sun__
  21.437 +    /*
  21.438 +     * use the DKIOCGMEDIAINFO ioctl to read the size.
  21.439 +     */
  21.440 +    rv = ioctl ( fd, DKIOCGMEDIAINFO, &minfo );
  21.441 +    if ( rv != -1 ) {
  21.442 +        size = minfo.dki_lbsize * minfo.dki_capacity;
  21.443 +    } else /* there are reports that lseek on some devices
  21.444 +              fails, but irc discussion said that contingency
  21.445 +              on contingency was overkill */
  21.446 +#endif
  21.447 +    {
  21.448 +        size = lseek(fd, 0, SEEK_END);
  21.449 +    }
  21.450 +    return size;
  21.451 +}
  21.452 +
  21.453 +static int raw_create(const char *filename, int64_t total_size,
  21.454 +                      const char *backing_file, int flags)
  21.455 +{
  21.456 +    int fd;
  21.457 +
  21.458 +    if (flags || backing_file)
  21.459 +        return -ENOTSUP;
  21.460 +
  21.461 +    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 
  21.462 +              0644);
  21.463 +    if (fd < 0)
  21.464 +        return -EIO;
  21.465 +    ftruncate(fd, total_size * 512);
  21.466 +    close(fd);
  21.467 +    return 0;
  21.468 +}
  21.469 +
  21.470 +static void raw_flush(BlockDriverState *bs)
  21.471 +{
  21.472 +    BDRVRawState *s = bs->opaque;
  21.473 +    fsync(s->fd);
  21.474 +}
  21.475 +
  21.476 +BlockDriver bdrv_raw = {
  21.477 +    "raw",
  21.478 +    sizeof(BDRVRawState),
  21.479 +    NULL, /* no probe for protocols */
  21.480 +    raw_open,
  21.481 +    NULL,
  21.482 +    NULL,
  21.483 +    raw_close,
  21.484 +    raw_create,
  21.485 +    raw_flush,
  21.486 +    
  21.487 +    .bdrv_aio_read = raw_aio_read,
  21.488 +    .bdrv_aio_write = raw_aio_write,
  21.489 +    .bdrv_aio_cancel = raw_aio_cancel,
  21.490 +    .aiocb_size = sizeof(RawAIOCB),
  21.491 +    .protocol_name = "file",
  21.492 +    .bdrv_pread = raw_pread,
  21.493 +    .bdrv_pwrite = raw_pwrite,
  21.494 +    .bdrv_truncate = raw_truncate,
  21.495 +    .bdrv_getlength = raw_getlength,
  21.496 +};
  21.497 +
  21.498 +/***********************************************/
  21.499 +/* host device */
  21.500 +
  21.501 +#ifdef CONFIG_COCOA
  21.502 +static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator );
  21.503 +static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize );
  21.504 +
  21.505 +kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )
  21.506 +{
  21.507 +    kern_return_t       kernResult; 
  21.508 +    mach_port_t     masterPort;
  21.509 +    CFMutableDictionaryRef  classesToMatch;
  21.510 +
  21.511 +    kernResult = IOMasterPort( MACH_PORT_NULL, &masterPort );
  21.512 +    if ( KERN_SUCCESS != kernResult ) {
  21.513 +        printf( "IOMasterPort returned %d\n", kernResult );
  21.514 +    }
  21.515 +    
  21.516 +    classesToMatch = IOServiceMatching( kIOCDMediaClass ); 
  21.517 +    if ( classesToMatch == NULL ) {
  21.518 +        printf( "IOServiceMatching returned a NULL dictionary.\n" );
  21.519 +    } else {
  21.520 +    CFDictionarySetValue( classesToMatch, CFSTR( kIOMediaEjectableKey ), kCFBooleanTrue );
  21.521 +    }
  21.522 +    kernResult = IOServiceGetMatchingServices( masterPort, classesToMatch, mediaIterator );
  21.523 +    if ( KERN_SUCCESS != kernResult )
  21.524 +    {
  21.525 +        printf( "IOServiceGetMatchingServices returned %d\n", kernResult );
  21.526 +    }
  21.527 +    
  21.528 +    return kernResult;
  21.529 +}
  21.530 +
  21.531 +kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize )
  21.532 +{
  21.533 +    io_object_t     nextMedia;
  21.534 +    kern_return_t   kernResult = KERN_FAILURE;
  21.535 +    *bsdPath = '\0';
  21.536 +    nextMedia = IOIteratorNext( mediaIterator );
  21.537 +    if ( nextMedia )
  21.538 +    {
  21.539 +        CFTypeRef   bsdPathAsCFString;
  21.540 +    bsdPathAsCFString = IORegistryEntryCreateCFProperty( nextMedia, CFSTR( kIOBSDNameKey ), kCFAllocatorDefault, 0 );
  21.541 +        if ( bsdPathAsCFString ) {
  21.542 +            size_t devPathLength;
  21.543 +            strcpy( bsdPath, _PATH_DEV );
  21.544 +            strcat( bsdPath, "r" );
  21.545 +            devPathLength = strlen( bsdPath );
  21.546 +            if ( CFStringGetCString( bsdPathAsCFString, bsdPath + devPathLength, maxPathSize - devPathLength, kCFStringEncodingASCII ) ) {
  21.547 +                kernResult = KERN_SUCCESS;
  21.548 +            }
  21.549 +            CFRelease( bsdPathAsCFString );
  21.550 +        }
  21.551 +        IOObjectRelease( nextMedia );
  21.552 +    }
  21.553 +    
  21.554 +    return kernResult;
  21.555 +}
  21.556 +
  21.557 +#endif
  21.558 +
  21.559 +static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
  21.560 +{
  21.561 +    BDRVRawState *s = bs->opaque;
  21.562 +    int fd, open_flags, ret;
  21.563 +
  21.564 +#ifdef CONFIG_COCOA
  21.565 +    if (strstart(filename, "/dev/cdrom", NULL)) {
  21.566 +        kern_return_t kernResult;
  21.567 +        io_iterator_t mediaIterator;
  21.568 +        char bsdPath[ MAXPATHLEN ];
  21.569 +        int fd;
  21.570 + 
  21.571 +        kernResult = FindEjectableCDMedia( &mediaIterator );
  21.572 +        kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) );
  21.573 +    
  21.574 +        if ( bsdPath[ 0 ] != '\0' ) {
  21.575 +            strcat(bsdPath,"s0");
  21.576 +            /* some CDs don't have a partition 0 */
  21.577 +            fd = open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE);
  21.578 +            if (fd < 0) {
  21.579 +                bsdPath[strlen(bsdPath)-1] = '1';
  21.580 +            } else {
  21.581 +                close(fd);
  21.582 +            }
  21.583 +            filename = bsdPath;
  21.584 +        }
  21.585 +        
  21.586 +        if ( mediaIterator )
  21.587 +            IOObjectRelease( mediaIterator );
  21.588 +    }
  21.589 +#endif
  21.590 +    open_flags = O_BINARY;
  21.591 +    if ((flags & BDRV_O_ACCESS) == O_RDWR) {
  21.592 +        open_flags |= O_RDWR;
  21.593 +    } else {
  21.594 +        open_flags |= O_RDONLY;
  21.595 +        bs->read_only = 1;
  21.596 +    }
  21.597 +
  21.598 +    s->type = FTYPE_FILE;
  21.599 +#if defined(__linux__)
  21.600 +    if (strstart(filename, "/dev/cd", NULL)) {
  21.601 +        /* open will not fail even if no CD is inserted */
  21.602 +        open_flags |= O_NONBLOCK;
  21.603 +        s->type = FTYPE_CD;
  21.604 +    } else if (strstart(filename, "/dev/fd", NULL)) {
  21.605 +        s->type = FTYPE_FD;
  21.606 +        s->fd_open_flags = open_flags;
  21.607 +        /* open will not fail even if no floppy is inserted */
  21.608 +        open_flags |= O_NONBLOCK;
  21.609 +    }
  21.610 +#endif
  21.611 +    fd = open(filename, open_flags, 0644);
  21.612 +    if (fd < 0) {
  21.613 +        ret = -errno;
  21.614 +        if (ret == -EROFS)
  21.615 +            ret = -EACCES;
  21.616 +        return ret;
  21.617 +    }
  21.618 +    s->fd = fd;
  21.619 +#if defined(__linux__)
  21.620 +    /* close fd so that we can reopen it as needed */
  21.621 +    if (s->type == FTYPE_FD) {
  21.622 +        close(s->fd);
  21.623 +        s->fd = -1;
  21.624 +        s->fd_media_changed = 1;
  21.625 +    }
  21.626 +#endif
  21.627 +    return 0;
  21.628 +}
  21.629 +
  21.630 +#if defined(__linux__) && !defined(QEMU_TOOL)
  21.631 +
  21.632 +/* Note: we do not have a reliable method to detect if the floppy is
  21.633 +   present. The current method is to try to open the floppy at every
  21.634 +   I/O and to keep it opened during a few hundreds of ms. */
  21.635 +static int fd_open(BlockDriverState *bs)
  21.636 +{
  21.637 +    BDRVRawState *s = bs->opaque;
  21.638 +    int last_media_present;
  21.639 +
  21.640 +    if (s->type != FTYPE_FD)
  21.641 +        return 0;
  21.642 +    last_media_present = (s->fd >= 0);
  21.643 +    if (s->fd >= 0 && 
  21.644 +        (qemu_get_clock(rt_clock) - s->fd_open_time) >= FD_OPEN_TIMEOUT) {
  21.645 +        close(s->fd);
  21.646 +        s->fd = -1;
  21.647 +#ifdef DEBUG_FLOPPY
  21.648 +        printf("Floppy closed\n");
  21.649 +#endif
  21.650 +    }
  21.651 +    if (s->fd < 0) {
  21.652 +        if (s->fd_got_error && 
  21.653 +            (qemu_get_clock(rt_clock) - s->fd_error_time) < FD_OPEN_TIMEOUT) {
  21.654 +#ifdef DEBUG_FLOPPY
  21.655 +            printf("No floppy (open delayed)\n");
  21.656 +#endif
  21.657 +            return -EIO;
  21.658 +        }
  21.659 +        s->fd = open(bs->filename, s->fd_open_flags);
  21.660 +        if (s->fd < 0) {
  21.661 +            s->fd_error_time = qemu_get_clock(rt_clock);
  21.662 +            s->fd_got_error = 1;
  21.663 +            if (last_media_present)
  21.664 +                s->fd_media_changed = 1;
  21.665 +#ifdef DEBUG_FLOPPY
  21.666 +            printf("No floppy\n");
  21.667 +#endif
  21.668 +            return -EIO;
  21.669 +        }
  21.670 +#ifdef DEBUG_FLOPPY
  21.671 +        printf("Floppy opened\n");
  21.672 +#endif
  21.673 +    }
  21.674 +    if (!last_media_present)
  21.675 +        s->fd_media_changed = 1;
  21.676 +    s->fd_open_time = qemu_get_clock(rt_clock);
  21.677 +    s->fd_got_error = 0;
  21.678 +    return 0;
  21.679 +}
  21.680 +#else
  21.681 +static int fd_open(BlockDriverState *bs)
  21.682 +{
  21.683 +    return 0;
  21.684 +}
  21.685 +#endif
  21.686 +
  21.687 +#if defined(__linux__)
  21.688 +
  21.689 +static int raw_is_inserted(BlockDriverState *bs)
  21.690 +{
  21.691 +    BDRVRawState *s = bs->opaque;
  21.692 +    int ret;
  21.693 +
  21.694 +    switch(s->type) {
  21.695 +    case FTYPE_CD:
  21.696 +        ret = ioctl(s->fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
  21.697 +        if (ret == CDS_DISC_OK)
  21.698 +            return 1;
  21.699 +        else
  21.700 +            return 0;
  21.701 +        break;
  21.702 +    case FTYPE_FD:
  21.703 +        ret = fd_open(bs);
  21.704 +        return (ret >= 0);
  21.705 +    default:
  21.706 +        return 1;
  21.707 +    }
  21.708 +}
  21.709 +
  21.710 +/* currently only used by fdc.c, but a CD version would be good too */
  21.711 +static int raw_media_changed(BlockDriverState *bs)
  21.712 +{
  21.713 +    BDRVRawState *s = bs->opaque;
  21.714 +
  21.715 +    switch(s->type) {
  21.716 +    case FTYPE_FD:
  21.717 +        {
  21.718 +            int ret;
  21.719 +            /* XXX: we do not have a true media changed indication. It
  21.720 +               does not work if the floppy is changed without trying
  21.721 +               to read it */
  21.722 +            fd_open(bs);
  21.723 +            ret = s->fd_media_changed;
  21.724 +            s->fd_media_changed = 0;
  21.725 +#ifdef DEBUG_FLOPPY
  21.726 +            printf("Floppy changed=%d\n", ret);
  21.727 +#endif
  21.728 +            return ret;
  21.729 +        }
  21.730 +    default:
  21.731 +        return -ENOTSUP;
  21.732 +    }
  21.733 +}
  21.734 +
  21.735 +static int raw_eject(BlockDriverState *bs, int eject_flag)
  21.736 +{
  21.737 +    BDRVRawState *s = bs->opaque;
  21.738 +
  21.739 +    switch(s->type) {
  21.740 +    case FTYPE_CD:
  21.741 +        if (eject_flag) {
  21.742 +            if (ioctl (s->fd, CDROMEJECT, NULL) < 0)
  21.743 +                perror("CDROMEJECT");
  21.744 +        } else {
  21.745 +            if (ioctl (s->fd, CDROMCLOSETRAY, NULL) < 0)
  21.746 +                perror("CDROMEJECT");
  21.747 +        }
  21.748 +        break;
  21.749 +    case FTYPE_FD:
  21.750 +        {
  21.751 +            int fd;
  21.752 +            if (s->fd >= 0) {
  21.753 +                close(s->fd);
  21.754 +                s->fd = -1;
  21.755 +            }
  21.756 +            fd = open(bs->filename, s->fd_open_flags | O_NONBLOCK);
  21.757 +            if (fd >= 0) {
  21.758 +                if (ioctl(fd, FDEJECT, 0) < 0)
  21.759 +                    perror("FDEJECT");
  21.760 +                close(fd);
  21.761 +            }
  21.762 +        }
  21.763 +        break;
  21.764 +    default:
  21.765 +        return -ENOTSUP;
  21.766 +    }
  21.767 +    return 0;
  21.768 +}
  21.769 +
  21.770 +static int raw_set_locked(BlockDriverState *bs, int locked)
  21.771 +{
  21.772 +    BDRVRawState *s = bs->opaque;
  21.773 +
  21.774 +    switch(s->type) {
  21.775 +    case FTYPE_CD:
  21.776 +        if (ioctl (s->fd, CDROM_LOCKDOOR, locked) < 0) {
  21.777 +            /* Note: an error can happen if the distribution automatically
  21.778 +               mounts the CD-ROM */
  21.779 +            //        perror("CDROM_LOCKDOOR");
  21.780 +        }
  21.781 +        break;
  21.782 +    default:
  21.783 +        return -ENOTSUP;
  21.784 +    }
  21.785 +    return 0;
  21.786 +}
  21.787 +
  21.788 +#else
  21.789 +
  21.790 +static int raw_is_inserted(BlockDriverState *bs)
  21.791 +{
  21.792 +    return 1;
  21.793 +}
  21.794 +
  21.795 +static int raw_media_changed(BlockDriverState *bs)
  21.796 +{
  21.797 +    return -ENOTSUP;
  21.798 +}
  21.799 +
  21.800 +static int raw_eject(BlockDriverState *bs, int eject_flag)
  21.801 +{
  21.802 +    return -ENOTSUP;
  21.803 +}
  21.804 +
  21.805 +static int raw_set_locked(BlockDriverState *bs, int locked)
  21.806 +{
  21.807 +    return -ENOTSUP;
  21.808 +}
  21.809 +
  21.810 +#endif /* !linux */
  21.811 +
  21.812 +BlockDriver bdrv_host_device = {
  21.813 +    "host_device",
  21.814 +    sizeof(BDRVRawState),
  21.815 +    NULL, /* no probe for protocols */
  21.816 +    hdev_open,
  21.817 +    NULL,
  21.818 +    NULL,
  21.819 +    raw_close,
  21.820 +    NULL,
  21.821 +    raw_flush,
  21.822 +    
  21.823 +    .bdrv_aio_read = raw_aio_read,
  21.824 +    .bdrv_aio_write = raw_aio_write,
  21.825 +    .bdrv_aio_cancel = raw_aio_cancel,
  21.826 +    .aiocb_size = sizeof(RawAIOCB),
  21.827 +    .bdrv_pread = raw_pread,
  21.828 +    .bdrv_pwrite = raw_pwrite,
  21.829 +    .bdrv_getlength = raw_getlength,
  21.830 +
  21.831 +    /* removable device support */
  21.832 +    .bdrv_is_inserted = raw_is_inserted,
  21.833 +    .bdrv_media_changed = raw_media_changed,
  21.834 +    .bdrv_eject = raw_eject,
  21.835 +    .bdrv_set_locked = raw_set_locked,
  21.836 +};
  21.837 +
  21.838 +#else /* _WIN32 */
  21.839 +
  21.840 +/* XXX: use another file ? */
  21.841 +#include <winioctl.h>
  21.842 +
  21.843 +#define FTYPE_FILE 0
  21.844 +#define FTYPE_CD     1
  21.845 +#define FTYPE_HARDDISK 2
  21.846 +
  21.847 +typedef struct BDRVRawState {
  21.848 +    HANDLE hfile;
  21.849 +    int type;
  21.850 +    char drive_path[16]; /* format: "d:\" */
  21.851 +} BDRVRawState;
  21.852 +
  21.853 +typedef struct RawAIOCB {
  21.854 +    BlockDriverAIOCB common;
  21.855 +    HANDLE hEvent;
  21.856 +    OVERLAPPED ov;
  21.857 +    int count;
  21.858 +} RawAIOCB;
  21.859 +
  21.860 +int qemu_ftruncate64(int fd, int64_t length)
  21.861 +{
  21.862 +    LARGE_INTEGER li;
  21.863 +    LONG high;
  21.864 +    HANDLE h;
  21.865 +    BOOL res;
  21.866 +
  21.867 +    if ((GetVersion() & 0x80000000UL) && (length >> 32) != 0)
  21.868 +	return -1;
  21.869 +
  21.870 +    h = (HANDLE)_get_osfhandle(fd);
  21.871 +
  21.872 +    /* get current position, ftruncate do not change position */
  21.873 +    li.HighPart = 0;
  21.874 +    li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT);
  21.875 +    if (li.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
  21.876 +	return -1;
  21.877 +
  21.878 +    high = length >> 32;
  21.879 +    if (!SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN))
  21.880 +	return -1;
  21.881 +    res = SetEndOfFile(h);
  21.882 +
  21.883 +    /* back to old position */
  21.884 +    SetFilePointer(h, li.LowPart, &li.HighPart, FILE_BEGIN);
  21.885 +    return res ? 0 : -1;
  21.886 +}
  21.887 +
  21.888 +static int set_sparse(int fd)
  21.889 +{
  21.890 +    DWORD returned;
  21.891 +    return (int) DeviceIoControl((HANDLE)_get_osfhandle(fd), FSCTL_SET_SPARSE,
  21.892 +				 NULL, 0, NULL, 0, &returned, NULL);
  21.893 +}
  21.894 +
  21.895 +static int raw_open(BlockDriverState *bs, const char *filename, int flags)
  21.896 +{
  21.897 +    BDRVRawState *s = bs->opaque;
  21.898 +    int access_flags, create_flags;
  21.899 +    DWORD overlapped;
  21.900 +
  21.901 +    s->type = FTYPE_FILE;
  21.902 +
  21.903 +    if ((flags & BDRV_O_ACCESS) == O_RDWR) {
  21.904 +        access_flags = GENERIC_READ | GENERIC_WRITE;
  21.905 +    } else {
  21.906 +        access_flags = GENERIC_READ;
  21.907 +    }
  21.908 +    if (flags & BDRV_O_CREAT) {
  21.909 +        create_flags = CREATE_ALWAYS;
  21.910 +    } else {
  21.911 +        create_flags = OPEN_EXISTING;
  21.912 +    }
  21.913 +#ifdef QEMU_TOOL
  21.914 +    overlapped = FILE_ATTRIBUTE_NORMAL;
  21.915 +#else
  21.916 +    overlapped = FILE_FLAG_OVERLAPPED;
  21.917 +#endif
  21.918 +    s->hfile = CreateFile(filename, access_flags, 
  21.919 +                          FILE_SHARE_READ, NULL,
  21.920 +                          create_flags, overlapped, NULL);
  21.921 +    if (s->hfile == INVALID_HANDLE_VALUE) {
  21.922 +        int err = GetLastError();
  21.923 +
  21.924 +        if (err == ERROR_ACCESS_DENIED)
  21.925 +            return -EACCES;
  21.926 +        return -1;
  21.927 +    }
  21.928 +    return 0;
  21.929 +}
  21.930 +
  21.931 +static int raw_pread(BlockDriverState *bs, int64_t offset, 
  21.932 +                     uint8_t *buf, int count)
  21.933 +{
  21.934 +    BDRVRawState *s = bs->opaque;
  21.935 +    OVERLAPPED ov;
  21.936 +    DWORD ret_count;
  21.937 +    int ret;
  21.938 +    
  21.939 +    memset(&ov, 0, sizeof(ov));
  21.940 +    ov.Offset = offset;
  21.941 +    ov.OffsetHigh = offset >> 32;
  21.942 +    ret = ReadFile(s->hfile, buf, count, &ret_count, &ov);
  21.943 +    if (!ret) {
  21.944 +        ret = GetOverlappedResult(s->hfile, &ov, &ret_count, TRUE);
  21.945 +        if (!ret)
  21.946 +            return -EIO;
  21.947 +        else
  21.948 +            return ret_count;
  21.949 +    }
  21.950 +    return ret_count;
  21.951 +}
  21.952 +
  21.953 +static int raw_pwrite(BlockDriverState *bs, int64_t offset, 
  21.954 +                      const uint8_t *buf, int count)
  21.955 +{
  21.956 +    BDRVRawState *s = bs->opaque;
  21.957 +    OVERLAPPED ov;
  21.958 +    DWORD ret_count;
  21.959 +    int ret;
  21.960 +    
  21.961 +    memset(&ov, 0, sizeof(ov));
  21.962 +    ov.Offset = offset;
  21.963 +    ov.OffsetHigh = offset >> 32;
  21.964 +    ret = WriteFile(s->hfile, buf, count, &ret_count, &ov);
  21.965 +    if (!ret) {
  21.966 +        ret = GetOverlappedResult(s->hfile, &ov, &ret_count, TRUE);
  21.967 +        if (!ret)
  21.968 +            return -EIO;
  21.969 +        else
  21.970 +            return ret_count;
  21.971 +    }
  21.972 +    return ret_count;
  21.973 +}
  21.974 +
  21.975 +#if 0
  21.976 +#ifndef QEMU_TOOL
  21.977 +static void raw_aio_cb(void *opaque)
  21.978 +{
  21.979 +    RawAIOCB *acb = opaque;
  21.980 +    BlockDriverState *bs = acb->common.bs;
  21.981 +    BDRVRawState *s = bs->opaque;
  21.982 +    DWORD ret_count;
  21.983 +    int ret;
  21.984 +
  21.985 +    ret = GetOverlappedResult(s->hfile, &acb->ov, &ret_count, TRUE);
  21.986 +    if (!ret || ret_count != acb->count) {
  21.987 +        acb->common.cb(acb->common.opaque, -EIO);
  21.988 +    } else {
  21.989 +        acb->common.cb(acb->common.opaque, 0);
  21.990 +    }
  21.991 +}
  21.992 +#endif
  21.993 +
  21.994 +static RawAIOCB *raw_aio_setup(BlockDriverState *bs,
  21.995 +        int64_t sector_num, uint8_t *buf, int nb_sectors,
  21.996 +        BlockDriverCompletionFunc *cb, void *opaque)
  21.997 +{
  21.998 +    RawAIOCB *acb;
  21.999 +    int64_t offset;
 21.1000 +
 21.1001 +    acb = qemu_aio_get(bs, cb, opaque);
 21.1002 +    if (acb->hEvent) {
 21.1003 +        acb->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
 21.1004 +        if (!acb->hEvent) {
 21.1005 +            qemu_aio_release(acb);
 21.1006 +            return NULL;
 21.1007 +        }
 21.1008 +    }
 21.1009 +    memset(&acb->ov, 0, sizeof(acb->ov));
 21.1010 +    offset = sector_num * 512;
 21.1011 +    acb->ov.Offset = offset;
 21.1012 +    acb->ov.OffsetHigh = offset >> 32;
 21.1013 +    acb->ov.hEvent = acb->hEvent;
 21.1014 +    acb->count = nb_sectors * 512;
 21.1015 +#ifndef QEMU_TOOL
 21.1016 +    qemu_add_wait_object(acb->ov.hEvent, raw_aio_cb, acb);
 21.1017 +#endif
 21.1018 +    return acb;
 21.1019 +}
 21.1020 +
 21.1021 +static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs,
 21.1022 +        int64_t sector_num, uint8_t *buf, int nb_sectors,
 21.1023 +        BlockDriverCompletionFunc *cb, void *opaque)
 21.1024 +{
 21.1025 +    BDRVRawState *s = bs->opaque;
 21.1026 +    RawAIOCB *acb;
 21.1027 +    int ret;
 21.1028 +
 21.1029 +    acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
 21.1030 +    if (!acb)
 21.1031 +        return NULL;
 21.1032 +    ret = ReadFile(s->hfile, buf, acb->count, NULL, &acb->ov);
 21.1033 +    if (!ret) {
 21.1034 +        qemu_aio_release(acb);
 21.1035 +        return NULL;
 21.1036 +    }
 21.1037 +#ifdef QEMU_TOOL
 21.1038 +    qemu_aio_release(acb);
 21.1039 +#endif
 21.1040 +    return (BlockDriverAIOCB *)acb;
 21.1041 +}
 21.1042 +
 21.1043 +static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs,
 21.1044 +        int64_t sector_num, uint8_t *buf, int nb_sectors,
 21.1045 +        BlockDriverCompletionFunc *cb, void *opaque)
 21.1046 +{
 21.1047 +    BDRVRawState *s = bs->opaque;
 21.1048 +    RawAIOCB *acb;
 21.1049 +    int ret;
 21.1050 +
 21.1051 +    acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
 21.1052 +    if (!acb)
 21.1053 +        return NULL;
 21.1054 +    ret = WriteFile(s->hfile, buf, acb->count, NULL, &acb->ov);
 21.1055 +    if (!ret) {
 21.1056 +        qemu_aio_release(acb);
 21.1057 +        return NULL;
 21.1058 +    }
 21.1059 +#ifdef QEMU_TOOL
 21.1060 +    qemu_aio_release(acb);
 21.1061 +#endif
 21.1062 +    return (BlockDriverAIOCB *)acb;
 21.1063 +}
 21.1064 +
 21.1065 +static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
 21.1066 +{
 21.1067 +#ifndef QEMU_TOOL
 21.1068 +    RawAIOCB *acb = (RawAIOCB *)blockacb;
 21.1069 +    BlockDriverState *bs = acb->common.bs;
 21.1070 +    BDRVRawState *s = bs->opaque;
 21.1071 +
 21.1072 +    qemu_del_wait_object(acb->ov.hEvent, raw_aio_cb, acb);
 21.1073 +    /* XXX: if more than one async I/O it is not correct */
 21.1074 +    CancelIo(s->hfile);
 21.1075 +    qemu_aio_release(acb);
 21.1076 +#endif
 21.1077 +}
 21.1078 +#endif /* #if 0 */
 21.1079 +
 21.1080 +static void raw_flush(BlockDriverState *bs)
 21.1081 +{
 21.1082 +    BDRVRawState *s = bs->opaque;
 21.1083 +    FlushFileBuffers(s->hfile);
 21.1084 +}
 21.1085 +
 21.1086 +static void raw_close(BlockDriverState *bs)
 21.1087 +{
 21.1088 +    BDRVRawState *s = bs->opaque;
 21.1089 +    CloseHandle(s->hfile);
 21.1090 +}
 21.1091 +
 21.1092 +static int raw_truncate(BlockDriverState *bs, int64_t offset)
 21.1093 +{
 21.1094 +    BDRVRawState *s = bs->opaque;
 21.1095 +    DWORD low, high;
 21.1096 +
 21.1097 +    low = offset;
 21.1098 +    high = offset >> 32;
 21.1099 +    if (!SetFilePointer(s->hfile, low, &high, FILE_BEGIN))
 21.1100 +	return -EIO;
 21.1101 +    if (!SetEndOfFile(s->hfile))
 21.1102 +        return -EIO;
 21.1103 +    return 0;
 21.1104 +}
 21.1105 +
 21.1106 +static int64_t raw_getlength(BlockDriverState *bs)
 21.1107 +{
 21.1108 +    BDRVRawState *s = bs->opaque;
 21.1109 +    LARGE_INTEGER l;
 21.1110 +    ULARGE_INTEGER available, total, total_free; 
 21.1111 +    DISK_GEOMETRY dg;
 21.1112 +    DWORD count;
 21.1113 +    BOOL status;
 21.1114 +
 21.1115 +    switch(s->type) {
 21.1116 +    case FTYPE_FILE:
 21.1117 +        l.LowPart = GetFileSize(s->hfile, &l.HighPart);
 21.1118 +        if (l.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
 21.1119 +            return -EIO;
 21.1120 +        break;
 21.1121 +    case FTYPE_CD:
 21.1122 +        if (!GetDiskFreeSpaceEx(s->drive_path, &available, &total, &total_free))
 21.1123 +            return -EIO;
 21.1124 +        l.QuadPart = total.QuadPart;
 21.1125 +        break;
 21.1126 +    case FTYPE_HARDDISK:
 21.1127 +        status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY,
 21.1128 +                                 NULL, 0, &dg, sizeof(dg), &count, NULL);
 21.1129 +        if (status != FALSE) {
 21.1130 +            l.QuadPart = dg.Cylinders.QuadPart * dg.TracksPerCylinder
 21.1131 +                * dg.SectorsPerTrack * dg.BytesPerSector;
 21.1132 +        }
 21.1133 +        break;
 21.1134 +    default:
 21.1135 +        return -EIO;
 21.1136 +    }
 21.1137 +    return l.QuadPart;
 21.1138 +}
 21.1139 +
 21.1140 +static int raw_create(const char *filename, int64_t total_size,
 21.1141 +                      const char *backing_file, int flags)
 21.1142 +{
 21.1143 +    int fd;
 21.1144 +
 21.1145 +    if (flags || backing_file)
 21.1146 +        return -ENOTSUP;
 21.1147 +
 21.1148 +    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 
 21.1149 +              0644);
 21.1150 +    if (fd < 0)
 21.1151 +        return -EIO;
 21.1152 +    set_sparse(fd);
 21.1153 +    ftruncate(fd, total_size * 512);
 21.1154 +    close(fd);
 21.1155 +    return 0;
 21.1156 +}
 21.1157 +
 21.1158 +void qemu_aio_init(void)
 21.1159 +{
 21.1160 +}
 21.1161 +
 21.1162 +void qemu_aio_poll(void)
 21.1163 +{
 21.1164 +}
 21.1165 +
 21.1166 +void qemu_aio_flush(void)
 21.1167 +{
 21.1168 +}
 21.1169 +
 21.1170 +void qemu_aio_wait_start(void)
 21.1171 +{
 21.1172 +}
 21.1173 +
 21.1174 +void qemu_aio_wait(void)
 21.1175 +{
 21.1176 +#ifndef QEMU_TOOL
 21.1177 +    qemu_bh_poll();
 21.1178 +#endif
 21.1179 +}
 21.1180 +
 21.1181 +void qemu_aio_wait_end(void)
 21.1182 +{
 21.1183 +}
 21.1184 +
 21.1185 +BlockDriver bdrv_raw = {
 21.1186 +    "raw",
 21.1187 +    sizeof(BDRVRawState),
 21.1188 +    NULL, /* no probe for protocols */
 21.1189 +    raw_open,
 21.1190 +    NULL,
 21.1191 +    NULL,
 21.1192 +    raw_close,
 21.1193 +    raw_create,
 21.1194 +    raw_flush,
 21.1195 +    
 21.1196 +#if 0
 21.1197 +    .bdrv_aio_read = raw_aio_read,
 21.1198 +    .bdrv_aio_write = raw_aio_write,
 21.1199 +    .bdrv_aio_cancel = raw_aio_cancel,
 21.1200 +    .aiocb_size = sizeof(RawAIOCB);
 21.1201 +#endif
 21.1202 +    .protocol_name = "file",
 21.1203 +    .bdrv_pread = raw_pread,
 21.1204 +    .bdrv_pwrite = raw_pwrite,
 21.1205 +    .bdrv_truncate = raw_truncate,
 21.1206 +    .bdrv_getlength = raw_getlength,
 21.1207 +};
 21.1208 +
 21.1209 +/***********************************************/
 21.1210 +/* host device */
 21.1211 +
 21.1212 +static int find_cdrom(char *cdrom_name, int cdrom_name_size)
 21.1213 +{
 21.1214 +    char drives[256], *pdrv = drives;
 21.1215 +    UINT type;
 21.1216 +
 21.1217 +    memset(drives, 0, sizeof(drives));
 21.1218 +    GetLogicalDriveStrings(sizeof(drives), drives);
 21.1219 +    while(pdrv[0] != '\0') {
 21.1220 +        type = GetDriveType(pdrv);
 21.1221 +        switch(type) {
 21.1222 +        case DRIVE_CDROM:
 21.1223 +            snprintf(cdrom_name, cdrom_name_size, "\\\\.\\%c:", pdrv[0]);
 21.1224 +            return 0;
 21.1225 +            break;
 21.1226 +        }
 21.1227 +        pdrv += lstrlen(pdrv) + 1;
 21.1228 +    }
 21.1229 +    return -1;
 21.1230 +}
 21.1231 +
 21.1232 +static int find_device_type(BlockDriverState *bs, const char *filename)
 21.1233 +{
 21.1234 +    BDRVRawState *s = bs->opaque;
 21.1235 +    UINT type;
 21.1236 +    const char *p;
 21.1237 +
 21.1238 +    if (strstart(filename, "\\\\.\\", &p) ||
 21.1239 +        strstart(filename, "//./", &p)) {
 21.1240 +        if (stristart(p, "PhysicalDrive", NULL))
 21.1241 +            return FTYPE_HARDDISK;
 21.1242 +        snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", p[0]);
 21.1243 +        type = GetDriveType(s->drive_path);
 21.1244 +        if (type == DRIVE_CDROM)
 21.1245 +            return FTYPE_CD;
 21.1246 +        else
 21.1247 +            return FTYPE_FILE;
 21.1248 +    } else {
 21.1249 +        return FTYPE_FILE;
 21.1250 +    }
 21.1251 +}
 21.1252 +
 21.1253 +static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
 21.1254 +{
 21.1255 +    BDRVRawState *s = bs->opaque;
 21.1256 +    int access_flags, create_flags;
 21.1257 +    DWORD overlapped;
 21.1258 +    char device_name[64];
 21.1259 +
 21.1260 +    if (strstart(filename, "/dev/cdrom", NULL)) {
 21.1261 +        if (find_cdrom(device_name, sizeof(device_name)) < 0)
 21.1262 +            return -ENOENT;
 21.1263 +        filename = device_name;
 21.1264 +    } else {
 21.1265 +        /* transform drive letters into device name */
 21.1266 +        if (((filename[0] >= 'a' && filename[0] <= 'z') ||
 21.1267 +             (filename[0] >= 'A' && filename[0] <= 'Z')) &&
 21.1268 +            filename[1] == ':' && filename[2] == '\0') {
 21.1269 +            snprintf(device_name, sizeof(device_name), "\\\\.\\%c:", filename[0]);
 21.1270 +            filename = device_name;
 21.1271 +        }
 21.1272 +    }
 21.1273 +    s->type = find_device_type(bs, filename);
 21.1274 +    
 21.1275 +    if ((flags & BDRV_O_ACCESS) == O_RDWR) {
 21.1276 +        access_flags = GENERIC_READ | GENERIC_WRITE;
 21.1277 +    } else {
 21.1278 +        access_flags = GENERIC_READ;
 21.1279 +    }
 21.1280 +    create_flags = OPEN_EXISTING;
 21.1281 +
 21.1282 +#ifdef QEMU_TOOL
 21.1283 +    overlapped = FILE_ATTRIBUTE_NORMAL;
 21.1284 +#else
 21.1285 +    overlapped = FILE_FLAG_OVERLAPPED;
 21.1286 +#endif
 21.1287 +    s->hfile = CreateFile(filename, access_flags, 
 21.1288 +                          FILE_SHARE_READ, NULL,
 21.1289 +                          create_flags, overlapped, NULL);
 21.1290 +    if (s->hfile == INVALID_HANDLE_VALUE) {
 21.1291 +        int err = GetLastError();
 21.1292 +
 21.1293 +        if (err == ERROR_ACCESS_DENIED)
 21.1294 +            return -EACCES;
 21.1295 +        return -1;
 21.1296 +    }
 21.1297 +    return 0;
 21.1298 +}
 21.1299 +
 21.1300 +#if 0
 21.1301 +/***********************************************/
 21.1302 +/* removable device additionnal commands */
 21.1303 +
 21.1304 +static int raw_is_inserted(BlockDriverState *bs)
 21.1305 +{
 21.1306 +    return 1;
 21.1307 +}
 21.1308 +
 21.1309 +static int raw_media_changed(BlockDriverState *bs)
 21.1310 +{
 21.1311 +    return -ENOTSUP;
 21.1312 +}
 21.1313 +
 21.1314 +static int raw_eject(BlockDriverState *bs, int eject_flag)
 21.1315 +{
 21.1316 +    DWORD ret_count;
 21.1317 +
 21.1318 +    if (s->type == FTYPE_FILE)
 21.1319 +        return -ENOTSUP;
 21.1320 +    if (eject_flag) {
 21.1321 +        DeviceIoControl(s->hfile, IOCTL_STORAGE_EJECT_MEDIA, 
 21.1322 +                        NULL, 0, NULL, 0, &lpBytesReturned, NULL);
 21.1323 +    } else {
 21.1324 +        DeviceIoControl(s->hfile, IOCTL_STORAGE_LOAD_MEDIA, 
 21.1325 +                        NULL, 0, NULL, 0, &lpBytesReturned, NULL);
 21.1326 +    }
 21.1327 +}
 21.1328 +
 21.1329 +static int raw_set_locked(BlockDriverState *bs, int locked)
 21.1330 +{
 21.1331 +    return -ENOTSUP;
 21.1332 +}
 21.1333 +#endif
 21.1334 +
 21.1335 +BlockDriver bdrv_host_device = {
 21.1336 +    "host_device",
 21.1337 +    sizeof(BDRVRawState),
 21.1338 +    NULL, /* no probe for protocols */
 21.1339 +    hdev_open,
 21.1340 +    NULL,
 21.1341 +    NULL,
 21.1342 +    raw_close,
 21.1343 +    NULL,
 21.1344 +    raw_flush,
 21.1345 +    
 21.1346 +#if 0
 21.1347 +    .bdrv_aio_read = raw_aio_read,
 21.1348 +    .bdrv_aio_write = raw_aio_write,
 21.1349 +    .bdrv_aio_cancel = raw_aio_cancel,
 21.1350 +    .aiocb_size = sizeof(RawAIOCB);
 21.1351 +#endif
 21.1352 +    .bdrv_pread = raw_pread,
 21.1353 +    .bdrv_pwrite = raw_pwrite,
 21.1354 +    .bdrv_getlength = raw_getlength,
 21.1355 +};
 21.1356 +#endif /* _WIN32 */
    22.1 --- a/tools/ioemu/block-vmdk.c	Tue May 08 10:38:06 2007 +0100
    22.2 +++ b/tools/ioemu/block-vmdk.c	Wed May 09 14:17:15 2007 +0100
    22.3 @@ -22,6 +22,7 @@
    22.4   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    22.5   * THE SOFTWARE.
    22.6   */
    22.7 +
    22.8  #include "vl.h"
    22.9  #include "block_int.h"
   22.10  
   22.11 @@ -59,7 +60,7 @@ typedef struct {
   22.12  #define L2_CACHE_SIZE 16
   22.13  
   22.14  typedef struct BDRVVmdkState {
   22.15 -    int fd;
   22.16 +    BlockDriverState *hd;
   22.17      int64_t l1_table_offset;
   22.18      int64_t l1_backup_table_offset;
   22.19      uint32_t *l1_table;
   22.20 @@ -73,6 +74,7 @@ typedef struct BDRVVmdkState {
   22.21      uint32_t l2_cache_counts[L2_CACHE_SIZE];
   22.22  
   22.23      unsigned int cluster_sectors;
   22.24 +    uint32_t parent_cid;
   22.25  } BDRVVmdkState;
   22.26  
   22.27  static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
   22.28 @@ -89,27 +91,278 @@ static int vmdk_probe(const uint8_t *buf
   22.29          return 0;
   22.30  }
   22.31  
   22.32 -static int vmdk_open(BlockDriverState *bs, const char *filename)
   22.33 +#define CHECK_CID 1
   22.34 +
   22.35 +#define SECTOR_SIZE 512				
   22.36 +#define DESC_SIZE 20*SECTOR_SIZE	// 20 sectors of 512 bytes each
   22.37 +#define HEADER_SIZE 512   			// first sector of 512 bytes 
   22.38 +
   22.39 +static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
   22.40 +{
   22.41 +    BDRVVmdkState *s = bs->opaque;
   22.42 +    char desc[DESC_SIZE];
   22.43 +    uint32_t cid;
   22.44 +    char *p_name, *cid_str; 
   22.45 +    size_t cid_str_size;
   22.46 +
   22.47 +    /* the descriptor offset = 0x200 */
   22.48 +    if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
   22.49 +        return 0;
   22.50 +
   22.51 +    if (parent) {
   22.52 +        cid_str = "parentCID";
   22.53 +        cid_str_size = sizeof("parentCID");
   22.54 +    } else {
   22.55 +        cid_str = "CID";
   22.56 +        cid_str_size = sizeof("CID");
   22.57 +    }
   22.58 +
   22.59 +    if ((p_name = strstr(desc,cid_str)) != 0) {
   22.60 +        p_name += cid_str_size;
   22.61 +        sscanf(p_name,"%x",&cid);
   22.62 +    }
   22.63 +
   22.64 +    return cid;
   22.65 +}
   22.66 +
   22.67 +static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
   22.68  {
   22.69      BDRVVmdkState *s = bs->opaque;
   22.70 -    int fd, i;
   22.71 -    uint32_t magic;
   22.72 -    int l1_size;
   22.73 +    char desc[DESC_SIZE], tmp_desc[DESC_SIZE];
   22.74 +    char *p_name, *tmp_str;
   22.75 +
   22.76 +    /* the descriptor offset = 0x200 */
   22.77 +    if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
   22.78 +        return -1;
   22.79 +
   22.80 +    tmp_str = strstr(desc,"parentCID");
   22.81 +    strcpy(tmp_desc, tmp_str);
   22.82 +    if ((p_name = strstr(desc,"CID")) != 0) {
   22.83 +        p_name += sizeof("CID");
   22.84 +        sprintf(p_name,"%x\n",cid);
   22.85 +        strcat(desc,tmp_desc);
   22.86 +    }
   22.87 +
   22.88 +    if (bdrv_pwrite(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
   22.89 +        return -1;
   22.90 +    return 0;
   22.91 +}
   22.92 +
   22.93 +static int vmdk_is_cid_valid(BlockDriverState *bs)
   22.94 +{
   22.95 +#ifdef CHECK_CID
   22.96 +    BDRVVmdkState *s = bs->opaque;
   22.97 +    BlockDriverState *p_bs = s->hd->backing_hd;
   22.98 +    uint32_t cur_pcid;
   22.99 +
  22.100 +    if (p_bs) {
  22.101 +        cur_pcid = vmdk_read_cid(p_bs,0);
  22.102 +        if (s->parent_cid != cur_pcid)
  22.103 +            // CID not valid
  22.104 +            return 0;
  22.105 +    }
  22.106 +#endif
  22.107 +    // CID valid
  22.108 +    return 1;
  22.109 +}
  22.110 +
  22.111 +static int vmdk_snapshot_create(const char *filename, const char *backing_file)
  22.112 +{
  22.113 +    int snp_fd, p_fd;
  22.114 +    uint32_t p_cid;
  22.115 +    char *p_name, *gd_buf, *rgd_buf; 
  22.116 +    const char *real_filename, *temp_str;
  22.117 +    VMDK4Header header;
  22.118 +    uint32_t gde_entries, gd_size;
  22.119 +    int64_t gd_offset, rgd_offset, capacity, gt_size;
  22.120 +    char p_desc[DESC_SIZE], s_desc[DESC_SIZE], hdr[HEADER_SIZE];
  22.121 +    char *desc_template =
  22.122 +    "# Disk DescriptorFile\n"
  22.123 +    "version=1\n"
  22.124 +    "CID=%x\n"
  22.125 +    "parentCID=%x\n"
  22.126 +    "createType=\"monolithicSparse\"\n"
  22.127 +    "parentFileNameHint=\"%s\"\n"
  22.128 +    "\n"
  22.129 +    "# Extent description\n"
  22.130 +    "RW %lu SPARSE \"%s\"\n"
  22.131 +    "\n"
  22.132 +    "# The Disk Data Base \n"
  22.133 +    "#DDB\n"
  22.134 +    "\n";
  22.135 +
  22.136 +    snp_fd = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 0644);
  22.137 +    if (snp_fd < 0)
  22.138 +        return -1;
  22.139 +    p_fd = open(backing_file, O_RDONLY | O_BINARY | O_LARGEFILE);
  22.140 +    if (p_fd < 0) {
  22.141 +        close(snp_fd);
  22.142 +        return -1;
  22.143 +    }
  22.144 +
  22.145 +    /* read the header */
  22.146 +    if (lseek(p_fd, 0x0, SEEK_SET) == -1)
  22.147 +        goto fail;
  22.148 +    if (read(p_fd, hdr, HEADER_SIZE) != HEADER_SIZE)
  22.149 +        goto fail;
  22.150 +
  22.151 +    /* write the header */
  22.152 +    if (lseek(snp_fd, 0x0, SEEK_SET) == -1)
  22.153 +        goto fail;
  22.154 +    if (write(snp_fd, hdr, HEADER_SIZE) == -1)
  22.155 +        goto fail;
  22.156 +
  22.157 +    memset(&header, 0, sizeof(header));
  22.158 +    memcpy(&header,&hdr[4], sizeof(header)); // skip the VMDK4_MAGIC
  22.159 +
  22.160 +    ftruncate(snp_fd, header.grain_offset << 9);
  22.161 +    /* the descriptor offset = 0x200 */
  22.162 +    if (lseek(p_fd, 0x200, SEEK_SET) == -1)
  22.163 +        goto fail;
  22.164 +    if (read(p_fd, p_desc, DESC_SIZE) != DESC_SIZE)
  22.165 +        goto fail;
  22.166 +
  22.167 +    if ((p_name = strstr(p_desc,"CID")) != 0) {
  22.168 +        p_name += sizeof("CID");
  22.169 +        sscanf(p_name,"%x",&p_cid);
  22.170 +    }
  22.171 +
  22.172 +    real_filename = filename;
  22.173 +    if ((temp_str = strrchr(real_filename, '\\')) != NULL)
  22.174 +        real_filename = temp_str + 1;
  22.175 +    if ((temp_str = strrchr(real_filename, '/')) != NULL)
  22.176 +        real_filename = temp_str + 1;
  22.177 +    if ((temp_str = strrchr(real_filename, ':')) != NULL)
  22.178 +        real_filename = temp_str + 1;
  22.179 +
  22.180 +    sprintf(s_desc, desc_template, p_cid, p_cid, backing_file
  22.181 +            , (uint32_t)header.capacity, real_filename);
  22.182  
  22.183 -    fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
  22.184 -    if (fd < 0) {
  22.185 -        fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
  22.186 -        if (fd < 0)
  22.187 +    /* write the descriptor */
  22.188 +    if (lseek(snp_fd, 0x200, SEEK_SET) == -1)
  22.189 +        goto fail;
  22.190 +    if (write(snp_fd, s_desc, strlen(s_desc)) == -1)
  22.191 +        goto fail;
  22.192 +
  22.193 +    gd_offset = header.gd_offset * SECTOR_SIZE;     // offset of GD table
  22.194 +    rgd_offset = header.rgd_offset * SECTOR_SIZE;   // offset of RGD table
  22.195 +    capacity = header.capacity * SECTOR_SIZE;       // Extent size
  22.196 +    /*
  22.197 +     * Each GDE span 32M disk, means:
  22.198 +     * 512 GTE per GT, each GTE points to grain
  22.199 +     */
  22.200 +    gt_size = (int64_t)header.num_gtes_per_gte * header.granularity * SECTOR_SIZE;
  22.201 +    if (!gt_size)
  22.202 +        goto fail;
  22.203 +    gde_entries = (uint32_t)(capacity / gt_size);  // number of gde/rgde 
  22.204 +    gd_size = gde_entries * sizeof(uint32_t);
  22.205 +
  22.206 +    /* write RGD */
  22.207 +    rgd_buf = qemu_malloc(gd_size);
  22.208 +    if (!rgd_buf)
  22.209 +        goto fail;
  22.210 +    if (lseek(p_fd, rgd_offset, SEEK_SET) == -1)
  22.211 +        goto fail_rgd;
  22.212 +    if (read(p_fd, rgd_buf, gd_size) != gd_size)
  22.213 +        goto fail_rgd;
  22.214 +    if (lseek(snp_fd, rgd_offset, SEEK_SET) == -1)
  22.215 +        goto fail_rgd;
  22.216 +    if (write(snp_fd, rgd_buf, gd_size) == -1)
  22.217 +        goto fail_rgd;
  22.218 +    qemu_free(rgd_buf);
  22.219 +
  22.220 +    /* write GD */
  22.221 +    gd_buf = qemu_malloc(gd_size);
  22.222 +    if (!gd_buf)
  22.223 +        goto fail_rgd;
  22.224 +    if (lseek(p_fd, gd_offset, SEEK_SET) == -1)
  22.225 +        goto fail_gd;
  22.226 +    if (read(p_fd, gd_buf, gd_size) != gd_size)
  22.227 +        goto fail_gd;
  22.228 +    if (lseek(snp_fd, gd_offset, SEEK_SET) == -1)
  22.229 +        goto fail_gd;
  22.230 +    if (write(snp_fd, gd_buf, gd_size) == -1)
  22.231 +        goto fail_gd;
  22.232 +    qemu_free(gd_buf);
  22.233 +
  22.234 +    close(p_fd);
  22.235 +    close(snp_fd);
  22.236 +    return 0;
  22.237 +
  22.238 +    fail_gd:
  22.239 +    qemu_free(gd_buf);
  22.240 +    fail_rgd:   
  22.241 +    qemu_free(rgd_buf);
  22.242 +    fail:
  22.243 +    close(p_fd);
  22.244 +    close(snp_fd);
  22.245 +    return -1;
  22.246 +}
  22.247 +
  22.248 +static void vmdk_parent_close(BlockDriverState *bs)
  22.249 +{
  22.250 +    if (bs->backing_hd)
  22.251 +        bdrv_close(bs->backing_hd);
  22.252 +}
  22.253 +
  22.254 +
  22.255 +static int vmdk_parent_open(BlockDriverState *bs, const char * filename)
  22.256 +{
  22.257 +    BDRVVmdkState *s = bs->opaque;
  22.258 +    char *p_name; 
  22.259 +    char desc[DESC_SIZE];
  22.260 +    char parent_img_name[1024];
  22.261 +
  22.262 +    /* the descriptor offset = 0x200 */
  22.263 +    if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
  22.264 +        return -1;
  22.265 +
  22.266 +    if ((p_name = strstr(desc,"parentFileNameHint")) != 0) {
  22.267 +        char *end_name;
  22.268 +        struct stat file_buf;
  22.269 +
  22.270 +        p_name += sizeof("parentFileNameHint") + 1;
  22.271 +        if ((end_name = strchr(p_name,'\"')) == 0)
  22.272              return -1;
  22.273 -        bs->read_only = 1;
  22.274 +                
  22.275 +        strncpy(s->hd->backing_file, p_name, end_name - p_name);
  22.276 +        if (stat(s->hd->backing_file, &file_buf) != 0) {
  22.277 +            path_combine(parent_img_name, sizeof(parent_img_name),
  22.278 +                         filename, s->hd->backing_file);
  22.279 +        } else {
  22.280 +            strcpy(parent_img_name, s->hd->backing_file);
  22.281 +        }
  22.282 +
  22.283 +        s->hd->backing_hd = bdrv_new("");
  22.284 +        if (!s->hd->backing_hd) {
  22.285 +            failure:
  22.286 +            bdrv_close(s->hd);
  22.287 +            return -1;
  22.288 +        }
  22.289 +        if (bdrv_open(s->hd->backing_hd, parent_img_name, 0) < 0)
  22.290 +            goto failure;
  22.291      }
  22.292 -    if (read(fd, &magic, sizeof(magic)) != sizeof(magic))
  22.293 +
  22.294 +    return 0;
  22.295 +}
  22.296 +
  22.297 +static int vmdk_open(BlockDriverState *bs, const char *filename, int flags)
  22.298 +{
  22.299 +    BDRVVmdkState *s = bs->opaque;
  22.300 +    uint32_t magic;
  22.301 +    int l1_size, i, ret;
  22.302 +
  22.303 +    ret = bdrv_file_open(&s->hd, filename, flags);
  22.304 +    if (ret < 0)
  22.305 +        return ret;
  22.306 +    if (bdrv_pread(s->hd, 0, &magic, sizeof(magic)) != sizeof(magic))
  22.307          goto fail;
  22.308 +
  22.309      magic = be32_to_cpu(magic);
  22.310      if (magic == VMDK3_MAGIC) {
  22.311          VMDK3Header header;
  22.312 -        if (read(fd, &header, sizeof(header)) != 
  22.313 -            sizeof(header))
  22.314 +
  22.315 +        if (bdrv_pread(s->hd, sizeof(magic), &header, sizeof(header)) != sizeof(header))
  22.316              goto fail;
  22.317          s->cluster_sectors = le32_to_cpu(header.granularity);
  22.318          s->l2_size = 1 << 9;
  22.319 @@ -120,8 +373,8 @@ static int vmdk_open(BlockDriverState *b
  22.320          s->l1_entry_sectors = s->l2_size * s->cluster_sectors;
  22.321      } else if (magic == VMDK4_MAGIC) {
  22.322          VMDK4Header header;
  22.323 -        
  22.324 -        if (read(fd, &header, sizeof(header)) != sizeof(header))
  22.325 +
  22.326 +        if (bdrv_pread(s->hd, sizeof(magic), &header, sizeof(header)) != sizeof(header))
  22.327              goto fail;
  22.328          bs->total_sectors = le64_to_cpu(header.capacity);
  22.329          s->cluster_sectors = le64_to_cpu(header.granularity);
  22.330 @@ -133,17 +386,22 @@ static int vmdk_open(BlockDriverState *b
  22.331              / s->l1_entry_sectors;
  22.332          s->l1_table_offset = le64_to_cpu(header.rgd_offset) << 9;
  22.333          s->l1_backup_table_offset = le64_to_cpu(header.gd_offset) << 9;
  22.334 +
  22.335 +        // try to open parent images, if exist
  22.336 +        if (vmdk_parent_open(bs, filename) != 0)
  22.337 +            goto fail;
  22.338 +        // write the CID once after the image creation
  22.339 +        s->parent_cid = vmdk_read_cid(bs,1);
  22.340      } else {
  22.341          goto fail;
  22.342      }
  22.343 +
  22.344      /* read the L1 table */
  22.345      l1_size = s->l1_size * sizeof(uint32_t);
  22.346      s->l1_table = qemu_malloc(l1_size);
  22.347      if (!s->l1_table)
  22.348          goto fail;
  22.349 -    if (lseek(fd, s->l1_table_offset, SEEK_SET) == -1)
  22.350 -        goto fail;
  22.351 -    if (read(fd, s->l1_table, l1_size) != l1_size)
  22.352 +    if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, l1_size) != l1_size)
  22.353          goto fail;
  22.354      for(i = 0; i < s->l1_size; i++) {
  22.355          le32_to_cpus(&s->l1_table[i]);
  22.356 @@ -153,9 +411,7 @@ static int vmdk_open(BlockDriverState *b
  22.357          s->l1_backup_table = qemu_malloc(l1_size);
  22.358          if (!s->l1_backup_table)
  22.359              goto fail;
  22.360 -        if (lseek(fd, s->l1_backup_table_offset, SEEK_SET) == -1)
  22.361 -            goto fail;
  22.362 -        if (read(fd, s->l1_backup_table, l1_size) != l1_size)
  22.363 +        if (bdrv_pread(s->hd, s->l1_backup_table_offset, s->l1_backup_table, l1_size) != l1_size)
  22.364              goto fail;
  22.365          for(i = 0; i < s->l1_size; i++) {
  22.366              le32_to_cpus(&s->l1_backup_table[i]);
  22.367 @@ -165,16 +421,43 @@ static int vmdk_open(BlockDriverState *b
  22.368      s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint32_t));
  22.369      if (!s->l2_cache)
  22.370          goto fail;
  22.371 -    s->fd = fd;
  22.372      return 0;
  22.373   fail:
  22.374      qemu_free(s->l1_backup_table);
  22.375      qemu_free(s->l1_table);
  22.376      qemu_free(s->l2_cache);
  22.377 -    close(fd);
  22.378 +    bdrv_delete(s->hd);
  22.379      return -1;
  22.380  }
  22.381  
  22.382 +static uint64_t get_cluster_offset(BlockDriverState *bs, uint64_t offset, int allocate);
  22.383 +
  22.384 +static int get_whole_cluster(BlockDriverState *bs, uint64_t cluster_offset,
  22.385 +                             uint64_t offset, int allocate)
  22.386 +{
  22.387 +    uint64_t parent_cluster_offset;
  22.388 +    BDRVVmdkState *s = bs->opaque;
  22.389 +    uint8_t  whole_grain[s->cluster_sectors*512];        // 128 sectors * 512 bytes each = grain size 64KB
  22.390 +
  22.391 +    // we will be here if it's first write on non-exist grain(cluster).
  22.392 +    // try to read from parent image, if exist
  22.393 +    if (s->hd->backing_hd) {
  22.394 +        BDRVVmdkState *ps = s->hd->backing_hd->opaque;
  22.395 +
  22.396 +        if (!vmdk_is_cid_valid(bs))
  22.397 +            return -1;
  22.398 +        parent_cluster_offset = get_cluster_offset(s->hd->backing_hd, offset, allocate);
  22.399 +        if (bdrv_pread(ps->hd, parent_cluster_offset, whole_grain, ps->cluster_sectors*512) != 
  22.400 +                                                                            ps->cluster_sectors*512)
  22.401 +            return -1;
  22.402 +
  22.403 +        if (bdrv_pwrite(s->hd, cluster_offset << 9, whole_grain, sizeof(whole_grain)) != 
  22.404 +                                                                            sizeof(whole_grain))
  22.405 +            return -1;
  22.406 +    }
  22.407 +    return 0;
  22.408 +}
  22.409 +
  22.410  static uint64_t get_cluster_offset(BlockDriverState *bs,
  22.411                                     uint64_t offset, int allocate)
  22.412  {
  22.413 @@ -212,34 +495,41 @@ static uint64_t get_cluster_offset(Block
  22.414          }
  22.415      }
  22.416      l2_table = s->l2_cache + (min_index * s->l2_size);
  22.417 -    lseek(s->fd, (int64_t)l2_offset * 512, SEEK_SET);
  22.418 -    if (read(s->fd, l2_table, s->l2_size * sizeof(uint32_t)) != 
  22.419 -        s->l2_size * sizeof(uint32_t))
  22.420 +    if (bdrv_pread(s->hd, (int64_t)l2_offset * 512, l2_table, s->l2_size * sizeof(uint32_t)) != 
  22.421 +                                                                        s->l2_size * sizeof(uint32_t))
  22.422          return 0;
  22.423 +
  22.424      s->l2_cache_offsets[min_index] = l2_offset;
  22.425      s->l2_cache_counts[min_index] = 1;
  22.426   found:
  22.427      l2_index = ((offset >> 9) / s->cluster_sectors) % s->l2_size;
  22.428      cluster_offset = le32_to_cpu(l2_table[l2_index]);
  22.429      if (!cluster_offset) {
  22.430 +        struct stat file_buf;
  22.431 +
  22.432          if (!allocate)
  22.433              return 0;
  22.434 -        cluster_offset = lseek(s->fd, 0, SEEK_END);
  22.435 -        ftruncate(s->fd, cluster_offset + (s->cluster_sectors << 9));
  22.436 +        stat(s->hd->filename, &file_buf);
  22.437 +        cluster_offset = file_buf.st_size;
  22.438 +        bdrv_truncate(s->hd, cluster_offset + (s->cluster_sectors << 9));
  22.439 +
  22.440          cluster_offset >>= 9;
  22.441          /* update L2 table */
  22.442          tmp = cpu_to_le32(cluster_offset);
  22.443          l2_table[l2_index] = tmp;
  22.444 -        lseek(s->fd, ((int64_t)l2_offset * 512) + (l2_index * sizeof(tmp)), SEEK_SET);
  22.445 -        if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
  22.446 +        if (bdrv_pwrite(s->hd, ((int64_t)l2_offset * 512) + (l2_index * sizeof(tmp)), 
  22.447 +                        &tmp, sizeof(tmp)) != sizeof(tmp))
  22.448              return 0;
  22.449          /* update backup L2 table */
  22.450          if (s->l1_backup_table_offset != 0) {
  22.451              l2_offset = s->l1_backup_table[l1_index];
  22.452 -            lseek(s->fd, ((int64_t)l2_offset * 512) + (l2_index * sizeof(tmp)), SEEK_SET);
  22.453 -            if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
  22.454 +            if (bdrv_pwrite(s->hd, ((int64_t)l2_offset * 512) + (l2_index * sizeof(tmp)), 
  22.455 +                            &tmp, sizeof(tmp)) != sizeof(tmp))
  22.456                  return 0;
  22.457          }
  22.458 +
  22.459 +        if (get_whole_cluster(bs, cluster_offset, offset, allocate) == -1)
  22.460 +            return 0;
  22.461      }
  22.462      cluster_offset <<= 9;
  22.463      return cluster_offset;
  22.464 @@ -265,9 +555,9 @@ static int vmdk_read(BlockDriverState *b
  22.465                      uint8_t *buf, int nb_sectors)
  22.466  {
  22.467      BDRVVmdkState *s = bs->opaque;
  22.468 -    int ret, index_in_cluster, n;
  22.469 +    int index_in_cluster, n, ret;
  22.470      uint64_t cluster_offset;
  22.471 -    
  22.472 +
  22.473      while (nb_sectors > 0) {
  22.474          cluster_offset = get_cluster_offset(bs, sector_num << 9, 0);
  22.475          index_in_cluster = sector_num % s->cluster_sectors;
  22.476 @@ -275,11 +565,18 @@ static int vmdk_read(BlockDriverState *b
  22.477          if (n > nb_sectors)
  22.478              n = nb_sectors;
  22.479          if (!cluster_offset) {
  22.480 -            memset(buf, 0, 512 * n);
  22.481 +            // try to read from parent image, if exist
  22.482 +            if (s->hd->backing_hd) {
  22.483 +                if (!vmdk_is_cid_valid(bs))
  22.484 +                    return -1;
  22.485 +                ret = bdrv_read(s->hd->backing_hd, sector_num, buf, n);
  22.486 +                if (ret < 0)
  22.487 +                    return -1;
  22.488 +            } else {
  22.489 +                memset(buf, 0, 512 * n);
  22.490 +            }
  22.491          } else {
  22.492 -            lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
  22.493 -            ret = read(s->fd, buf, n * 512);
  22.494 -            if (ret != n * 512) 
  22.495 +            if(bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512)
  22.496                  return -1;
  22.497          }
  22.498          nb_sectors -= n;
  22.499 @@ -293,8 +590,9 @@ static int vmdk_write(BlockDriverState *
  22.500                       const uint8_t *buf, int nb_sectors)
  22.501  {
  22.502      BDRVVmdkState *s = bs->opaque;
  22.503 -    int ret, index_in_cluster, n;
  22.504 +    int index_in_cluster, n;
  22.505      uint64_t cluster_offset;
  22.506 +    static int cid_update = 0;
  22.507  
  22.508      while (nb_sectors > 0) {
  22.509          index_in_cluster = sector_num & (s->cluster_sectors - 1);
  22.510 @@ -304,13 +602,17 @@ static int vmdk_write(BlockDriverState *
  22.511          cluster_offset = get_cluster_offset(bs, sector_num << 9, 1);
  22.512          if (!cluster_offset)
  22.513              return -1;
  22.514 -        lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
  22.515 -        ret = write(s->fd, buf, n * 512);
  22.516 -        if (ret != n * 512)
  22.517 +        if (bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512)
  22.518              return -1;
  22.519          nb_sectors -= n;
  22.520          sector_num += n;
  22.521          buf += n * 512;
  22.522 +
  22.523 +        // update CID on the first write every time the virtual disk is opened
  22.524 +        if (!cid_update) {
  22.525 +            vmdk_write_cid(bs, time(NULL));
  22.526 +            cid_update++;
  22.527 +        }
  22.528      }
  22.529      return 0;
  22.530  }
  22.531 @@ -334,7 +636,7 @@ static int vmdk_create(const char *filen
  22.532          "# The Disk Data Base \n"
  22.533          "#DDB\n"
  22.534          "\n"
  22.535 -        "ddb.virtualHWVersion = \"3\"\n"
  22.536 +        "ddb.virtualHWVersion = \"4\"\n"
  22.537          "ddb.geometry.cylinders = \"%lu\"\n"
  22.538          "ddb.geometry.heads = \"16\"\n"
  22.539          "ddb.geometry.sectors = \"63\"\n"
  22.540 @@ -343,6 +645,9 @@ static int vmdk_create(const char *filen
  22.541      const char *real_filename, *temp_str;
  22.542  
  22.543      /* XXX: add support for backing file */
  22.544 +    if (backing_file) {
  22.545 +        return vmdk_snapshot_create(filename, backing_file);
  22.546 +    }
  22.547  
  22.548      fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
  22.549                0644);
  22.550 @@ -421,15 +726,18 @@ static int vmdk_create(const char *filen
  22.551  static void vmdk_close(BlockDriverState *bs)
  22.552  {
  22.553      BDRVVmdkState *s = bs->opaque;
  22.554 +
  22.555      qemu_free(s->l1_table);
  22.556      qemu_free(s->l2_cache);
  22.557 -    close(s->fd);
  22.558 +    bdrv_delete(s->hd);
  22.559 +    // try to close parent image, if exist
  22.560 +    vmdk_parent_close(s->hd);
  22.561  }
  22.562  
  22.563  static void vmdk_flush(BlockDriverState *bs)
  22.564  {
  22.565      BDRVVmdkState *s = bs->opaque;
  22.566 -    fsync(s->fd);
  22.567 +    bdrv_flush(s->hd);
  22.568  }
  22.569  
  22.570  BlockDriver bdrv_vmdk = {
    23.1 --- a/tools/ioemu/block-vpc.c	Tue May 08 10:38:06 2007 +0100
    23.2 +++ b/tools/ioemu/block-vpc.c	Wed May 09 14:17:15 2007 +0100
    23.3 @@ -86,19 +86,16 @@ static int vpc_probe(const uint8_t *buf,
    23.4      return 0;
    23.5  }
    23.6  
    23.7 -static int vpc_open(BlockDriverState *bs, const char *filename)
    23.8 +static int vpc_open(BlockDriverState *bs, const char *filename, int flags)
    23.9  {
   23.10      BDRVVPCState *s = bs->opaque;
   23.11      int fd, i;
   23.12      struct vpc_subheader header;
   23.13  
   23.14 -    fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
   23.15 -    if (fd < 0) {
   23.16 -        fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
   23.17 -        if (fd < 0)
   23.18 -            return -1;
   23.19 -    }
   23.20 -    
   23.21 +    fd = open(filename, O_RDONLY | O_BINARY);
   23.22 +    if (fd < 0)
   23.23 +        return -1;
   23.24 +
   23.25      bs->read_only = 1; // no write support yet
   23.26      
   23.27      s->fd = fd;
    24.1 --- a/tools/ioemu/block-vvfat.c	Tue May 08 10:38:06 2007 +0100
    24.2 +++ b/tools/ioemu/block-vvfat.c	Wed May 09 14:17:15 2007 +0100
    24.3 @@ -61,7 +61,7 @@ void nonono(const char* file, int line, 
    24.4      exit(-5);
    24.5  }
    24.6  #undef assert
    24.7 -#define assert(a) if (!(a)) nonono(__FILE__, __LINE__, #a)
    24.8 +#define assert(a) do {if (!(a)) nonono(__FILE__, __LINE__, #a);}while(0)
    24.9  #endif
   24.10  
   24.11  #else
   24.12 @@ -351,13 +351,6 @@ typedef struct BDRVVVFATState {
   24.13  } BDRVVVFATState;
   24.14  
   24.15  
   24.16 -static int vvfat_probe(const uint8_t *buf, int buf_size, const char *filename)
   24.17 -{
   24.18 -    if (strstart(filename, "fat:", NULL))
   24.19 -	return 100;
   24.20 -    return 0;
   24.21 -}
   24.22 -
   24.23  static void init_mbr(BDRVVVFATState* s)
   24.24  {
   24.25      /* TODO: if the files mbr.img and bootsect.img exist, use them */
   24.26 @@ -954,18 +947,22 @@ static int init_directories(BDRVVVFATSta
   24.27      return 0;
   24.28  }
   24.29  
   24.30 +#ifdef DEBUG
   24.31  static BDRVVVFATState *vvv = NULL;
   24.32 +#endif
   24.33  
   24.34  static int enable_write_target(BDRVVVFATState *s);
   24.35  static int is_consistent(BDRVVVFATState *s);
   24.36  
   24.37 -static int vvfat_open(BlockDriverState *bs, const char* dirname)
   24.38 +static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags)
   24.39  {
   24.40      BDRVVVFATState *s = bs->opaque;
   24.41      int floppy = 0;
   24.42      int i;
   24.43  
   24.44 +#ifdef DEBUG
   24.45      vvv = s;
   24.46 +#endif
   24.47  
   24.48  DLOG(if (stderr == NULL) {
   24.49      stderr = fopen("vvfat.log", "a");
   24.50 @@ -1040,7 +1037,6 @@ DLOG(if (stderr == NULL) {
   24.51  	bs->heads = bs->cyls = bs->secs = 0;
   24.52  
   24.53      //    assert(is_consistent(s));
   24.54 -
   24.55      return 0;
   24.56  }
   24.57  
   24.58 @@ -2178,7 +2174,7 @@ static int commit_one_file(BDRVVVFATStat
   24.59      for (i = s->cluster_size; i < offset; i += s->cluster_size)
   24.60  	c = modified_fat_get(s, c);
   24.61  
   24.62 -    fd = open(mapping->path, O_RDWR | O_CREAT, 0666);
   24.63 +    fd = open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
   24.64      if (fd < 0) {
   24.65  	fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
   24.66  		strerror(errno), errno);
   24.67 @@ -2732,8 +2728,7 @@ static int enable_write_target(BDRVVVFAT
   24.68      array_init(&(s->commits), sizeof(commit_t));
   24.69  
   24.70      s->qcow_filename = malloc(1024);
   24.71 -    strcpy(s->qcow_filename, "/tmp/vl.XXXXXX");
   24.72 -    get_tmp_filename(s->qcow_filename, strlen(s->qcow_filename) + 1);
   24.73 +    get_tmp_filename(s->qcow_filename, 1024);
   24.74      if (bdrv_create(&bdrv_qcow,
   24.75  		s->qcow_filename, s->sector_count, "fat:", 0) < 0)
   24.76  	return -1;
   24.77 @@ -2767,14 +2762,15 @@ static void vvfat_close(BlockDriverState
   24.78  BlockDriver bdrv_vvfat = {
   24.79      "vvfat",
   24.80      sizeof(BDRVVVFATState),
   24.81 -    vvfat_probe,
   24.82 +    NULL, /* no probe for protocols */
   24.83      vvfat_open,
   24.84      vvfat_read,
   24.85      vvfat_write,
   24.86      vvfat_close,
   24.87      NULL, /* ??? Not sure if we can do any meaningful flushing.  */
   24.88      NULL,
   24.89 -    vvfat_is_allocated
   24.90 +    vvfat_is_allocated,
   24.91 +    .protocol_name = "fat",
   24.92  };
   24.93  
   24.94  #ifdef DEBUG
    25.1 --- a/tools/ioemu/block.c	Tue May 08 10:38:06 2007 +0100
    25.2 +++ b/tools/ioemu/block.c	Wed May 09 14:17:15 2007 +0100
    25.3 @@ -32,85 +32,108 @@
    25.4  #include <sys/disk.h>
    25.5  #endif
    25.6  
    25.7 -#ifdef CONFIG_COCOA
    25.8 -#include <paths.h>
    25.9 -#include <sys/param.h>
   25.10 -#include <IOKit/IOKitLib.h>
   25.11 -#include <IOKit/IOBSD.h>
   25.12 -#include <IOKit/storage/IOMediaBSDClient.h>
   25.13 -#include <IOKit/storage/IOMedia.h>
   25.14 -#include <IOKit/storage/IOCDMedia.h>
   25.15 -//#include <IOKit/storage/IOCDTypes.h>
   25.16 -#include <CoreFoundation/CoreFoundation.h>
   25.17 -#endif
   25.18 +#define SECTOR_BITS 9
   25.19 +#define SECTOR_SIZE (1 << SECTOR_BITS)
   25.20 +
   25.21 +typedef struct BlockDriverAIOCBSync {
   25.22 +    BlockDriverAIOCB common;
   25.23 +    QEMUBH *bh;
   25.24 +    int ret;
   25.25 +} BlockDriverAIOCBSync;
   25.26  
   25.27 -#ifdef __sun__
   25.28 -#include <sys/dkio.h>
   25.29 -#endif
   25.30 +static BlockDriverAIOCB *bdrv_aio_read_em(BlockDriverState *bs,
   25.31 +        int64_t sector_num, uint8_t *buf, int nb_sectors,
   25.32 +        BlockDriverCompletionFunc *cb, void *opaque);
   25.33 +static BlockDriverAIOCB *bdrv_aio_write_em(BlockDriverState *bs,
   25.34 +        int64_t sector_num, const uint8_t *buf, int nb_sectors,
   25.35 +        BlockDriverCompletionFunc *cb, void *opaque);
   25.36 +static void bdrv_aio_cancel_em(BlockDriverAIOCB *acb);
   25.37 +static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num, 
   25.38 +                        uint8_t *buf, int nb_sectors);
   25.39 +static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
   25.40 +                         const uint8_t *buf, int nb_sectors);
   25.41  
   25.42  static BlockDriverState *bdrv_first;
   25.43  static BlockDriver *first_drv;
   25.44  
   25.45 -#ifdef CONFIG_COCOA
   25.46 -static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator );
   25.47 -static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize );
   25.48 -
   25.49 -kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )
   25.50 +int path_is_absolute(const char *path)
   25.51  {
   25.52 -    kern_return_t       kernResult; 
   25.53 -    mach_port_t     masterPort;
   25.54 -    CFMutableDictionaryRef  classesToMatch;
   25.55 -
   25.56 -    kernResult = IOMasterPort( MACH_PORT_NULL, &masterPort );
   25.57 -    if ( KERN_SUCCESS != kernResult ) {
   25.58 -        printf( "IOMasterPort returned %d\n", kernResult );
   25.59 -    }
   25.60 -    
   25.61 -    classesToMatch = IOServiceMatching( kIOCDMediaClass ); 
   25.62 -    if ( classesToMatch == NULL ) {
   25.63 -        printf( "IOServiceMatching returned a NULL dictionary.\n" );
   25.64 -    } else {
   25.65 -    CFDictionarySetValue( classesToMatch, CFSTR( kIOMediaEjectableKey ), kCFBooleanTrue );
   25.66 -    }
   25.67 -    kernResult = IOServiceGetMatchingServices( masterPort, classesToMatch, mediaIterator );
   25.68 -    if ( KERN_SUCCESS != kernResult )
   25.69 -    {
   25.70 -        printf( "IOServiceGetMatchingServices returned %d\n", kernResult );
   25.71 -    }
   25.72 -    
   25.73 -    return kernResult;
   25.74 +    const char *p;
   25.75 +#ifdef _WIN32
   25.76 +    /* specific case for names like: "\\.\d:" */
   25.77 +    if (*path == '/' || *path == '\\')
   25.78 +        return 1;
   25.79 +#endif
   25.80 +    p = strchr(path, ':');
   25.81 +    if (p)
   25.82 +        p++;
   25.83 +    else
   25.84 +        p = path;
   25.85 +#ifdef _WIN32
   25.86 +    return (*p == '/' || *p == '\\');
   25.87 +#else
   25.88 +    return (*p == '/');
   25.89 +#endif
   25.90  }
   25.91  
   25.92 -kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize )
   25.93 +/* if filename is absolute, just copy it to dest. Otherwise, build a
   25.94 +   path to it by considering it is relative to base_path. URL are
   25.95 +   supported. */
   25.96 +void path_combine(char *dest, int dest_size,
   25.97 +                  const char *base_path,
   25.98 +                  const char *filename)
   25.99  {
  25.100 -    io_object_t     nextMedia;
  25.101 -    kern_return_t   kernResult = KERN_FAILURE;
  25.102 -    *bsdPath = '\0';
  25.103 -    nextMedia = IOIteratorNext( mediaIterator );
  25.104 -    if ( nextMedia )
  25.105 -    {
  25.106 -        CFTypeRef   bsdPathAsCFString;
  25.107 -    bsdPathAsCFString = IORegistryEntryCreateCFProperty( nextMedia, CFSTR( kIOBSDNameKey ), kCFAllocatorDefault, 0 );
  25.108 -        if ( bsdPathAsCFString ) {
  25.109 -            size_t devPathLength;
  25.110 -            strcpy( bsdPath, _PATH_DEV );
  25.111 -            strcat( bsdPath, "r" );
  25.112 -            devPathLength = strlen( bsdPath );
  25.113 -            if ( CFStringGetCString( bsdPathAsCFString, bsdPath + devPathLength, maxPathSize - devPathLength, kCFStringEncodingASCII ) ) {
  25.114 -                kernResult = KERN_SUCCESS;
  25.115 -            }
  25.116 -            CFRelease( bsdPathAsCFString );
  25.117 +    const char *p, *p1;
  25.118 +    int len;
  25.119 +
  25.120 +    if (dest_size <= 0)
  25.121 +        return;
  25.122 +    if (path_is_absolute(filename)) {
  25.123 +        pstrcpy(dest, dest_size, filename);
  25.124 +    } else {
  25.125 +        p = strchr(base_path, ':');
  25.126 +        if (p)
  25.127 +            p++;
  25.128 +        else
  25.129 +            p = base_path;
  25.130 +        p1 = strrchr(base_path, '/');
  25.131 +#ifdef _WIN32
  25.132 +        {
  25.133 +            const char *p2;
  25.134 +            p2 = strrchr(base_path, '\\');
  25.135 +            if (!p1 || p2 > p1)
  25.136 +                p1 = p2;
  25.137          }
  25.138 -        IOObjectRelease( nextMedia );
  25.139 +#endif
  25.140 +        if (p1)
  25.141 +            p1++;
  25.142 +        else
  25.143 +            p1 = base_path;
  25.144 +        if (p1 > p)
  25.145 +            p = p1;
  25.146 +        len = p - base_path;
  25.147 +        if (len > dest_size - 1)
  25.148 +            len = dest_size - 1;
  25.149 +        memcpy(dest, base_path, len);
  25.150 +        dest[len] = '\0';
  25.151 +        pstrcat(dest, dest_size, filename);
  25.152      }
  25.153 -    
  25.154 -    return kernResult;
  25.155  }
  25.156  
  25.157 -#endif
  25.158  
  25.159  void bdrv_register(BlockDriver *bdrv)
  25.160  {
  25.161 +    if (!bdrv->bdrv_aio_read) {
  25.162 +        /* add AIO emulation layer */
  25.163 +        bdrv->bdrv_aio_read = bdrv_aio_read_em;
  25.164 +        bdrv->bdrv_aio_write = bdrv_aio_write_em;
  25.165 +        bdrv->bdrv_aio_cancel = bdrv_aio_cancel_em;
  25.166 +        bdrv->aiocb_size = sizeof(BlockDriverAIOCBSync);
  25.167 +    } else if (!bdrv->bdrv_read && !bdrv->bdrv_pread) {
  25.168 +        /* add synchronous IO emulation layer */
  25.169 +        bdrv->bdrv_read = bdrv_read_em;
  25.170 +        bdrv->bdrv_write = bdrv_write_em;
  25.171 +    }
  25.172      bdrv->next = first_drv;
  25.173      first_drv = bdrv;
  25.174  }
  25.175 @@ -156,14 +179,10 @@ int bdrv_create(BlockDriver *drv,
  25.176  #ifdef _WIN32
  25.177  void get_tmp_filename(char *filename, int size)
  25.178  {
  25.179 -    char* p = strrchr(filename, '/');
  25.180 -
  25.181 -    if (p == NULL)
  25.182 -	return;
  25.183 -
  25.184 -    /* XXX: find a better function */
  25.185 -    tmpnam(p);
  25.186 -    *p = '/';
  25.187 +    char temp_dir[MAX_PATH];
  25.188 +    
  25.189 +    GetTempPath(MAX_PATH, temp_dir);
  25.190 +    GetTempFileName(temp_dir, "qem", 0, filename);
  25.191  }
  25.192  #else
  25.193  void get_tmp_filename(char *filename, int size)
  25.194 @@ -176,101 +195,141 @@ void get_tmp_filename(char *filename, in
  25.195  }
  25.196  #endif
  25.197  
  25.198 +#ifdef _WIN32
  25.199 +static int is_windows_drive_prefix(const char *filename)
  25.200 +{
  25.201 +    return (((filename[0] >= 'a' && filename[0] <= 'z') ||
  25.202 +             (filename[0] >= 'A' && filename[0] <= 'Z')) &&
  25.203 +            filename[1] == ':');
  25.204 +}
  25.205 +    
  25.206 +static int is_windows_drive(const char *filename)
  25.207 +{
  25.208 +    if (is_windows_drive_prefix(filename) && 
  25.209 +        filename[2] == '\0')
  25.210 +        return 1;
  25.211 +    if (strstart(filename, "\\\\.\\", NULL) ||
  25.212 +        strstart(filename, "//./", NULL))
  25.213 +        return 1;
  25.214 +    return 0;
  25.215 +}
  25.216 +#endif
  25.217 +
  25.218 +static BlockDriver *find_protocol(const char *filename)
  25.219 +{
  25.220 +    BlockDriver *drv1;
  25.221 +    char protocol[128];
  25.222 +    int len;
  25.223 +    const char *p;
  25.224 +
  25.225 +#ifdef _WIN32
  25.226 +    if (is_windows_drive(filename) ||
  25.227 +        is_windows_drive_prefix(filename))
  25.228 +        return &bdrv_raw;
  25.229 +#endif
  25.230 +    p = strchr(filename, ':');
  25.231 +    if (!p)
  25.232 +        return &bdrv_raw;
  25.233 +    len = p - filename;
  25.234 +    if (len > sizeof(protocol) - 1)
  25.235 +        len = sizeof(protocol) - 1;
  25.236 +    memcpy(protocol, filename, len);
  25.237 +    protocol[len] = '\0';
  25.238 +    for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {
  25.239 +        if (drv1->protocol_name && 
  25.240 +            !strcmp(drv1->protocol_name, protocol))
  25.241 +            return drv1;
  25.242 +    }
  25.243 +    return NULL;
  25.244 +}
  25.245 +
  25.246  /* XXX: force raw format if block or character device ? It would
  25.247     simplify the BSD case */
  25.248  static BlockDriver *find_image_format(const char *filename)
  25.249  {
  25.250 -    int fd, ret, score, score_max;
  25.251 +    int ret, score, score_max;
  25.252      BlockDriver *drv1, *drv;
  25.253 -    uint8_t *buf;
  25.254 -    size_t bufsize = 1024;
  25.255 -
  25.256 -    fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
  25.257 -    if (fd < 0) {
  25.258 -        buf = NULL;
  25.259 -        ret = 0;
  25.260 -    } else {
  25.261 -#ifdef DIOCGSECTORSIZE
  25.262 -        {
  25.263 -            unsigned int sectorsize = 512;
  25.264 -            if (!ioctl(fd, DIOCGSECTORSIZE, &sectorsize) &&
  25.265 -                sectorsize > bufsize)
  25.266 -                bufsize = sectorsize;
  25.267 +    uint8_t buf[2048];
  25.268 +    BlockDriverState *bs;
  25.269 +    
  25.270 +    /* detect host devices. By convention, /dev/cdrom[N] is always
  25.271 +       recognized as a host CDROM */
  25.272 +    if (strstart(filename, "/dev/cdrom", NULL))
  25.273 +        return &bdrv_host_device;
  25.274 +#ifdef _WIN32
  25.275 +    if (is_windows_drive(filename))
  25.276 +        return &bdrv_host_device;
  25.277 +#else
  25.278 +    {
  25.279 +        struct stat st;
  25.280 +        if (stat(filename, &st) >= 0 && 
  25.281 +            (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode))) {
  25.282 +            return &bdrv_host_device;
  25.283          }
  25.284 +    }
  25.285  #endif
  25.286 -#ifdef CONFIG_COCOA
  25.287 -        u_int32_t   blockSize = 512;
  25.288 -        if ( !ioctl( fd, DKIOCGETBLOCKSIZE, &blockSize ) && blockSize > bufsize) {
  25.289 -            bufsize = blockSize;
  25.290 -        }
  25.291 -#endif
  25.292 -        buf = qemu_malloc(bufsize);
  25.293 -        if (!buf)
  25.294 -            return NULL;
  25.295 -        ret = read(fd, buf, bufsize);
  25.296 -        if (ret < 0) {
  25.297 -            close(fd);
  25.298 -            qemu_free(buf);
  25.299 -            return NULL;
  25.300 -        }
  25.301 -        close(fd);
  25.302 +    
  25.303 +    drv = find_protocol(filename);
  25.304 +    /* no need to test disk image formats for vvfat */
  25.305 +    if (drv == &bdrv_vvfat)
  25.306 +        return drv;
  25.307 +
  25.308 +    ret = bdrv_file_open(&bs, filename, BDRV_O_RDONLY);
  25.309 +    if (ret < 0)
  25.310 +        return NULL;
  25.311 +    ret = bdrv_pread(bs, 0, buf, sizeof(buf));
  25.312 +    bdrv_delete(bs);
  25.313 +    if (ret < 0) {
  25.314 +        return NULL;
  25.315      }
  25.316 -    
  25.317 -    drv = NULL;
  25.318 +
  25.319      score_max = 0;
  25.320      for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {
  25.321 -        score = drv1->bdrv_probe(buf, ret, filename);
  25.322 -        if (score > score_max) {
  25.323 -            score_max = score;
  25.324 -            drv = drv1;
  25.325 +        if (drv1->bdrv_probe) {
  25.326 +            score = drv1->bdrv_probe(buf, ret, filename);
  25.327 +            if (score > score_max) {
  25.328 +                score_max = score;
  25.329 +                drv = drv1;
  25.330 +            }
  25.331          }
  25.332      }
  25.333 -    qemu_free(buf);
  25.334      return drv;
  25.335  }
  25.336  
  25.337 -int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot)
  25.338 +int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags)
  25.339  {
  25.340 -#ifdef CONFIG_COCOA
  25.341 -    if ( strncmp( filename, "/dev/cdrom", 10 ) == 0 ) {
  25.342 -        kern_return_t kernResult;
  25.343 -        io_iterator_t mediaIterator;
  25.344 -        char bsdPath[ MAXPATHLEN ];
  25.345 -        int fd;
  25.346 - 
  25.347 -        kernResult = FindEjectableCDMedia( &mediaIterator );
  25.348 -        kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) );
  25.349 -    
  25.350 -        if ( bsdPath[ 0 ] != '\0' ) {
  25.351 -            strcat(bsdPath,"s0");
  25.352 -            /* some CDs don't have a partition 0 */
  25.353 -            fd = open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE);
  25.354 -            if (fd < 0) {
  25.355 -                bsdPath[strlen(bsdPath)-1] = '1';
  25.356 -            } else {
  25.357 -                close(fd);
  25.358 -            }
  25.359 -            filename = bsdPath;
  25.360 -        }
  25.361 -        
  25.362 -        if ( mediaIterator )
  25.363 -            IOObjectRelease( mediaIterator );
  25.364 +    BlockDriverState *bs;
  25.365 +    int ret;
  25.366 +
  25.367 +    bs = bdrv_new("");
  25.368 +    if (!bs)
  25.369 +        return -ENOMEM;
  25.370 +    ret = bdrv_open2(bs, filename, flags | BDRV_O_FILE, NULL);
  25.371 +    if (ret < 0) {
  25.372 +        bdrv_delete(bs);
  25.373 +        return ret;
  25.374      }
  25.375 -#endif
  25.376 -    return bdrv_open2(bs, filename, snapshot, NULL);
  25.377 +    *pbs = bs;
  25.378 +    return 0;
  25.379  }
  25.380  
  25.381 -int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot,
  25.382 +int bdrv_open(BlockDriverState *bs, const char *filename, int flags)
  25.383 +{
  25.384 +    return bdrv_open2(bs, filename, flags, NULL);
  25.385 +}
  25.386 +
  25.387 +int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
  25.388                 BlockDriver *drv)
  25.389  {
  25.390 -    int ret;
  25.391 +    int ret, open_flags;
  25.392      char tmp_filename[1024];
  25.393 +    char backing_filename[1024];
  25.394      
  25.395      bs->read_only = 0;
  25.396      bs->is_temporary = 0;
  25.397      bs->encrypted = 0;
  25.398  
  25.399 -    if (snapshot) {
  25.400 +    if (flags & BDRV_O_SNAPSHOT) {
  25.401          BlockDriverState *bs1;
  25.402          int64_t total_size;
  25.403          
  25.404 @@ -280,19 +339,19 @@ int bdrv_open2(BlockDriverState *bs, con
  25.405          /* if there is a backing file, use it */
  25.406          bs1 = bdrv_new("");
  25.407          if (!bs1) {
  25.408 -            return -1;
  25.409 +            return -ENOMEM;
  25.410          }
  25.411          if (bdrv_open(bs1, filename, 0) < 0) {
  25.412              bdrv_delete(bs1);
  25.413              return -1;
  25.414          }
  25.415 -        total_size = bs1->total_sectors;
  25.416 +        total_size = bdrv_getlength(bs1) >> SECTOR_BITS;
  25.417          bdrv_delete(bs1);
  25.418          
  25.419          get_tmp_filename(tmp_filename, sizeof(tmp_filename));
  25.420 -        /* XXX: use cow for linux as it is more efficient ? */
  25.421 -        if (bdrv_create(&bdrv_qcow, tmp_filename, 
  25.422 -                        total_size, filename, 0) < 0) {
  25.423 +        realpath(filename, backing_filename);
  25.424 +        if (bdrv_create(&bdrv_qcow2, tmp_filename, 
  25.425 +                        total_size, backing_filename, 0) < 0) {
  25.426              return -1;
  25.427          }
  25.428          filename = tmp_filename;
  25.429 @@ -300,41 +359,62 @@ int bdrv_open2(BlockDriverState *bs, con
  25.430      }
  25.431  
  25.432      pstrcpy(bs->filename, sizeof(bs->filename), filename);
  25.433 -    if (!drv) {
  25.434 -        drv = find_image_format(filename);
  25.435 +    if (flags & BDRV_O_FILE) {
  25.436 +        drv = find_protocol(filename);
  25.437          if (!drv)
  25.438 -            return -1;
  25.439 +            return -ENOENT;
  25.440 +    } else {
  25.441 +        if (!drv) {
  25.442 +            drv = find_image_format(filename);
  25.443 +            if (!drv)
  25.444 +                return -1;
  25.445 +        }
  25.446      }
  25.447      bs->drv = drv;
  25.448      bs->opaque = qemu_mallocz(drv->instance_size);
  25.449      if (bs->opaque == NULL && drv->instance_size > 0)
  25.450          return -1;
  25.451 -    
  25.452 -    ret = drv->bdrv_open(bs, filename);
  25.453 +    /* Note: for compatibility, we open disk image files as RDWR, and
  25.454 +       RDONLY as fallback */
  25.455 +    if (!(flags & BDRV_O_FILE))
  25.456 +        open_flags = BDRV_O_RDWR;
  25.457 +    else
  25.458 +        open_flags = flags & ~(BDRV_O_FILE | BDRV_O_SNAPSHOT);
  25.459 +    ret = drv->bdrv_open(bs, filename, open_flags);
  25.460 +    if (ret == -EACCES && !(flags & BDRV_O_FILE)) {
  25.461 +        ret = drv->bdrv_open(bs, filename, BDRV_O_RDONLY);
  25.462 +        bs->read_only = 1;
  25.463 +    }
  25.464      if (ret < 0) {
  25.465          qemu_free(bs->opaque);
  25.466 -        return -1;
  25.467 +        bs->opaque = NULL;
  25.468 +        bs->drv = NULL;
  25.469 +        return ret;
  25.470 +    }
  25.471 +    if (drv->bdrv_getlength) {
  25.472 +        bs->total_sectors = bdrv_getlength(bs) >> SECTOR_BITS;
  25.473      }
  25.474  #ifndef _WIN32
  25.475      if (bs->is_temporary) {
  25.476          unlink(filename);
  25.477      }
  25.478  #endif
  25.479 -    if (bs->backing_file[0] != '\0' && drv->bdrv_is_allocated) {
  25.480 +    if (bs->backing_file[0] != '\0') {
  25.481          /* if there is a backing file, use it */
  25.482          bs->backing_hd = bdrv_new("");
  25.483          if (!bs->backing_hd) {
  25.484          fail:
  25.485              bdrv_close(bs);
  25.486 -            return -1;
  25.487 +            return -ENOMEM;
  25.488          }
  25.489 -        if (bdrv_open(bs->backing_hd, bs->backing_file, 0) < 0)
  25.490 +        path_combine(backing_filename, sizeof(backing_filename),
  25.491 +                     filename, bs->backing_file);
  25.492 +        if (bdrv_open(bs->backing_hd, backing_filename, 0) < 0)
  25.493              goto fail;
  25.494      }
  25.495  
  25.496 -    bs->inserted = 1;
  25.497 -
  25.498      /* call the change callback */
  25.499 +    bs->media_changed = 1;
  25.500      if (bs->change_cb)
  25.501          bs->change_cb(bs->change_opaque);
  25.502  
  25.503 @@ -343,7 +423,7 @@ int bdrv_open2(BlockDriverState *bs, con
  25.504  
  25.505  void bdrv_close(BlockDriverState *bs)
  25.506  {
  25.507 -    if (bs->inserted) {
  25.508 +    if (bs->drv) {
  25.509          if (bs->backing_hd)
  25.510              bdrv_delete(bs->backing_hd);
  25.511          bs->drv->bdrv_close(bs);
  25.512 @@ -355,9 +435,9 @@ void bdrv_close(BlockDriverState *bs)
  25.513  #endif
  25.514          bs->opaque = NULL;
  25.515          bs->drv = NULL;
  25.516 -        bs->inserted = 0;
  25.517  
  25.518          /* call the change callback */
  25.519 +        bs->media_changed = 1;
  25.520          if (bs->change_cb)
  25.521              bs->change_cb(bs->change_opaque);
  25.522      }
  25.523 @@ -373,12 +453,13 @@ void bdrv_delete(BlockDriverState *bs)
  25.524  /* commit COW file into the raw image */
  25.525  int bdrv_commit(BlockDriverState *bs)
  25.526  {
  25.527 -    int64_t i;
  25.528 +    BlockDriver *drv = bs->drv;
  25.529 +    int64_t i, total_sectors;
  25.530      int n, j;
  25.531      unsigned char sector[512];
  25.532  
  25.533 -    if (!bs->inserted)
  25.534 -        return -ENOENT;
  25.535 +    if (!drv)
  25.536 +        return -ENOMEDIUM;
  25.537  
  25.538      if (bs->read_only) {
  25.539  	return -EACCES;
  25.540 @@ -388,8 +469,9 @@ int bdrv_commit(BlockDriverState *bs)
  25.541  	return -ENOTSUP;
  25.542      }
  25.543  
  25.544 -    for (i = 0; i < bs->total_sectors;) {
  25.545 -        if (bs->drv->bdrv_is_allocated(bs, i, 65536, &n)) {
  25.546 +    total_sectors = bdrv_getlength(bs) >> SECTOR_BITS;
  25.547 +    for (i = 0; i < total_sectors;) {
  25.548 +        if (drv->bdrv_is_allocated(bs, i, 65536, &n)) {
  25.549              for(j = 0; j < n; j++) {
  25.550                  if (bdrv_read(bs, i, sector, 1) != 0) {
  25.551                      return -EIO;
  25.552 @@ -405,72 +487,241 @@ int bdrv_commit(BlockDriverState *bs)
  25.553          }
  25.554      }
  25.555  
  25.556 -    if (bs->drv->bdrv_make_empty)
  25.557 -	return bs->drv->bdrv_make_empty(bs);
  25.558 +    if (drv->bdrv_make_empty)
  25.559 +	return drv->bdrv_make_empty(bs);
  25.560  
  25.561      return 0;
  25.562  }
  25.563  
  25.564 -/* return -1 if error */
  25.565 +/* return < 0 if error. See bdrv_write() for the return codes */
  25.566  int bdrv_read(BlockDriverState *bs, int64_t sector_num, 
  25.567                uint8_t *buf, int nb_sectors)
  25.568  {
  25.569 -    int ret, n;
  25.570      BlockDriver *drv = bs->drv;
  25.571  
  25.572 -    if (!bs->inserted)
  25.573 -        return -1;
  25.574 +    if (!drv)
  25.575 +        return -ENOMEDIUM;
  25.576 +
  25.577      if (sector_num < 0)
  25.578 -	return -1;
  25.579 +	return -EINVAL;
  25.580  
  25.581 -    while (nb_sectors > 0) {
  25.582 -        if (sector_num == 0 && bs->boot_sector_enabled) {
  25.583 +    if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
  25.584              memcpy(buf, bs->boot_sector_data, 512);
  25.585 -            n = 1;
  25.586 -        } else if (bs->backing_hd) {
  25.587 -            if (drv->bdrv_is_allocated(bs, sector_num, nb_sectors, &n)) {
  25.588 -                ret = drv->bdrv_read(bs, sector_num, buf, n);
  25.589 -                if (ret < 0)
  25.590 -                    return -1;
  25.591 -            } else {
  25.592 -                /* read from the base image */
  25.593 -                ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
  25.594 -                if (ret < 0)
  25.595 -                    return -1;
  25.596 -            }
  25.597 -        } else {
  25.598 -            ret = drv->bdrv_read(bs, sector_num, buf, nb_sectors);
  25.599 -            if (ret < 0)
  25.600 -                return -1;
  25.601 -            /* no need to loop */
  25.602 -            break;
  25.603 -        }
  25.604 -        nb_sectors -= n;
  25.605 -        sector_num += n;
  25.606 -        buf += n * 512;
  25.607 +        sector_num++;
  25.608 +        nb_sectors--;
  25.609 +        buf += 512;
  25.610 +        if (nb_sectors == 0)
  25.611 +            return 0;
  25.612      }
  25.613 -    return 0;
  25.614 +    if (drv->bdrv_pread) {
  25.615 +        int ret, len;
  25.616 +        len = nb_sectors * 512;
  25.617 +        ret = drv->bdrv_pread(bs, sector_num * 512, buf, len);
  25.618 +        if (ret < 0)
  25.619 +            return ret;
  25.620 +        else if (ret != len)
  25.621 +            return -EINVAL;
  25.622 +        else
  25.623 +            return 0;
  25.624 +    } else {
  25.625 +        return drv->bdrv_read(bs, sector_num, buf, nb_sectors);
  25.626 +    }
  25.627  }
  25.628  
  25.629 -/* return -1 if error */
  25.630 +/* Return < 0 if error. Important errors are: 
  25.631 +  -EIO         generic I/O error (may happen for all errors)
  25.632 +  -ENOMEDIUM   No media inserted.
  25.633 +  -EINVAL      Invalid sector number or nb_sectors
  25.634 +  -EACCES      Trying to write a read-only device
  25.635 +*/
  25.636  int bdrv_write(BlockDriverState *bs, int64_t sector_num, 
  25.637                 const uint8_t *buf, int nb_sectors)
  25.638  {
  25.639 -    if (!bs->inserted)
  25.640 -        return -1;
  25.641 +    BlockDriver *drv = bs->drv;
  25.642 +    if (!bs->drv)
  25.643 +        return -ENOMEDIUM;
  25.644      if (bs->read_only)
  25.645 -        return -1;
  25.646 +        return -EACCES;
  25.647      if (sector_num < 0)
  25.648 -	return -1;
  25.649 +	return -EINVAL;
  25.650      if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
  25.651          memcpy(bs->boot_sector_data, buf, 512);   
  25.652      }
  25.653 -    return bs->drv->bdrv_write(bs, sector_num, buf, nb_sectors);
  25.654 +    if (drv->bdrv_pwrite) {
  25.655 +        int ret, len;
  25.656 +        len = nb_sectors * 512;
  25.657 +        ret = drv->bdrv_pwrite(bs, sector_num * 512, buf, len);
  25.658 +        if (ret < 0)
  25.659 +            return ret;
  25.660 +        else if (ret != len)
  25.661 +            return -EIO;
  25.662 +        else
  25.663 +            return 0;
  25.664 +    } else {
  25.665 +        return drv->bdrv_write(bs, sector_num, buf, nb_sectors);
  25.666 +    }
  25.667 +}
  25.668 +
  25.669 +static int bdrv_pread_em(BlockDriverState *bs, int64_t offset, 
  25.670 +                         uint8_t *buf, int count1)
  25.671 +{
  25.672 +    uint8_t tmp_buf[SECTOR_SIZE];
  25.673 +    int len, nb_sectors, count;
  25.674 +    int64_t sector_num;
  25.675 +
  25.676 +    count = count1;
  25.677 +    /* first read to align to sector start */
  25.678 +    len = (SECTOR_SIZE - offset) & (SECTOR_SIZE - 1);
  25.679 +    if (len > count)
  25.680 +        len = count;
  25.681 +    sector_num = offset >> SECTOR_BITS;
  25.682 +    if (len > 0) {
  25.683 +        if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
  25.684 +            return -EIO;
  25.685 +        memcpy(buf, tmp_buf + (offset & (SECTOR_SIZE - 1)), len);
  25.686 +        count -= len;
  25.687 +        if (count == 0)
  25.688 +            return count1;
  25.689 +        sector_num++;
  25.690 +        buf += len;
  25.691 +    }
  25.692 +
  25.693 +    /* read the sectors "in place" */
  25.694 +    nb_sectors = count >> SECTOR_BITS;
  25.695 +    if (nb_sectors > 0) {
  25.696 +        if (bdrv_read(bs, sector_num, buf, nb_sectors) < 0)
  25.697 +            return -EIO;
  25.698 +        sector_num += nb_sectors;
  25.699 +        len = nb_sectors << SECTOR_BITS;
  25.700 +        buf += len;
  25.701 +        count -= len;
  25.702 +    }
  25.703 +
  25.704 +    /* add data from the last sector */
  25.705 +    if (count > 0) {
  25.706 +        if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
  25.707 +            return -EIO;
  25.708 +        memcpy(buf, tmp_buf, count);
  25.709 +    }
  25.710 +    return count1;
  25.711  }
  25.712  
  25.713 +static int bdrv_pwrite_em(BlockDriverState *bs, int64_t offset, 
  25.714 +                          const uint8_t *buf, int count1)
  25.715 +{
  25.716 +    uint8_t tmp_buf[SECTOR_SIZE];
  25.717 +    int len, nb_sectors, count;
  25.718 +    int64_t sector_num;
  25.719 +
  25.720 +    count = count1;
  25.721 +    /* first write to align to sector start */
  25.722 +    len = (SECTOR_SIZE - offset) & (SECTOR_SIZE - 1);
  25.723 +    if (len > count)
  25.724 +        len = count;
  25.725 +    sector_num = offset >> SECTOR_BITS;
  25.726 +    if (len > 0) {
  25.727 +        if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
  25.728 +            return -EIO;
  25.729 +        memcpy(tmp_buf + (offset & (SECTOR_SIZE - 1)), buf, len);
  25.730 +        if (bdrv_write(bs, sector_num, tmp_buf, 1) < 0)
  25.731 +            return -EIO;
  25.732 +        count -= len;
  25.733 +        if (count == 0)
  25.734 +            return count1;
  25.735 +        sector_num++;
  25.736 +        buf += len;
  25.737 +    }
  25.738 +
  25.739 +    /* write the sectors "in place" */
  25.740 +    nb_sectors = count >> SECTOR_BITS;
  25.741 +    if (nb_sectors > 0) {
  25.742 +        if (bdrv_write(bs, sector_num, buf, nb_sectors) < 0)
  25.743 +            return -EIO;
  25.744 +        sector_num += nb_sectors;
  25.745 +        len = nb_sectors << SECTOR_BITS;
  25.746 +        buf += len;
  25.747 +        count -= len;
  25.748 +    }
  25.749 +
  25.750 +    /* add data from the last sector */
  25.751 +    if (count > 0) {
  25.752 +        if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
  25.753 +            return -EIO;
  25.754 +        memcpy(tmp_buf, buf, count);
  25.755 +        if (bdrv_write(bs, sector_num, tmp_buf, 1) < 0)
  25.756 +            return -EIO;
  25.757 +    }
  25.758 +    return count1;
  25.759 +}
  25.760 +
  25.761 +/**
  25.762 + * Read with byte offsets (needed only for file protocols) 
  25.763 + */
  25.764 +int bdrv_pread(BlockDriverState *bs, int64_t offset, 
  25.765 +               void *buf1, int count1)
  25.766 +{
  25.767 +    BlockDriver *drv = bs->drv;
  25.768 +
  25.769 +    if (!drv)
  25.770 +        return -ENOMEDIUM;
  25.771 +    if (!drv->bdrv_pread)
  25.772 +        return bdrv_pread_em(bs, offset, buf1, count1);
  25.773 +    return drv->bdrv_pread(bs, offset, buf1, count1);
  25.774 +}
  25.775 +
  25.776 +/** 
  25.777 + * Write with byte offsets (needed only for file protocols) 
  25.778 + */
  25.779 +int bdrv_pwrite(BlockDriverState *bs, int64_t offset, 
  25.780 +                const void *buf1, int count1)
  25.781 +{
  25.782 +    BlockDriver *drv = bs->drv;
  25.783 +
  25.784 +    if (!drv)
  25.785 +        return -ENOMEDIUM;
  25.786 +    if (!drv->bdrv_pwrite)
  25.787 +        return bdrv_pwrite_em(bs, offset, buf1, count1);
  25.788 +    return drv->bdrv_pwrite(bs, offset, buf1, count1);
  25.789 +}
  25.790 +
  25.791 +/**
  25.792 + * Truncate file to 'offset' bytes (needed only for file protocols)
  25.793 + */
  25.794 +int bdrv_truncate(BlockDriverState *bs, int64_t offset)
  25.795 +{
  25.796 +    BlockDriver *drv = bs->drv;
  25.797 +    if (!drv)
  25.798 +        return -ENOMEDIUM;
  25.799 +    if (!drv->bdrv_truncate)
  25.800 +        return -ENOTSUP;
  25.801 +    return drv->bdrv_truncate(bs, offset);
  25.802 +}
  25.803 +
  25.804 +/**
  25.805 + * Length of a file in bytes. Return < 0 if error or unknown.
  25.806 + */
  25.807 +int64_t bdrv_getlength(BlockDriverState *bs)
  25.808 +{
  25.809 +    BlockDriver *drv = bs->drv;
  25.810 +    if (!drv)
  25.811 +        return -ENOMEDIUM;
  25.812 +    if (!drv->bdrv_getlength) {
  25.813 +        /* legacy mode */
  25.814 +        return bs->total_sectors * SECTOR_SIZE;
  25.815 +    }
  25.816 +    return drv->bdrv_getlength(bs);
  25.817 +}
  25.818 +
  25.819 +/* return 0 as number of sectors if no device present or error */
  25.820  void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr)
  25.821  {
  25.822 -    *nb_sectors_ptr = bs->total_sectors;
  25.823 +    int64_t length;
  25.824 +    length = bdrv_getlength(bs);
  25.825 +    if (length < 0)
  25.826 +        length = 0;
  25.827 +    else
  25.828 +        length = length >> SECTOR_BITS;
  25.829 +    *nb_sectors_ptr = length;
  25.830  }
  25.831  
  25.832  /* force a given boot sector. */
  25.833 @@ -531,21 +782,7 @@ int bdrv_is_read_only(BlockDriverState *
  25.834      return bs->read_only;
  25.835  }
  25.836  
  25.837 -int bdrv_is_inserted(BlockDriverState *bs)
  25.838 -{
  25.839 -    return bs->inserted;
  25.840 -}
  25.841 -
  25.842 -int bdrv_is_locked(BlockDriverState *bs)
  25.843 -{
  25.844 -    return bs->locked;
  25.845 -}
  25.846 -
  25.847 -void bdrv_set_locked(BlockDriverState *bs, int locked)
  25.848 -{
  25.849 -    bs->locked = locked;
  25.850 -}
  25.851 -
  25.852 +/* XXX: no longer used */
  25.853  void bdrv_set_change_cb(BlockDriverState *bs, 
  25.854                          void (*change_cb)(void *opaque), void *opaque)
  25.855  {
  25.856 @@ -577,7 +814,7 @@ int bdrv_set_key(BlockDriverState *bs, c
  25.857  
  25.858  void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size)
  25.859  {
  25.860 -    if (!bs->inserted || !bs->drv) {
  25.861 +    if (!bs->drv) {
  25.862          buf[0] = '\0';
  25.863      } else {
  25.864          pstrcpy(buf, buf_size, bs->drv->format_name);
  25.865 @@ -649,10 +886,13 @@ void bdrv_info(void)
  25.866          if (bs->removable) {
  25.867              term_printf(" locked=%d", bs->locked);
  25.868          }
  25.869 -        if (bs->inserted) {
  25.870 -            term_printf(" file=%s", bs->filename);
  25.871 -            if (bs->backing_file[0] != '\0')
  25.872 -                term_printf(" backing_file=%s", bs->backing_file);
  25.873 +        if (bs->drv) {
  25.874 +            term_printf(" file=");
  25.875 +	    term_print_filename(bs->filename);
  25.876 +            if (bs->backing_file[0] != '\0') {
  25.877 +                term_printf(" backing_file=");
  25.878 +		term_print_filename(bs->backing_file);
  25.879 +	    }
  25.880              term_printf(" ro=%d", bs->read_only);
  25.881              term_printf(" drv=%s", bs->drv->format_name);
  25.882              if (bs->encrypted)
  25.883 @@ -664,192 +904,337 @@ void bdrv_info(void)
  25.884      }
  25.885  }
  25.886  
  25.887 -/**************************************************************/
  25.888 -/* RAW block driver */
  25.889 +void bdrv_get_backing_filename(BlockDriverState *bs, 
  25.890 +                               char *filename, int filename_size)
  25.891 +{
  25.892 +    if (!bs->backing_hd) {
  25.893 +        pstrcpy(filename, filename_size, "");
  25.894 +    } else {
  25.895 +        pstrcpy(filename, filename_size, bs->backing_file);
  25.896 +    }
  25.897 +}
  25.898 +
  25.899 +int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num, 
  25.900 +                          const uint8_t *buf, int nb_sectors)
  25.901 +{
  25.902 +    BlockDriver *drv = bs->drv;
  25.903 +    if (!drv)
  25.904 +        return -ENOMEDIUM;
  25.905 +    if (!drv->bdrv_write_compressed)
  25.906 +        return -ENOTSUP;
  25.907 +    return drv->bdrv_write_compressed(bs, sector_num, buf, nb_sectors);
  25.908 +}
  25.909 +    
  25.910 +int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
  25.911 +{
  25.912 +    BlockDriver *drv = bs->drv;
  25.913 +    if (!drv)
  25.914 +        return -ENOMEDIUM;
  25.915 +    if (!drv->bdrv_get_info)
  25.916 +        return -ENOTSUP;
  25.917 +    memset(bdi, 0, sizeof(*bdi));
  25.918 +    return drv->bdrv_get_info(bs, bdi);
  25.919 +}
  25.920  
  25.921 -typedef struct BDRVRawState {
  25.922 -    int fd;
  25.923 -} BDRVRawState;
  25.924 +/**************************************************************/
  25.925 +/* handling of snapshots */
  25.926 +
  25.927 +int bdrv_snapshot_create(BlockDriverState *bs, 
  25.928 +                         QEMUSnapshotInfo *sn_info)
  25.929 +{
  25.930 +    BlockDriver *drv = bs->drv;
  25.931 +    if (!drv)
  25.932 +        return -ENOMEDIUM;
  25.933 +    if (!drv->bdrv_snapshot_create)
  25.934 +        return -ENOTSUP;
  25.935 +    return drv->bdrv_snapshot_create(bs, sn_info);
  25.936 +}
  25.937  
  25.938 -static int raw_probe(const uint8_t *buf, int buf_size, const char *filename)
  25.939 +int bdrv_snapshot_goto(BlockDriverState *bs, 
  25.940 +                       const char *snapshot_id)
  25.941  {
  25.942 -    return 1; /* maybe */
  25.943 +    BlockDriver *drv = bs->drv;
  25.944 +    if (!drv)
  25.945 +        return -ENOMEDIUM;
  25.946 +    if (!drv->bdrv_snapshot_goto)
  25.947 +        return -ENOTSUP;
  25.948 +    return drv->bdrv_snapshot_goto(bs, snapshot_id);
  25.949 +}
  25.950 +
  25.951 +int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
  25.952 +{
  25.953 +    BlockDriver *drv = bs->drv;
  25.954 +    if (!drv)
  25.955 +        return -ENOMEDIUM;
  25.956 +    if (!drv->bdrv_snapshot_delete)
  25.957 +        return -ENOTSUP;
  25.958 +    return drv->bdrv_snapshot_delete(bs, snapshot_id);
  25.959  }
  25.960  
  25.961 -static int raw_open(BlockDriverState *bs, const char *filename)
  25.962 +int bdrv_snapshot_list(BlockDriverState *bs, 
  25.963 +                       QEMUSnapshotInfo **psn_info)
  25.964 +{
  25.965 +    BlockDriver *drv = bs->drv;
  25.966 +    if (!drv)
  25.967 +        return -ENOMEDIUM;
  25.968 +    if (!drv->bdrv_snapshot_list)
  25.969 +        return -ENOTSUP;
  25.970 +    return drv->bdrv_snapshot_list(bs, psn_info);
  25.971 +}
  25.972 +
  25.973 +#define NB_SUFFIXES 4
  25.974 +
  25.975 +char *get_human_readable_size(char *buf, int buf_size, int64_t size)
  25.976  {
  25.977 -    BDRVRawState *s = bs->opaque;
  25.978 -    int fd;
  25.979 -    int64_t size;
  25.980 -#ifdef _BSD
  25.981 -    struct stat sb;
  25.982 -#endif
  25.983 -#ifdef __sun__
  25.984 -    struct dk_minfo minfo;
  25.985 -    int rv;
  25.986 -#endif
  25.987 +    static const char suffixes[NB_SUFFIXES] = "KMGT";
  25.988 +    int64_t base;
  25.989 +    int i;
  25.990  
  25.991 -    fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
  25.992 -    if (fd < 0) {
  25.993 -        fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
  25.994 -        if (fd < 0)
  25.995 -            return -1;
  25.996 -        bs->read_only = 1;
  25.997 +    if (size <= 999) {
  25.998 +        snprintf(buf, buf_size, "%" PRId64, size);
  25.999 +    } else {
 25.1000 +        base = 1024;
 25.1001 +        for(i = 0; i < NB_SUFFIXES; i++) {
 25.1002 +            if (size < (10 * base)) {
 25.1003 +                snprintf(buf, buf_size, "%0.1f%c", 
 25.1004 +                         (double)size / base,
 25.1005 +                         suffixes[i]);
 25.1006 +                break;
 25.1007 +            } else if (size < (1000 * base) || i == (NB_SUFFIXES - 1)) {
 25.1008 +                snprintf(buf, buf_size, "%" PRId64 "%c", 
 25.1009 +                         ((size + (base >> 1)) / base),
 25.1010 +                         suffixes[i]);
 25.1011 +                break;
 25.1012 +            }
 25.1013 +            base = base * 1024;
 25.1014 +        }
 25.1015      }
 25.1016 -#ifdef _BSD
 25.1017 -    if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) {
 25.1018 -#ifdef DIOCGMEDIASIZE
 25.1019 -	if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size))
 25.1020 -#endif
 25.1021 -#ifdef CONFIG_COCOA
 25.1022 -        size = LONG_LONG_MAX;
 25.1023 -#else
 25.1024 -        size = lseek(fd, 0LL, SEEK_END);
 25.1025 -#endif
 25.1026 -    } else
 25.1027 -#endif
 25.1028 -#ifdef __sun__
 25.1029 -    /*
 25.1030 -     * use the DKIOCGMEDIAINFO ioctl to read the size.
 25.1031 -     */
 25.1032 -    rv = ioctl ( fd, DKIOCGMEDIAINFO, &minfo );
 25.1033 -    if ( rv != -1 ) {
 25.1034 -        size = minfo.dki_lbsize * minfo.dki_capacity;
 25.1035 -    } else /* there are reports that lseek on some devices
 25.1036 -              fails, but irc discussion said that contingency
 25.1037 -              on contingency was overkill */
 25.1038 -#endif
 25.1039 -    {
 25.1040 -        size = lseek(fd, 0, SEEK_END);
 25.1041 -    }
 25.1042 -#ifdef _WIN32
 25.1043 -    /* On Windows hosts it can happen that we're unable to get file size
 25.1044 -       for CD-ROM raw device (it's inherent limitation of the CDFS driver). */
 25.1045 -    if (size == -1)
 25.1046 -        size = LONG_LONG_MAX;
 25.1047 -#endif
 25.1048 -    bs->total_sectors = size / 512;
 25.1049 -    s->fd = fd;
 25.1050 -    return 0;
 25.1051 +    return buf;
 25.1052  }
 25.1053  
 25.1054 -static int raw_read(BlockDriverState *bs, int64_t sector_num, 
 25.1055 -                    uint8_t *buf, int nb_sectors)
 25.1056 +char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn)
 25.1057  {
 25.1058 -    BDRVRawState *s = bs->opaque;
 25.1059 -    int ret;
 25.1060 -    
 25.1061 -    lseek(s->fd, sector_num * 512, SEEK_SET);
 25.1062 -    ret = read(s->fd, buf, nb_sectors * 512);
 25.1063 -    if (ret != nb_sectors * 512) 
 25.1064 -        return -1;
 25.1065 -    return 0;
 25.1066 +    char buf1[128], date_buf[128], clock_buf[128];
 25.1067 +#ifdef _WIN32
 25.1068 +    struct tm *ptm;
 25.1069 +#else
 25.1070 +    struct tm tm;
 25.1071 +#endif
 25.1072 +    time_t ti;
 25.1073 +    int64_t secs;
 25.1074 +
 25.1075 +    if (!sn) {
 25.1076 +        snprintf(buf, buf_size, 
 25.1077 +                 "%-10s%-20s%7s%20s%15s", 
 25.1078 +                 "ID", "TAG", "VM SIZE", "DATE", "VM CLOCK");
 25.1079 +    } else {
 25.1080 +        ti = sn->date_sec;
 25.1081 +#ifdef _WIN32
 25.1082 +        ptm = localtime(&ti);
 25.1083 +        strftime(date_buf, sizeof(date_buf),
 25.1084 +                 "%Y-%m-%d %H:%M:%S", ptm);
 25.1085 +#else
 25.1086 +        localtime_r(&ti, &tm);
 25.1087 +        strftime(date_buf, sizeof(date_buf),
 25.1088 +                 "%Y-%m-%d %H:%M:%S", &tm);
 25.1089 +#endif
 25.1090 +        secs = sn->vm_clock_nsec / 1000000000;
 25.1091 +        snprintf(clock_buf, sizeof(clock_buf),
 25.1092 +                 "%02d:%02d:%02d.%03d",
 25.1093 +                 (int)(secs / 3600),
 25.1094 +                 (int)((secs / 60) % 60),
 25.1095 +                 (int)(secs % 60), 
 25.1096 +                 (int)((sn->vm_clock_nsec / 1000000) % 1000));
 25.1097 +        snprintf(buf, buf_size,
 25.1098 +                 "%-10s%-20s%7s%20s%15s", 
 25.1099 +                 sn->id_str, sn->name,
 25.1100 +                 get_human_readable_size(buf1, sizeof(buf1), sn->vm_state_size),
 25.1101 +                 date_buf,
 25.1102 +                 clock_buf);
 25.1103 +    }
 25.1104 +    return buf;
 25.1105  }
 25.1106  
 25.1107 -static int raw_write(BlockDriverState *bs, int64_t sector_num, 
 25.1108 -                     const uint8_t *buf, int nb_sectors)
 25.1109 +
 25.1110 +/**************************************************************/
 25.1111 +/* async I/Os */
 25.1112 +
 25.1113 +BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num,
 25.1114 +                                uint8_t *buf, int nb_sectors,
 25.1115 +                                BlockDriverCompletionFunc *cb, void *opaque)
 25.1116  {
 25.1117 -    BDRVRawState *s = bs->opaque;
 25.1118 -    int ret;
 25.1119 +    BlockDriver *drv = bs->drv;
 25.1120 +
 25.1121 +    if (!drv)
 25.1122 +        return NULL;
 25.1123      
 25.1124 -    lseek(s->fd, sector_num * 512, SEEK_SET);
 25.1125 -    ret = write(s->fd, buf, nb_sectors * 512);
 25.1126 -    if (ret != nb_sectors * 512) 
 25.1127 -        return -1;
 25.1128 -    return 0;
 25.1129 +    /* XXX: we assume that nb_sectors == 0 is suppored by the async read */
 25.1130 +    if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
 25.1131 +        memcpy(buf, bs->boot_sector_data, 512);
 25.1132 +        sector_num++;
 25.1133 +        nb_sectors--;
 25.1134 +        buf += 512;
 25.1135 +    }
 25.1136 +
 25.1137 +    return drv->bdrv_aio_read(bs, sector_num, buf, nb_sectors, cb, opaque);
 25.1138 +}
 25.1139 +
 25.1140 +BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num,
 25.1141 +                                 const uint8_t *buf, int nb_sectors,
 25.1142 +                                 BlockDriverCompletionFunc *cb, void *opaque)
 25.1143 +{
 25.1144 +    BlockDriver *drv = bs->drv;
 25.1145 +
 25.1146 +    if (!drv)
 25.1147 +        return NULL;
 25.1148 +    if (bs->read_only)
 25.1149 +        return NULL;
 25.1150 +    if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
 25.1151 +        memcpy(bs->boot_sector_data, buf, 512);   
 25.1152 +    }
 25.1153 +
 25.1154 +    return drv->bdrv_aio_write(bs, sector_num, buf, nb_sectors, cb, opaque);
 25.1155  }
 25.1156  
 25.1157 -static void raw_close(BlockDriverState *bs)
 25.1158 +void bdrv_aio_cancel(BlockDriverAIOCB *acb)
 25.1159 +{
 25.1160 +    BlockDriver *drv = acb->bs->drv;
 25.1161 +
 25.1162 +    drv->bdrv_aio_cancel(acb);
 25.1163 +}
 25.1164 +
 25.1165 +
 25.1166 +/**************************************************************/
 25.1167 +/* async block device emulation */
 25.1168 +
 25.1169 +#ifdef QEMU_TOOL
 25.1170 +static BlockDriverAIOCB *bdrv_aio_read_em(BlockDriverState *bs,
 25.1171 +        int64_t sector_num, uint8_t *buf, int nb_sectors,
 25.1172 +        BlockDriverCompletionFunc *cb, void *opaque)
 25.1173  {
 25.1174 -    BDRVRawState *s = bs->opaque;
 25.1175 -    bs->total_sectors = 0;
 25.1176 -    close(s->fd);
 25.1177 +    int ret;
 25.1178 +    ret = bdrv_read(bs, sector_num, buf, nb_sectors);
 25.1179 +    cb(opaque, ret);
 25.1180 +    return NULL;
 25.1181 +}
 25.1182 +
 25.1183 +static BlockDriverAIOCB *bdrv_aio_write_em(BlockDriverState *bs,
 25.1184 +        int64_t sector_num, const uint8_t *buf, int nb_sectors,
 25.1185 +        BlockDriverCompletionFunc *cb, void *opaque)
 25.1186 +{
 25.1187 +    int ret;
 25.1188 +    ret = bdrv_write(bs, sector_num, buf, nb_sectors);
 25.1189 +    cb(opaque, ret);
 25.1190 +    return NULL;
 25.1191 +}
 25.1192 +
 25.1193 +static void bdrv_aio_cancel_em(BlockDriverAIOCB *acb)
 25.1194 +{
 25.1195 +}
 25.1196 +#else
 25.1197 +static void bdrv_aio_bh_cb(void *opaque)
 25.1198 +{
 25.1199 +    BlockDriverAIOCBSync *acb = opaque;
 25.1200 +    acb->common.cb(acb->common.opaque, acb->ret);
 25.1201 +    qemu_aio_release(acb);
 25.1202  }
 25.1203  
 25.1204 -#ifdef _WIN32
 25.1205 -#include <windows.h>
 25.1206 -#include <winioctl.h>
 25.1207 -
 25.1208 -int qemu_ftruncate64(int fd, int64_t length)
 25.1209 +static BlockDriverAIOCB *bdrv_aio_read_em(BlockDriverState *bs,
 25.1210 +        int64_t sector_num, uint8_t *buf, int nb_sectors,
 25.1211 +        BlockDriverCompletionFunc *cb, void *opaque)
 25.1212  {
 25.1213 -    LARGE_INTEGER li;
 25.1214 -    LONG high;
 25.1215 -    HANDLE h;
 25.1216 -    BOOL res;
 25.1217 -
 25.1218 -    if ((GetVersion() & 0x80000000UL) && (length >> 32) != 0)
 25.1219 -	return -1;
 25.1220 +    BlockDriverAIOCBSync *acb;
 25.1221 +    int ret;
 25.1222  
 25.1223 -    h = (HANDLE)_get_osfhandle(fd);
 25.1224 -
 25.1225 -    /* get current position, ftruncate do not change position */
 25.1226 -    li.HighPart = 0;
 25.1227 -    li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT);
 25.1228 -    if (li.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
 25.1229 -	return -1;
 25.1230 +    acb = qemu_aio_get(bs, cb, opaque);
 25.1231 +    if (!acb->bh)
 25.1232 +        acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb);
 25.1233 +    ret = bdrv_read(bs, sector_num, buf, nb_sectors);
 25.1234 +    acb->ret = ret;
 25.1235 +    qemu_bh_schedule(acb->bh);
 25.1236 +    return &acb->common;
 25.1237 +}
 25.1238  
 25.1239 -    high = length >> 32;
 25.1240 -    if (!SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN))
 25.1241 -	return -1;
 25.1242 -    res = SetEndOfFile(h);
 25.1243 +static BlockDriverAIOCB *bdrv_aio_write_em(BlockDriverState *bs,
 25.1244 +        int64_t sector_num, const uint8_t *buf, int nb_sectors,
 25.1245 +        BlockDriverCompletionFunc *cb, void *opaque)
 25.1246 +{
 25.1247 +    BlockDriverAIOCBSync *acb;
 25.1248 +    int ret;
 25.1249  
 25.1250 -    /* back to old position */
 25.1251 -    SetFilePointer(h, li.LowPart, &li.HighPart, FILE_BEGIN);
 25.1252 -    return res ? 0 : -1;
 25.1253 +    acb = qemu_aio_get(bs, cb, opaque);
 25.1254 +    if (!acb->bh)
 25.1255 +        acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb);
 25.1256 +    ret = bdrv_write(bs, sector_num, buf, nb_sectors);
 25.1257 +    acb->ret = ret;
 25.1258 +    qemu_bh_schedule(acb->bh);
 25.1259 +    return &acb->common;
 25.1260  }
 25.1261  
 25.1262 -static int set_sparse(int fd)
 25.1263 +static void bdrv_aio_cancel_em(BlockDriverAIOCB *blockacb)
 25.1264  {
 25.1265 -    DWORD returned;
 25.1266 -    return (int) DeviceIoControl((HANDLE)_get_osfhandle(fd), FSCTL_SET_SPARSE,
 25.1267 -				 NULL, 0, NULL, 0, &returned, NULL);
 25.1268 +    BlockDriverAIOCBSync *acb = (BlockDriverAIOCBSync *)blockacb;
 25.1269 +    qemu_bh_cancel(acb->bh);
 25.1270 +    qemu_aio_release(acb);
 25.1271  }
 25.1272 -#else
 25.1273 -static inline int set_sparse(int fd)
 25.1274 -{
 25.1275 -    return 1;
 25.1276 -}
 25.1277 -#endif
 25.1278 +#endif /* !QEMU_TOOL */
 25.1279  
 25.1280 -static int raw_create(const char *filename, int64_t total_size,
 25.1281 -                      const char *backing_file, int flags)
 25.1282 -{
 25.1283 -    int fd;
 25.1284 -
 25.1285 -    if (flags || backing_file)
 25.1286 -        return -ENOTSUP;
 25.1287 +/**************************************************************/
 25.1288 +/* sync block device emulation */
 25.1289  
 25.1290 -    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 
 25.1291 -              0644);
 25.1292 -    if (fd < 0)
 25.1293 -        return -EIO;
 25.1294 -    set_sparse(fd);
 25.1295 -    ftruncate(fd, total_size * 512);
 25.1296 -    close(fd);
 25.1297 -    return 0;
 25.1298 +static void bdrv_rw_em_cb(void *opaque, int ret)
 25.1299 +{
 25.1300 +    *(int *)opaque = ret;
 25.1301  }
 25.1302  
 25.1303 -static void raw_flush(BlockDriverState *bs)
 25.1304 +#define NOT_DONE 0x7fffffff
 25.1305 +
 25.1306 +static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num, 
 25.1307 +                        uint8_t *buf, int nb_sectors)
 25.1308  {
 25.1309 -    BDRVRawState *s = bs->opaque;
 25.1310 -    fsync(s->fd);
 25.1311 +    int async_ret;
 25.1312 +    BlockDriverAIOCB *acb;
 25.1313 +
 25.1314 +    async_ret = NOT_DONE;
 25.1315 +    qemu_aio_wait_start();
 25.1316 +    acb = bdrv_aio_read(bs, sector_num, buf, nb_sectors, 
 25.1317 +                        bdrv_rw_em_cb, &async_ret);
 25.1318 +    if (acb == NULL) {
 25.1319 +        qemu_aio_wait_end();
 25.1320 +        return -1;
 25.1321 +    }
 25.1322 +    while (async_ret == NOT_DONE) {
 25.1323 +        qemu_aio_wait();
 25.1324 +    }
 25.1325 +    qemu_aio_wait_end();
 25.1326 +    return async_ret;
 25.1327  }
 25.1328  
 25.1329 -BlockDriver bdrv_raw = {
 25.1330 -    "raw",
 25.1331 -    sizeof(BDRVRawState),
 25.1332 -    raw_probe,
 25.1333 -    raw_open,
 25.1334 -    raw_read,
 25.1335 -    raw_write,
 25.1336 -    raw_close,
 25.1337 -    raw_create,
 25.1338 -    raw_flush,
 25.1339 -};
 25.1340 +static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
 25.1341 +                         const uint8_t *buf, int nb_sectors)
 25.1342 +{
 25.1343 +    int async_ret;
 25.1344 +    BlockDriverAIOCB *acb;
 25.1345 +
 25.1346 +    async_ret = NOT_DONE;
 25.1347 +    qemu_aio_wait_start();
 25.1348 +    acb = bdrv_aio_write(bs, sector_num, buf, nb_sectors, 
 25.1349 +                         bdrv_rw_em_cb, &async_ret);
 25.1350 +    if (acb == NULL) {
 25.1351 +        qemu_aio_wait_end();
 25.1352 +        return -1;
 25.1353 +    }
 25.1354 +    while (async_ret == NOT_DONE) {
 25.1355 +        qemu_aio_wait();
 25.1356 +    }
 25.1357 +    qemu_aio_wait_end();
 25.1358 +    return async_ret;
 25.1359 +}
 25.1360  
 25.1361  void bdrv_init(void)
 25.1362  {
 25.1363      bdrv_register(&bdrv_raw);
 25.1364 +    bdrv_register(&bdrv_host_device);
 25.1365  #ifndef _WIN32
 25.1366      bdrv_register(&bdrv_cow);
 25.1367  #endif
 25.1368 @@ -860,4 +1245,109 @@ void bdrv_init(void)
 25.1369      bdrv_register(&bdrv_bochs);
 25.1370      bdrv_register(&bdrv_vpc);
 25.1371      bdrv_register(&bdrv_vvfat);
 25.1372 +    bdrv_register(&bdrv_qcow2);
 25.1373  }
 25.1374 +
 25.1375 +void *qemu_aio_get(BlockDriverState *bs, BlockDriverCompletionFunc *cb,
 25.1376 +                   void *opaque)
 25.1377 +{
 25.1378 +    BlockDriver *drv;
 25.1379 +    BlockDriverAIOCB *acb;
 25.1380 +
 25.1381 +    drv = bs->drv;
 25.1382 +    if (drv->free_aiocb) {
 25.1383 +        acb = drv->free_aiocb;
 25.1384 +        drv->free_aiocb = acb->next;
 25.1385 +    } else {
 25.1386 +        acb = qemu_mallocz(drv->aiocb_size);
 25.1387 +        if (!acb)
 25.1388 +            return NULL;
 25.1389 +    }
 25.1390 +    acb->bs = bs;
 25.1391 +    acb->cb = cb;
 25.1392 +    acb->opaque = opaque;
 25.1393 +    return acb;
 25.1394 +}
 25.1395 +
 25.1396 +void qemu_aio_release(void *p)
 25.1397 +{
 25.1398 +    BlockDriverAIOCB *acb = p;
 25.1399 +    BlockDriver *drv = acb->bs->drv;
 25.1400 +    acb->next = drv->free_aiocb;
 25.1401 +    drv->free_aiocb = acb;
 25.1402 +}
 25.1403 +
 25.1404 +/**************************************************************/
 25.1405 +/* removable device support */
 25.1406 +
 25.1407 +/**
 25.1408 + * Return TRUE if the media is present
 25.1409 + */
 25.1410 +int bdrv_is_inserted(BlockDriverState *bs)
 25.1411 +{
 25.1412 +    BlockDriver *drv = bs->drv;
 25.1413 +    int ret;
 25.1414 +    if (!drv)
 25.1415 +        return 0;
 25.1416 +    if (!drv->bdrv_is_inserted)
 25.1417 +        return 1;
 25.1418 +    ret = drv->bdrv_is_inserted(bs);
 25.1419 +    return ret;
 25.1420 +}
 25.1421 +
 25.1422 +/**
 25.1423 + * Return TRUE if the media changed since the last call to this
 25.1424 + * function. It is currently only used for floppy disks 
 25.1425 + */
 25.1426 +int bdrv_media_changed(BlockDriverState *bs)
 25.1427 +{
 25.1428 +    BlockDriver *drv = bs->drv;
 25.1429 +    int ret;
 25.1430 +
 25.1431 +    if (!drv || !drv->bdrv_media_changed)
 25.1432 +        ret = -ENOTSUP;
 25.1433 +    else
 25.1434 +        ret = drv->bdrv_media_changed(bs);
 25.1435 +    if (ret == -ENOTSUP)
 25.1436 +        ret = bs->media_changed;
 25.1437 +    bs->media_changed = 0;
 25.1438 +    return ret;
 25.1439 +}
 25.1440 +
 25.1441 +/**
 25.1442 + * If eject_flag is TRUE, eject the media. Otherwise, close the tray
 25.1443 + */
 25.1444 +void bdrv_eject(BlockDriverState *bs, int eject_flag)
 25.1445 +{
 25.1446 +    BlockDriver *drv = bs->drv;
 25.1447 +    int ret;
 25.1448 +
 25.1449 +    if (!drv || !drv->bdrv_eject) {
 25.1450 +        ret = -ENOTSUP;
 25.1451 +    } else {
 25.1452 +        ret = drv->bdrv_eject(bs, eject_flag);
 25.1453 +    }
 25.1454 +    if (ret == -ENOTSUP) {
 25.1455 +        if (eject_flag)
 25.1456 +            bdrv_close(bs);
 25.1457 +    }
 25.1458 +}
 25.1459 +
 25.1460 +int bdrv_is_locked(BlockDriverState *bs)
 25.1461 +{
 25.1462 +    return bs->locked;
 25.1463 +}
 25.1464 +
 25.1465 +/**
 25.1466 + * Lock or unlock the media (if it is locked, the user won't be able
 25.1467 + * to eject it manually).
 25.1468 + */
 25.1469 +void bdrv_set_locked(BlockDriverState *bs, int locked)
 25.1470 +{
 25.1471 +    BlockDriver *drv = bs->drv;
 25.1472 +
 25.1473 +    bs->locked = locked;
 25.1474 +    if (drv && drv->bdrv_set_locked) {
 25.1475 +        drv->bdrv_set_locked(bs, locked);
 25.1476 +    }
 25.1477 +}
    26.1 --- a/tools/ioemu/block_int.h	Tue May 08 10:38:06 2007 +0100
    26.2 +++ b/tools/ioemu/block_int.h	Wed May 09 14:17:15 2007 +0100
    26.3 @@ -28,7 +28,7 @@ struct BlockDriver {
    26.4      const char *format_name;
    26.5      int instance_size;
    26.6      int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename);
    26.7 -    int (*bdrv_open)(BlockDriverState *bs, const char *filename);
    26.8 +    int (*bdrv_open)(BlockDriverState *bs, const char *filename, int flags);
    26.9      int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num, 
   26.10                       uint8_t *buf, int nb_sectors);
   26.11      int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num, 
   26.12 @@ -41,13 +41,49 @@ struct BlockDriver {
   26.13                               int nb_sectors, int *pnum);
   26.14      int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
   26.15      int (*bdrv_make_empty)(BlockDriverState *bs);
   26.16 +    /* aio */
   26.17 +    BlockDriverAIOCB *(*bdrv_aio_read)(BlockDriverState *bs,
   26.18 +        int64_t sector_num, uint8_t *buf, int nb_sectors,
   26.19 +        BlockDriverCompletionFunc *cb, void *opaque);
   26.20 +    BlockDriverAIOCB *(*bdrv_aio_write)(BlockDriverState *bs,
   26.21 +        int64_t sector_num, const uint8_t *buf, int nb_sectors,
   26.22 +        BlockDriverCompletionFunc *cb, void *opaque);
   26.23 +    void (*bdrv_aio_cancel)(BlockDriverAIOCB *acb);
   26.24 +    int aiocb_size;
   26.25 +
   26.26 +    const char *protocol_name;
   26.27 +    int (*bdrv_pread)(BlockDriverState *bs, int64_t offset, 
   26.28 +                      uint8_t *buf, int count);
   26.29 +    int (*bdrv_pwrite)(BlockDriverState *bs, int64_t offset, 
   26.30 +                       const uint8_t *buf, int count);
   26.31 +    int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset);
   26.32 +    int64_t (*bdrv_getlength)(BlockDriverState *bs);
   26.33 +    int (*bdrv_write_compressed)(BlockDriverState *bs, int64_t sector_num, 
   26.34 +                                 const uint8_t *buf, int nb_sectors);
   26.35 +
   26.36 +    int (*bdrv_snapshot_create)(BlockDriverState *bs, 
   26.37 +                                QEMUSnapshotInfo *sn_info);
   26.38 +    int (*bdrv_snapshot_goto)(BlockDriverState *bs, 
   26.39 +                              const char *snapshot_id);
   26.40 +    int (*bdrv_snapshot_delete)(BlockDriverState *bs, const char *snapshot_id);
   26.41 +    int (*bdrv_snapshot_list)(BlockDriverState *bs, 
   26.42 +                              QEMUSnapshotInfo **psn_info);
   26.43 +    int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi);
   26.44 +
   26.45 +    /* removable device specific */
   26.46 +    int (*bdrv_is_inserted)(BlockDriverState *bs);
   26.47 +    int (*bdrv_media_changed)(BlockDriverState *bs);
   26.48 +    int (*bdrv_eject)(BlockDriverState *bs, int eject_flag);
   26.49 +    int (*bdrv_set_locked)(BlockDriverState *bs, int locked);
   26.50 +    
   26.51 +    BlockDriverAIOCB *free_aiocb;
   26.52      struct BlockDriver *next;
   26.53  };
   26.54  
   26.55  struct BlockDriverState {
   26.56 -    int64_t total_sectors;
   26.57 +    int64_t total_sectors; /* if we are reading a disk image, give its
   26.58 +                              size in sectors */
   26.59      int read_only; /* if true, the media is read only */
   26.60 -    int inserted; /* if true, the media is present */
   26.61      int removable; /* if true, the media can be removed */
   26.62      int locked;    /* if true, the media cannot temporarily be ejected */
   26.63      int encrypted; /* if true, the media is encrypted */
   26.64 @@ -55,7 +91,7 @@ struct BlockDriverState {
   26.65      void (*change_cb)(void *opaque);
   26.66      void *change_opaque;
   26.67  
   26.68 -    BlockDriver *drv;
   26.69 +    BlockDriver *drv; /* NULL means no media */
   26.70      void *opaque;
   26.71  
   26.72      int boot_sector_enabled;
   26.73 @@ -65,8 +101,12 @@ struct BlockDriverState {
   26.74      char backing_file[1024]; /* if non zero, the image is a diff of
   26.75                                  this file image */
   26.76      int is_temporary;
   26.77 -    
   26.78 +    int media_changed;
   26.79 +
   26.80      BlockDriverState *backing_hd;
   26.81 +    /* async read/write emulation */
   26.82 +
   26.83 +    void *sync_aiocb;
   26.84      
   26.85      /* NOTE: the following infos are only hints for real hardware
   26.86         drivers. They are not used by the block driver */
   26.87 @@ -76,6 +116,17 @@ struct BlockDriverState {
   26.88      BlockDriverState *next;
   26.89  };
   26.90  
   26.91 +struct BlockDriverAIOCB {
   26.92 +    BlockDriverState *bs;
   26.93 +    BlockDriverCompletionFunc *cb;
   26.94 +    void *opaque;
   26.95 +    BlockDriverAIOCB *next;
   26.96 +};
   26.97 +
   26.98  void get_tmp_filename(char *filename, int size);
   26.99  
  26.100 +void *qemu_aio_get(BlockDriverState *bs, BlockDriverCompletionFunc *cb,
  26.101 +                   void *opaque);
  26.102 +void qemu_aio_release(void *p);
  26.103 +
  26.104  #endif /* BLOCK_INT_H */
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/tools/ioemu/check_ops.sh	Wed May 09 14:17:15 2007 +0100
    27.3 @@ -0,0 +1,47 @@
    27.4 +#! /bin/sh
    27.5 +# Script to check for duplicate function prologues in op.o
    27.6 +# Typically this indicates missing FORCE_RET();
    27.7 +# This script does not detect other errors that may be present.
    27.8 +
    27.9 +# Usage: check_ops.sh [-m machine] [op.o]
   27.10 +#   machine and op.o are guessed if not specified.
   27.11 +
   27.12 +if [ "x$1" = "x-m" ]; then
   27.13 +  machine=$2
   27.14 +  shift 2
   27.15 +else
   27.16 +  machine=`uname -m`
   27.17 +fi
   27.18 +if [ -z "$1" ]; then
   27.19 +  for f in `find . -name op.o`; do
   27.20 +    /bin/sh "$0" -m $machine $f
   27.21 +  done
   27.22 +  exit 0
   27.23 +fi
   27.24 +
   27.25 +case $machine in
   27.26 +  i?86)
   27.27 +    ret='\tret'
   27.28 +    ;;
   27.29 +  x86_64)
   27.30 +    ret='\tretq'
   27.31 +    ;;
   27.32 +  arm)
   27.33 +    ret='\tldm.*pc'
   27.34 +    ;;
   27.35 +  ppc* | powerpc*)
   27.36 +    ret='\tblr'
   27.37 +    ;;
   27.38 +  mips*)
   27.39 +    ret='\tjr.*ra'
   27.40 +    ;;
   27.41 +  *)
   27.42 +    echo "Unknown machine `uname -m`"
   27.43 +    ;;
   27.44 +esac
   27.45 +echo $1
   27.46 +# op_exit_tb causes false positives on some hosts.
   27.47 +${CROSS}objdump -dr $1  | \
   27.48 +  sed -e '/>:$\|'"$ret"'/!d' -e 's/.*<\(.*\)>:/~\1:/' -e 's/.*'"$ret"'.*/!/' | \
   27.49 +  sed -e ':1;N;s/\n//;t1' | sed -e 's/~/\n/g' | grep -v '^op_exit_tb' | \
   27.50 +  grep '^op_.*!!'
    28.1 --- a/tools/ioemu/configure	Tue May 08 10:38:06 2007 +0100
    28.2 +++ b/tools/ioemu/configure	Wed May 09 14:17:15 2007 +0100
    28.3 @@ -22,6 +22,8 @@ static="no"
    28.4  libdir="lib"
    28.5  cross_prefix=""
    28.6  cc="gcc"
    28.7 +gcc3_search="yes"
    28.8 +gcc3_list="gcc-3.4 gcc34 gcc-3.3 gcc33 gcc-3.2 gcc32"
    28.9  host_cc="gcc"
   28.10  ar="ar"
   28.11  make="make"
   28.12 @@ -89,14 +91,13 @@ bsd="no"
   28.13  linux="no"
   28.14  kqemu="no"
   28.15  profiler="no"
   28.16 -kernel_path=""
   28.17  cocoa="no"
   28.18  check_gfx="yes"
   28.19  check_gcc="no"
   28.20  softmmu="yes"
   28.21 -user="no"
   28.22 +linux_user="no"
   28.23 +darwin_user="no"
   28.24  build_docs="no"
   28.25 -build_acpi_tables="no"
   28.26  uname_release=""
   28.27  
   28.28  # OS specific
   28.29 @@ -104,7 +105,7 @@ targetos=`uname -s`
   28.30  case $targetos in
   28.31  CYGWIN*)
   28.32  mingw32="yes"
   28.33 -CFLAGS="-O2 -mno-cygwin"
   28.34 +OS_CFLAGS="-mno-cygwin"
   28.35  ;;
   28.36  MINGW32*)
   28.37  mingw32="yes"
   28.38 @@ -127,6 +128,10 @@ oss="yes"
   28.39  Darwin)
   28.40  bsd="yes"
   28.41  darwin="yes"
   28.42 +darwin_user="yes"
   28.43 +cocoa="yes"
   28.44 +coreaudio="yes"
   28.45 +OS_CFLAGS="-mdynamic-no-pic"
   28.46  ;;
   28.47  SunOS)
   28.48  solaris="yes"
   28.49 @@ -134,7 +139,7 @@ solaris="yes"
   28.50  *)
   28.51  oss="yes"
   28.52  linux="yes"
   28.53 -user="yes"
   28.54 +linux_user="yes"
   28.55  if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
   28.56      kqemu="yes"
   28.57  fi
   28.58 @@ -151,6 +156,11 @@ if [ "$solaris" = "yes" ] ; then
   28.59      make="gmake"
   28.60      install="ginstall"
   28.61      solarisrev=`uname -r | cut -f2 -d.`
   28.62 +    if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
   28.63 +        if test "$solarisrev" -gt 10 ; then
   28.64 +            kqemu="yes"
   28.65 +        fi
   28.66 +    fi
   28.67  fi
   28.68  
   28.69  # find source path
   28.70 @@ -181,6 +191,7 @@ for opt do
   28.71    --cross-prefix=*) cross_prefix="$optarg"
   28.72    ;;
   28.73    --cc=*) cc="$optarg"
   28.74 +  gcc3_search="no"
   28.75    ;;
   28.76    --host-cc=*) host_cc="$optarg"
   28.77    ;;
   28.78 @@ -224,8 +235,6 @@ for opt do
   28.79    ;;
   28.80    --enable-profiler) profiler="yes"
   28.81    ;;
   28.82 -  --kernel-path=*) kernel_path="$optarg"
   28.83 -  ;;
   28.84    --enable-cocoa) cocoa="yes" ; coreaudio="yes" ; sdl="no"
   28.85    ;;
   28.86    --disable-gcc-check) check_gcc="no"
   28.87 @@ -234,21 +243,22 @@ for opt do
   28.88    ;;
   28.89    --enable-system) softmmu="yes"
   28.90    ;;
   28.91 -  --disable-user) user="no"
   28.92 +  --disable-linux-user) linux_user="no"
   28.93 +  ;;
   28.94 +  --enable-linux-user) linux_user="yes"
   28.95    ;;
   28.96 -  --enable-user) user="yes"
   28.97 +  --disable-darwin-user) darwin_user="no"
   28.98 +  ;;
   28.99 +  --enable-darwin-user) darwin_user="yes"
  28.100    ;;
  28.101    --enable-uname-release=*) uname_release="$optarg"
  28.102    ;;
  28.103 -  --enable-iasl) build_acpi_tables="yes"
  28.104 -  ;;
  28.105    esac
  28.106  done
  28.107  
  28.108 -# Checking for CFLAGS
  28.109 -if test -z "$CFLAGS"; then
  28.110 -    CFLAGS="-O2"
  28.111 -fi
  28.112 +# default flags for all hosts
  28.113 +CFLAGS="$CFLAGS -Wall -O2 -g -fno-strict-aliasing"
  28.114 +LDFLAGS="$LDFLAGS -g"
  28.115  
  28.116  if test x"$show_help" = x"yes" ; then
  28.117  cat << EOF
  28.118 @@ -266,7 +276,6 @@ echo "  --target-list=LIST       set tar
  28.119  echo ""
  28.120  echo "kqemu kernel acceleration support:"
  28.121  echo "  --disable-kqemu          disable kqemu support"
  28.122 -echo "  --kernel-path=PATH       set the kernel path (configure probes it)"
  28.123  echo ""
  28.124  echo "Advanced options (experts only):"
  28.125  echo "  --source-path=PATH       path of source code [$source_path]"
  28.126 @@ -285,14 +294,15 @@ echo "  --enable-fmod            enable 
  28.127  echo "  --enabled-dsound         enable DirectSound audio driver"
  28.128  echo "  --enable-system          enable all system emulation targets"
  28.129  echo "  --disable-system         disable all system emulation targets"
  28.130 -echo "  --enable-user            enable all linux usermode emulation targets"
  28.131 -echo "  --disable-user           disable all linux usermode emulation targets"
  28.132 +echo "  --enable-linux-user      enable all linux usermode emulation targets"
  28.133 +echo "  --disable-linux-user     disable all linux usermode emulation targets"
  28.134 +echo "  --enable-darwin-user     enable all darwin usermode emulation targets"
  28.135 +echo "  --disable-darwin-user    disable all darwin usermode emulation targets"
  28.136  echo "  --fmod-lib               path to FMOD library"
  28.137  echo "  --fmod-inc               path to FMOD includes"
  28.138  echo "  --enable-uname-release=R Return R for uname -r in usermode emulation"
  28.139 -echo "  --enable-iasl            compilation of ACPI tables with the IASL compiler"
  28.140  echo ""
  28.141 -echo "NOTE: The object files are build at the place where configure is launched"
  28.142 +echo "NOTE: The object files are built at the place where configure is launched"
  28.143  exit 1
  28.144  fi
  28.145  
  28.146 @@ -321,6 +331,45 @@ if test "$mingw32" = "yes" ; then
  28.147      fi
  28.148  fi
  28.149  
  28.150 +# Check for gcc4, error if pre-gcc4 
  28.151 +if test "$check_gcc" = "yes" ; then
  28.152 +    cat > $TMPC <<EOF
  28.153 +#if __GNUC__ < 4
  28.154 +#error gcc3
  28.155 +#endif
  28.156 +int main(){return 0;}
  28.157 +EOF
  28.158 +    check_cc() {
  28.159 +	which "$1" >&/dev/null
  28.160 +	return $?
  28.161 +    }
  28.162 +
  28.163 +    if "$cc" -o $TMPE $TMPC 2>/dev/null ; then
  28.164 +	echo "WARNING: \"$cc\" looks like gcc 4.x"
  28.165 +	found_compat_cc="no"
  28.166 +	if test "$gcc3_search" = "yes" ; then
  28.167 +	    echo "Looking for gcc 3.x"
  28.168 +	    for compat_cc in $gcc3_list ; do
  28.169 +		if check_cc "$compat_cc" ; then
  28.170 +		    echo "Found \"$compat_cc\""
  28.171 +		    cc="$compat_cc"
  28.172 +		    found_compat_cc="yes"
  28.173 +		    break
  28.174 +		fi
  28.175 +	    done
  28.176 +	    if test "$found_compat_cc" = "no" ; then
  28.177 +		echo "gcc 3.x not found!"
  28.178 +	    fi
  28.179 +	fi
  28.180 +	if test "$found_compat_cc" = "no" ; then
  28.181 +	    echo "QEMU is known to have problems when compiled with gcc 4.x"
  28.182 +	    echo "It is recommended that you use gcc 3.x to build QEMU"
  28.183 +	    echo "To use this compiler anyway, configure with --disable-gcc-check"
  28.184 +	    exit 1;
  28.185 +	fi
  28.186 +    fi
  28.187 +fi
  28.188 +
  28.189  #
  28.190  # Solaris specific configure tool chain decisions
  28.191  #
  28.192 @@ -368,8 +417,12 @@ if test -z "$target_list" ; then
  28.193          target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu arm-softmmu"
  28.194      fi
  28.195  # the following are Linux specific
  28.196 -    if [ "$user" = "yes" ] ; then
  28.197 -        target_list="i386-user arm-user armeb-user sparc-user ppc-user mips-user mipsel-user $target_list"
  28.198 +    if [ "$linux_user" = "yes" ] ; then
  28.199 +        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"
  28.200 +    fi
  28.201 +# the following are Darwin specific
  28.202 +    if [ "$darwin_user" = "yes" ] ; then
  28.203 +        target_list="i386-darwin-user ppc-darwin-user $target_list"
  28.204      fi
  28.205  # the i386-dm target
  28.206      target_list="i386-dm"
  28.207 @@ -427,23 +480,6 @@ if $cc -fno-reorder-blocks -fno-optimize
  28.208     have_gcc3_options="yes"
  28.209  fi
  28.210  
  28.211 -# Check for gcc4, error if pre-gcc4 
  28.212 -if test "$check_gcc" = "yes" ; then
  28.213 -    cat > $TMPC <<EOF
  28.214 -#if __GNUC__ < 4
  28.215 -#error gcc3
  28.216 -#endif
  28.217 -int main(){return 0;}
  28.218 -EOF
  28.219 -    if $cc -o $TMPO $TMPC 2>/dev/null ; then
  28.220 -        echo "ERROR: \"$cc\" looks like gcc 4.x"
  28.221 -        echo "QEMU is known to have problems when compiled with gcc 4.x"
  28.222 -        echo "It is recommended that you use gcc 3.x to build QEMU"
  28.223 -        echo "To use this compiler anyway, configure with --disable-gcc-check"
  28.224 -        exit 1;
  28.225 -    fi
  28.226 -fi
  28.227 -
  28.228  ##########################################
  28.229  # SDL probe
  28.230  
  28.231 @@ -472,7 +508,9 @@ if $cc -o $TMPE `$sdl_config --cflags 2>
  28.232  if test "$_sdlversion" -lt 121 ; then
  28.233  sdl_too_old=yes
  28.234  else
  28.235 -sdl=yes
  28.236 + if test "$cocoa" = "no" ; then
  28.237 +   sdl=yes
  28.238 + fi
  28.239  fi
  28.240  
  28.241  # static link with sdl ?
  28.242 @@ -493,8 +531,34 @@ fi # static link
  28.243  fi # sdl compile test
  28.244  
  28.245  fi # cross compilation
  28.246 +
  28.247 +else
  28.248 + # Make sure to disable cocoa if sdl was set
  28.249 + if test "$sdl" = "yes" ; then
  28.250 +   cocoa="no"
  28.251 +   coreaudio="no"
  28.252 + fi
  28.253  fi # -z $sdl
  28.254  
  28.255 +##########################################
  28.256 +# alsa sound support libraries
  28.257 +
  28.258 +if test "$alsa" = "yes" ; then
  28.259 +  cat > $TMPC << EOF
  28.260 +#include <alsa/asoundlib.h>
  28.261 +int main(void) { snd_pcm_t **handle; return snd_pcm_close(*handle); }
  28.262 +EOF
  28.263 +  if $cc -o $TMPE $TMPC -lasound 2> /dev/null ; then
  28.264 +    :
  28.265 +  else
  28.266 +    echo
  28.267 +    echo "Error: Could not find alsa"
  28.268 +    echo "Make sure to have the alsa libs and headers installed."
  28.269 +    echo
  28.270 +    exit 1
  28.271 +  fi
  28.272 +fi
  28.273 +
  28.274  # Check if tools are available to build documentation.
  28.275  if [ -x "`which texi2html`" ] && [ -x "`which pod2man`" ]; then
  28.276    build_docs="yes"
  28.277 @@ -600,6 +664,7 @@ fi
  28.278  echo "HOST_CC=$host_cc" >> $config_mak
  28.279  echo "AR=$ar" >> $config_mak
  28.280  echo "STRIP=$strip -s -R .comment -R .note" >> $config_mak
  28.281 +echo "OS_CFLAGS=$OS_CFLAGS" >> $config_mak
  28.282  echo "CFLAGS=$CFLAGS" >> $config_mak
  28.283  echo "LDFLAGS=$LDFLAGS" >> $config_mak
  28.284  echo "EXESUF=$EXESUF" >> $config_mak
  28.285 @@ -719,9 +784,6 @@ echo "TARGET_DIRS=$target_list" >> $conf
  28.286  if [ "$build_docs" = "yes" ] ; then
  28.287    echo "BUILD_DOCS=yes" >> $config_mak
  28.288  fi
  28.289 -if [ "$build_acpi_tables" = "yes" ] ; then
  28.290 -  echo "BUILD_ACPI_TABLES=yes" >> $config_mak
  28.291 -fi
  28.292  
  28.293  # XXX: suppress that
  28.294  if [ "$bsd" = "yes" ] ; then
  28.295 @@ -745,6 +807,7 @@ target_bigendian="no"
  28.296  [ "$target_cpu" = "ppc64" ] && target_bigendian=yes
  28.297  [ "$target_cpu" = "mips" ] && target_bigendian=yes
  28.298  [ "$target_cpu" = "sh4eb" ] && target_bigendian=yes
  28.299 +[ "$target_cpu" = "m68k" ] && target_bigendian=yes
  28.300  target_softmmu="no"
  28.301  if expr $target : '.*-softmmu' > /dev/null ; then
  28.302    target_softmmu="yes"
  28.303 @@ -756,11 +819,21 @@ if expr $target : '.*-user' > /dev/null 
  28.304    target_user_only="yes"
  28.305  fi
  28.306  
  28.307 +target_linux_user="no"
  28.308 +if expr $target : '.*-linux-user' > /dev/null ; then
  28.309 +  target_linux_user="yes"
  28.310 +fi
  28.311 +
  28.312 +target_darwin_user="no"
  28.313 +if expr $target : '.*-darwin-user' > /dev/null ; then
  28.314 +  target_darwin_user="yes"
  28.315 +fi
  28.316 +
  28.317  #echo "Creating $config_mak, $config_h and $target_dir/Makefile"
  28.318  
  28.319  mkdir -p $target_dir
  28.320  mkdir -p $target_dir/fpu
  28.321 -if test "$target" = "arm-user" -o "$target" = "armeb-user" ; then
  28.322 +if test "$target" = "arm-linux-user" -o "$target" = "armeb-linux-user" ; then
  28.323    mkdir -p $target_dir/nwfpe
  28.324  fi
  28.325  if test "$target_user_only" = "no" ; then
  28.326 @@ -840,6 +913,11 @@ elif test "$target_cpu" = "sh4" -o "$tar
  28.327    echo "#define TARGET_ARCH \"sh4\"" >> $config_h
  28.328    echo "#define TARGET_SH4 1" >> $config_h
  28.329    bflt="yes"
  28.330 +elif test "$target_cpu" = "m68k" ; then
  28.331 +  echo "TARGET_ARCH=m68k" >> $config_mak
  28.332 +  echo "#define TARGET_ARCH \"m68k\"" >> $config_h
  28.333 +  echo "#define TARGET_M68K 1" >> $config_h
  28.334 +  bflt="yes"
  28.335  else
  28.336    echo "Unsupported target CPU"
  28.337    exit 1
  28.338 @@ -856,12 +934,19 @@ if test "$target_user_only" = "yes" ; th
  28.339    echo "CONFIG_USER_ONLY=yes" >> $config_mak
  28.340    echo "#define CONFIG_USER_ONLY 1" >> $config_h
  28.341  fi
  28.342 -
  28.343 +if test "$target_linux_user" = "yes" ; then
  28.344 +  echo "CONFIG_LINUX_USER=yes" >> $config_mak
  28.345 +  echo "#define CONFIG_LINUX_USER 1" >> $config_h
  28.346 +fi
  28.347 +if test "$target_darwin_user" = "yes" ; then
  28.348 +  echo "CONFIG_DARWIN_USER=yes" >> $config_mak
  28.349 +  echo "#define CONFIG_DARWIN_USER 1" >> $config_h
  28.350 +fi
  28.351  if expr $target : '.*-dm' > /dev/null ; then
  28.352    echo "#define CONFIG_DM 1" >> $config_h
  28.353  fi
  28.354  
  28.355 -if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" -o "$target_cpu" = "sparc" -o "$target_cpu" = "sparc64"; then
  28.356 +if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" -o "$target_cpu" = "sparc" -o "$target_cpu" = "sparc64" -o "$target_cpu" = "m68k"; then
  28.357    echo "CONFIG_SOFTFLOAT=yes" >> $config_mak
  28.358    echo "#define CONFIG_SOFTFLOAT 1" >> $config_h
  28.359  fi
    29.1 --- a/tools/ioemu/console.c	Tue May 08 10:38:06 2007 +0100
    29.2 +++ b/tools/ioemu/console.c	Wed May 09 14:17:15 2007 +0100
    29.3 @@ -121,6 +121,7 @@ struct TextConsole {
    29.4      int total_height;
    29.5      int backscroll_height;
    29.6      int x, y;
    29.7 +    int x_saved, y_saved;
    29.8      int y_displayed;
    29.9      int y_base;
   29.10      TextAttributes t_attrib_default; /* default text attributes */
   29.11 @@ -131,10 +132,7 @@ struct TextConsole {
   29.12      int esc_params[MAX_ESC_PARAMS];
   29.13      int nb_esc_params;
   29.14  
   29.15 -    /* kbd read handler */
   29.16 -    IOCanRWHandler *fd_can_read; 
   29.17 -    IOReadHandler *fd_read;
   29.18 -    void *fd_opaque;
   29.19 +    CharDriverState *chr;
   29.20      /* fifo for key pressed */
   29.21      QEMUFIFO out_fifo;
   29.22      uint8_t out_fifo_buf[16];
   29.23 @@ -147,7 +145,7 @@ static int nb_consoles = 0;
   29.24  
   29.25  void vga_hw_update(void)
   29.26  {
   29.27 -    if (active_console->hw_update)
   29.28 +    if (active_console && active_console->hw_update)
   29.29          active_console->hw_update(active_console->hw);
   29.30  }
   29.31  
   29.32 @@ -659,10 +657,6 @@ static void console_handle_escape(TextCo
   29.33  {
   29.34      int i;
   29.35  
   29.36 -    if (s->nb_esc_params == 0) { /* ESC[m sets all attributes to default */
   29.37 -        s->t_attrib = s->t_attrib_default;
   29.38 -        return;
   29.39 -    }
   29.40      for (i=0; i<s->nb_esc_params; i++) {
   29.41          switch (s->esc_params[i]) {
   29.42              case 0: /* reset all console attributes to default */
   29.43 @@ -752,10 +746,21 @@ static void console_handle_escape(TextCo
   29.44      }
   29.45  }
   29.46  
   29.47 +static void console_clear_xy(TextConsole *s, int x, int y)
   29.48 +{
   29.49 +    int y1 = (s->y_base + y) % s->total_height;
   29.50 +    TextCell *c = &s->cells[y1 * s->width + x];
   29.51 +    c->ch = ' ';
   29.52 +    c->t_attrib = s->t_attrib_default;
   29.53 +    c++;
   29.54 +    update_xy(s, x, y);
   29.55 +}
   29.56 +
   29.57  static void console_putchar(TextConsole *s, int ch)
   29.58  {
   29.59      TextCell *c;
   29.60 -    int y1, i, x;
   29.61 +    int y1, i;
   29.62 +    int x, y;
   29.63  
   29.64      switch(s->state) {
   29.65      case TTY_STATE_NORM:
   29.66 @@ -781,20 +786,31 @@ static void console_putchar(TextConsole 
   29.67          case '\a':  /* alert aka. bell */
   29.68              /* TODO: has to be implemented */
   29.69              break;
   29.70 +        case 14:
   29.71 +            /* SI (shift in), character set 0 (ignored) */
   29.72 +            break;
   29.73 +        case 15:
   29.74 +            /* SO (shift out), character set 1 (ignored) */
   29.75 +            break;
   29.76          case 27:    /* esc (introducing an escape sequence) */
   29.77              s->state = TTY_STATE_ESC;
   29.78              break;
   29.79          default:
   29.80 +            if (s->x >= s->width - 1) {
   29.81 +                break;
   29.82 +            }
   29.83              y1 = (s->y_base + s->y) % s->total_height;
   29.84              c = &s->cells[y1 * s->width + s->x];
   29.85              c->ch = ch;
   29.86              c->t_attrib = s->t_attrib;
   29.87              update_xy(s, s->x, s->y);
   29.88              s->x++;
   29.89 +#if 0 /* line wrap disabled */
   29.90              if (s->x >= s->width) {
   29.91                  s->x = 0;
   29.92                  console_put_lf(s);
   29.93              }
   29.94 +#endif
   29.95              break;
   29.96          }
   29.97          break;
   29.98 @@ -818,32 +834,150 @@ static void console_putchar(TextConsole 
   29.99              s->nb_esc_params++;
  29.100              if (ch == ';')
  29.101                  break;
  29.102 +#ifdef DEBUG_CONSOLE
  29.103 +            fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
  29.104 +                    s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
  29.105 +#endif
  29.106              s->state = TTY_STATE_NORM;
  29.107              switch(ch) {
  29.108 -            case 'D':
  29.109 -                if (s->x > 0)
  29.110 -                    s->x--;
  29.111 +            case 'A':
  29.112 +                /* move cursor up */
  29.113 +                if (s->esc_params[0] == 0) {
  29.114 +                    s->esc_params[0] = 1;
  29.115 +                }
  29.116 +                s->y -= s->esc_params[0];
  29.117 +                if (s->y < 0) {
  29.118 +                    s->y = 0;
  29.119 +                }
  29.120 +                break;
  29.121 +            case 'B':
  29.122 +                /* move cursor down */
  29.123 +                if (s->esc_params[0] == 0) {
  29.124 +                    s->esc_params[0] = 1;
  29.125 +                }
  29.126 +                s->y += s->esc_params[0];
  29.127 +                if (s->y >= s->height) {
  29.128 +                    s->y = s->height - 1;
  29.129 +                }
  29.130                  break;
  29.131              case 'C':
  29.132 -                if (s->x < (s->width - 1))
  29.133 -                    s->x++;
  29.134 +                /* move cursor right */
  29.135 +                if (s->esc_params[0] == 0) {
  29.136 +                    s->esc_params[0] = 1;
  29.137 +                }
  29.138 +                s->x += s->esc_params[0];
  29.139 +                if (s->x >= s->width) {
  29.140 +                    s->x = s->width - 1;
  29.141 +                }
  29.142                  break;
  29.143 -            case 'K':
  29.144 -                /* clear to eol */
  29.145 -                y1 = (s->y_base + s->y) % s->total_height;
  29.146 -                for(x = s->x; x < s->width; x++) {
  29.147 -                    c = &s->cells[y1 * s->width + x];
  29.148 -                    c->ch = ' ';
  29.149 -                    c->t_attrib = s->t_attrib_default;
  29.150 -                    c++;
  29.151 -                    update_xy(s, x, s->y);
  29.152 +            case 'D':
  29.153 +                /* move cursor left */
  29.154 +                if (s->esc_params[0] == 0) {
  29.155 +                    s->esc_params[0] = 1;
  29.156 +                }
  29.157 +                s->x -= s->esc_params[0];
  29.158 +                if (s->x < 0) {
  29.159 +                    s->x = 0;
  29.160 +                }
  29.161 +                break;
  29.162 +            case 'G':
  29.163 +                /* move cursor to column */
  29.164 +                s->x = s->esc_params[0] - 1;
  29.165 +                if (s->x < 0) {
  29.166 +                    s->x = 0;
  29.167 +                }
  29.168 +                break;
  29.169 +            case 'f':
  29.170 +            case 'H':
  29.171 +                /* move cursor to row, column */
  29.172 +                s->x = s->esc_params[1] - 1;
  29.173 +                if (s->x < 0) {
  29.174 +                    s->x = 0;
  29.175 +                }
  29.176 +                s->y = s->esc_params[0] - 1;
  29.177 +                if (s->y < 0) {
  29.178 +                    s->y = 0;
  29.179                  }
  29.180                  break;
  29.181 -            default:
  29.182 +            case 'J':
  29.183 +                switch (s->esc_params[0]) {
  29.184 +                case 0:
  29.185 +                    /* clear to end of screen */
  29.186 +                    for (y = s->y; y < s->height; y++) {
  29.187 +                        for (x = 0; x < s->width; x++) {
  29.188 +                            if (y == s->y && x < s->x) {
  29.189 +                                continue;
  29.190 +                            }
  29.191 +                            console_clear_xy(s, x, y);
  29.192 +                        }
  29.193 +                    }
  29.194 +                    break;
  29.195 +                case 1:
  29.196 +                    /* clear from beginning of screen */
  29.197 +                    for (y = 0; y <= s->y; y++) {
  29.198 +                        for (x = 0; x < s->width; x++) {
  29.199 +                            if (y == s->y && x > s->x) {
  29.200 +                                break;
  29.201 +                            }
  29.202 +                            console_clear_xy(s, x, y);
  29.203 +                        }
  29.204 +                    }
  29.205 +                    break;
  29.206 +                case 2:
  29.207 +                    /* clear entire screen */
  29.208 +                    for (y = 0; y <= s->height; y++) {
  29.209 +                        for (x = 0; x < s->width; x++) {
  29.210 +                            console_clear_xy(s, x, y);
  29.211 +                        }
  29.212 +                    }
  29.213 +                break;
  29.214 +                }
  29.215 +            case 'K':
  29.216 +                switch (s->esc_params[0]) {
  29.217 +                case 0:
  29.218 +                /* clear to eol */
  29.219 +                for(x = s->x; x < s->width; x++) {
  29.220 +                        console_clear_xy(s, x, s->y);
  29.221 +                }
  29.222 +                break;
  29.223 +                case 1:
  29.224 +                    /* clear from beginning of line */
  29.225 +                    for (x = 0; x <= s->x; x++) {
  29.226 +                        console_clear_xy(s, x, s->y);
  29.227 +                    }
  29.228 +                    break;
  29.229 +                case 2:
  29.230 +                    /* clear entire line */
  29.231 +                    for(x = 0; x < s->width; x++) {
  29.232 +                        console_clear_xy(s, x, s->y);
  29.233 +                    }
  29.234                  break;
  29.235              }
  29.236 +                break;
  29.237 +            case 'm':
  29.238              console_handle_escape(s);
  29.239              break;
  29.240 +            case 'n':
  29.241 +                /* report cursor position */
  29.242 +                /* TODO: send ESC[row;colR */
  29.243 +                break;
  29.244 +            case 's':
  29.245 +                /* save cursor position */
  29.246 +                s->x_saved = s->x;
  29.247 +                s->y_saved = s->y;
  29.248 +                break;
  29.249 +            case 'u':
  29.250 +                /* restore cursor position */
  29.251 +                s->x = s->x_saved;
  29.252 +                s->y = s->y_saved;
  29.253 +                break;
  29.254 +            default:
  29.255 +#ifdef DEBUG_CONSOLE
  29.256 +                fprintf(stderr, "unhandled escape character '%c'\n", ch);
  29.257 +#endif
  29.258 +                break;
  29.259 +            }
  29.260 +            break;
  29.261          }
  29.262      }
  29.263  }
  29.264 @@ -884,16 +1018,6 @@ static int console_puts(CharDriverState 
  29.265      return len;
  29.266  }
  29.267  
  29.268 -static void console_chr_add_read_handler(CharDriverState *chr, 
  29.269 -                                         IOCanRWHandler *fd_can_read, 
  29.270 -                                         IOReadHandler *fd_read, void *opaque)
  29.271 -{
  29.272 -    TextConsole *s = chr->opaque;
  29.273 -    s->fd_can_read = fd_can_read;
  29.274 -    s->fd_read = fd_read;
  29.275 -    s->fd_opaque = opaque;
  29.276 -}
  29.277 -
  29.278  static void console_send_event(CharDriverState *chr, int event)
  29.279  {
  29.280      TextConsole *s = chr->opaque;
  29.281 @@ -915,14 +1039,14 @@ static void kbd_send_chars(void *opaque)
  29.282      int len;
  29.283      uint8_t buf[16];
  29.284      
  29.285 -    len = s->fd_can_read(s->fd_opaque);
  29.286 +    len = qemu_chr_can_read(s->chr);
  29.287      if (len > s->out_fifo.count)
  29.288          len = s->out_fifo.count;
  29.289      if (len > 0) {
  29.290          if (len > sizeof(buf))
  29.291              len = sizeof(buf);
  29.292          qemu_fifo_read(&s->out_fifo, buf, len);
  29.293 -        s->fd_read(s->fd_opaque, buf, len);
  29.294 +        qemu_chr_read(s->chr, buf, len);
  29.295      }
  29.296      /* characters are pending: we send them a bit later (XXX:
  29.297         horrible, should change char device API) */
  29.298 @@ -973,7 +1097,7 @@ void kbd_put_keysym(int keysym)
  29.299          } else {
  29.300                  *q++ = keysym;
  29.301          }
  29.302 -        if (s->fd_read) {
  29.303 +        if (s->chr->chr_read) {
  29.304              qemu_fifo_write(&s->out_fifo, buf, q - buf);
  29.305              kbd_send_chars(s);
  29.306          }
  29.307 @@ -1059,9 +1183,9 @@ CharDriverState *text_console_init(Displ
  29.308      }
  29.309      chr->opaque = s;
  29.310      chr->chr_write = console_puts;
  29.311 -    chr->chr_add_read_handler = console_chr_add_read_handler;
  29.312      chr->chr_send_event = console_send_event;
  29.313  
  29.314 +    s->chr = chr;
  29.315      s->out_fifo.buf = s->out_fifo_buf;
  29.316      s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
  29.317      s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
  29.318 @@ -1091,5 +1215,7 @@ CharDriverState *text_console_init(Displ
  29.319      s->t_attrib = s->t_attrib_default;
  29.320      text_console_resize(s);
  29.321  
  29.322 +    qemu_chr_reset(chr);
  29.323 +
  29.324      return chr;
  29.325  }
    30.1 --- a/tools/ioemu/cpu-all.h	Tue May 08 10:38:06 2007 +0100
    30.2 +++ b/tools/ioemu/cpu-all.h	Wed May 09 14:17:15 2007 +0100
    30.3 @@ -727,6 +727,13 @@ void page_unprotect_range(target_ulong d
    30.4  #define cpu_gen_code cpu_ppc_gen_code
    30.5  #define cpu_signal_handler cpu_ppc_signal_handler
    30.6  
    30.7 +#elif defined(TARGET_M68K)
    30.8 +#define CPUState CPUM68KState
    30.9 +#define cpu_init cpu_m68k_init
   30.10 +#define cpu_exec cpu_m68k_exec
   30.11 +#define cpu_gen_code cpu_m68k_gen_code
   30.12 +#define cpu_signal_handler cpu_m68k_signal_handler
   30.13 +
   30.14  #elif defined(TARGET_MIPS)
   30.15  #define CPUState CPUMIPSState
   30.16  #define cpu_init cpu_mips_init
   30.17 @@ -770,6 +777,7 @@ extern int code_copy_enabled;
   30.18  #define CPU_INTERRUPT_TIMER  0x08 /* internal timer exception pending */
   30.19  #define CPU_INTERRUPT_FIQ    0x10 /* Fast interrupt pending.  */
   30.20  #define CPU_INTERRUPT_HALT   0x20 /* CPU halt wanted */
   30.21 +#define CPU_INTERRUPT_SMI    0x40 /* (x86 only) SMI interrupt pending */
   30.22  
   30.23  void cpu_interrupt(CPUState *s, int mask);
   30.24  void cpu_reset_interrupt(CPUState *env, int mask);
   30.25 @@ -889,6 +897,7 @@ typedef uint32_t CPUReadMemoryFunc(void 
   30.26  void cpu_register_physical_memory(target_phys_addr_t start_addr, 
   30.27                                    unsigned long size,
   30.28                                    unsigned long phys_offset);
   30.29 +uint32_t cpu_get_physical_page_desc(target_phys_addr_t addr);
   30.30  int cpu_register_io_memory(int io_index,
   30.31                             CPUReadMemoryFunc **mem_read,
   30.32                             CPUWriteMemoryFunc **mem_write,
   30.33 @@ -1042,6 +1051,15 @@ static inline int64_t cpu_get_real_ticks
   30.34          return rval.i64;
   30.35  #endif
   30.36  }
   30.37 +#else
   30.38 +/* The host CPU doesn't have an easily accessible cycle counter.
   30.39 +   Just return a monotonically increasing vlue.  This will be totally wrong,
   30.40 +   but hopefully better than nothing.  */
   30.41 +static inline int64_t cpu_get_real_ticks (void)
   30.42 +{
   30.43 +    static int64_t ticks = 0;
   30.44 +    return ticks++;
   30.45 +}
   30.46  #endif
   30.47  
   30.48  /* profiling */
    31.1 --- a/tools/ioemu/cpu-defs.h	Tue May 08 10:38:06 2007 +0100
    31.2 +++ b/tools/ioemu/cpu-defs.h	Wed May 09 14:17:15 2007 +0100
    31.3 @@ -80,6 +80,14 @@ typedef unsigned long ram_addr_t;
    31.4  #define TB_JMP_CACHE_BITS 12
    31.5  #define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS)
    31.6  
    31.7 +/* Only the bottom TB_JMP_PAGE_BITS of the jump cache hash bits vary for
    31.8 +   addresses on the same page.  The top bits are the same.  This allows
    31.9 +   TLB invalidation to quickly clear a subset of the hash table.  */
   31.10 +#define TB_JMP_PAGE_BITS (TB_JMP_CACHE_BITS / 2)
   31.11 +#define TB_JMP_PAGE_SIZE (1 << TB_JMP_PAGE_BITS)
   31.12 +#define TB_JMP_ADDR_MASK (TB_JMP_PAGE_SIZE - 1)
   31.13 +#define TB_JMP_PAGE_MASK (TB_JMP_CACHE_SIZE - TB_JMP_PAGE_SIZE)
   31.14 +
   31.15  #define CPU_TLB_BITS 8
   31.16  #define CPU_TLB_SIZE (1 << CPU_TLB_BITS)
   31.17  
    32.1 --- a/tools/ioemu/cpu-exec.c	Tue May 08 10:38:06 2007 +0100
    32.2 +++ b/tools/ioemu/cpu-exec.c	Wed May 09 14:17:15 2007 +0100
    32.3 @@ -40,14 +40,14 @@ int tb_invalidated_flag;
    32.4  //#define DEBUG_EXEC
    32.5  //#define DEBUG_SIGNAL
    32.6  
    32.7 -#if defined(TARGET_ARM) || defined(TARGET_SPARC)
    32.8 +#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_M68K)
    32.9  /* XXX: unify with i386 target */
   32.10  void cpu_loop_exit(void)
   32.11  {
   32.12      longjmp(env->jmp_env, 1);
   32.13  }
   32.14  #endif
   32.15 -#if !(defined(TARGET_SPARC) || defined(TARGET_SH4))
   32.16 +#if !(defined(TARGET_SPARC) || defined(TARGET_SH4) || defined(TARGET_M68K))
   32.17  #define reg_T2
   32.18  #endif
   32.19  
   32.20 @@ -194,6 +194,10 @@ static inline TranslationBlock *tb_find_
   32.21      flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK);
   32.22      cs_base = 0;
   32.23      pc = env->PC;
   32.24 +#elif defined(TARGET_M68K)
   32.25 +    flags = env->fpcr & M68K_FPCR_PREC;
   32.26 +    cs_base = 0;
   32.27 +    pc = env->pc;
   32.28  #elif defined(TARGET_SH4)
   32.29      flags = env->sr & (SR_MD | SR_RB);
   32.30      cs_base = 0;         /* XXXXX */
   32.31 @@ -222,43 +226,16 @@ static inline TranslationBlock *tb_find_
   32.32  
   32.33  int cpu_exec(CPUState *env1)
   32.34  {
   32.35 -    int saved_T0, saved_T1;
   32.36 -#if defined(reg_T2)
   32.37 -    int saved_T2;
   32.38 -#endif
   32.39 -    CPUState *saved_env;
   32.40 -#if defined(TARGET_I386)
   32.41 -#ifdef reg_EAX
   32.42 -    int saved_EAX;
   32.43 -#endif
   32.44 -#ifdef reg_ECX
   32.45 -    int saved_ECX;
   32.46 -#endif
   32.47 -#ifdef reg_EDX
   32.48 -    int saved_EDX;
   32.49 -#endif
   32.50 -#ifdef reg_EBX
   32.51 -    int saved_EBX;
   32.52 -#endif
   32.53 -#ifdef reg_ESP
   32.54 -    int saved_ESP;
   32.55 -#endif
   32.56 -#ifdef reg_EBP
   32.57 -    int saved_EBP;
   32.58 -#endif
   32.59 -#ifdef reg_ESI
   32.60 -    int saved_ESI;
   32.61 -#endif
   32.62 -#ifdef reg_EDI
   32.63 -    int saved_EDI;
   32.64 -#endif
   32.65 -#elif defined(TARGET_SPARC)
   32.66 +#define DECLARE_HOST_REGS 1
   32.67 +#include "hostregs_helper.h"
   32.68 +#if defined(TARGET_SPARC)
   32.69  #if defined(reg_REGWPTR)
   32.70      uint32_t *saved_regwptr;
   32.71  #endif
   32.72  #endif
   32.73  #if defined(__sparc__) && !defined(HOST_SOLARIS)
   32.74 -    int saved_i7, tmp_T0;
   32.75 +    int saved_i7;
   32.76 +    target_ulong tmp_T0;
   32.77  #endif
   32.78      int ret, interrupt_request;
   32.79      void (*gen_func)(void);
   32.80 @@ -320,44 +297,15 @@ int cpu_exec(CPUState *env1)
   32.81      cpu_single_env = env1; 
   32.82  
   32.83      /* first we save global registers */
   32.84 -    saved_env = env;
   32.85 +#define SAVE_HOST_REGS 1
   32.86 +#include "hostregs_helper.h"
   32.87      env = env1;
   32.88 -    saved_T0 = T0;
   32.89 -    saved_T1 = T1;
   32.90 -#if defined(reg_T2)
   32.91 -    saved_T2 = T2;
   32.92 -#endif
   32.93  #if defined(__sparc__) && !defined(HOST_SOLARIS)
   32.94      /* we also save i7 because longjmp may not restore it */
   32.95      asm volatile ("mov %%i7, %0" : "=r" (saved_i7));
   32.96  #endif
   32.97  
   32.98  #if defined(TARGET_I386)
   32.99 -#ifdef reg_EAX
  32.100 -    saved_EAX = EAX;
  32.101 -#endif
  32.102 -#ifdef reg_ECX
  32.103 -    saved_ECX = ECX;
  32.104 -#endif
  32.105 -#ifdef reg_EDX
  32.106 -    saved_EDX = EDX;
  32.107 -#endif
  32.108 -#ifdef reg_EBX
  32.109 -    saved_EBX = EBX;
  32.110 -#endif
  32.111 -#ifdef reg_ESP
  32.112 -    saved_ESP = ESP;
  32.113 -#endif
  32.114 -#ifdef reg_EBP
  32.115 -    saved_EBP = EBP;
  32.116 -#endif
  32.117 -#ifdef reg_ESI
  32.118 -    saved_ESI = ESI;
  32.119 -#endif
  32.120 -#ifdef reg_EDI
  32.121 -    saved_EDI = EDI;
  32.122 -#endif
  32.123 -
  32.124      env_to_regs();
  32.125      /* put eflags in CPU temporary format */
  32.126      CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
  32.127 @@ -370,6 +318,10 @@ int cpu_exec(CPUState *env1)
  32.128      saved_regwptr = REGWPTR;
  32.129  #endif
  32.130  #elif defined(TARGET_PPC)
  32.131 +#elif defined(TARGET_M68K)
  32.132 +    env->cc_op = CC_OP_FLAGS;
  32.133 +    env->cc_dest = env->sr & 0xf;
  32.134 +    env->cc_x = (env->sr >> 4) & 1;
  32.135  #elif defined(TARGET_MIPS)
  32.136  #elif defined(TARGET_SH4)
  32.137      /* XXXXX */
  32.138 @@ -390,7 +342,7 @@ int cpu_exec(CPUState *env1)
  32.139                      break;
  32.140                  } else if (env->user_mode_only) {
  32.141                      /* if user mode only, we simulate a fake exception
  32.142 -                       which will be hanlded outside the cpu execution
  32.143 +                       which will be handled outside the cpu execution
  32.144                         loop */
  32.145  #if defined(TARGET_I386)
  32.146                      do_interrupt_user(env->exception_index, 
  32.147 @@ -458,8 +410,16 @@ int cpu_exec(CPUState *env1)
  32.148                  interrupt_request = env->interrupt_request;
  32.149                  if (__builtin_expect(interrupt_request, 0)) {
  32.150  #if defined(TARGET_I386)
  32.151 -                    /* if hardware interrupt pending, we execute it */
  32.152 -                    if ((interrupt_request & CPU_INTERRUPT_HARD) &&
  32.153 +                    if ((interrupt_request & CPU_INTERRUPT_SMI) &&
  32.154 +                        !(env->hflags & HF_SMM_MASK)) {
  32.155 +                        env->interrupt_request &= ~CPU_INTERRUPT_SMI;
  32.156 +                        do_smm_enter();
  32.157 +#if defined(__sparc__) && !defined(HOST_SOLARIS)
  32.158 +                        tmp_T0 = 0;
  32.159 +#else
  32.160 +                        T0 = 0;
  32.161 +#endif
  32.162 +                    } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
  32.163                          (env->eflags & IF_MASK) && 
  32.164                          !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
  32.165                          int intno;
  32.166 @@ -519,7 +479,6 @@ int cpu_exec(CPUState *env1)
  32.167                          env->exception_index = EXCP_EXT_INTERRUPT;
  32.168                          env->error_code = 0;
  32.169                          do_interrupt(env);
  32.170 -                        env->interrupt_request &= ~CPU_INTERRUPT_HARD;
  32.171  #if defined(__sparc__) && !defined(HOST_SOLARIS)
  32.172                          tmp_T0 = 0;
  32.173  #else
  32.174 @@ -548,8 +507,10 @@ int cpu_exec(CPUState *env1)
  32.175  			//do_interrupt(0, 0, 0, 0, 0);
  32.176  			env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
  32.177  		    } else if (interrupt_request & CPU_INTERRUPT_HALT) {
  32.178 -                        env1->halted = 1;
  32.179 -                        return EXCP_HALTED;
  32.180 +			env->interrupt_request &= ~CPU_INTERRUPT_HALT;
  32.181 +			env->halted = 1;
  32.182 +			env->exception_index = EXCP_HLT;
  32.183 +			cpu_loop_exit();
  32.184                      }
  32.185  #elif defined(TARGET_ARM)
  32.186                      if (interrupt_request & CPU_INTERRUPT_FIQ
  32.187 @@ -622,6 +583,12 @@ int cpu_exec(CPUState *env1)
  32.188                      cpu_dump_state(env, logfile, fprintf, 0);
  32.189  #elif defined(TARGET_PPC)
  32.190                      cpu_dump_state(env, logfile, fprintf, 0);
  32.191 +#elif defined(TARGET_M68K)
  32.192 +                    cpu_m68k_flush_flags(env, env->cc_op);
  32.193 +                    env->cc_op = CC_OP_FLAGS;
  32.194 +                    env->sr = (env->sr & 0xffe0)
  32.195 +                              | env->cc_dest | (env->cc_x << 4);
  32.196 +                    cpu_dump_state(env, logfile, fprintf, 0);
  32.197  #elif defined(TARGET_MIPS)
  32.198                      cpu_dump_state(env, logfile, fprintf, 0);
  32.199  #elif defined(TARGET_SH4)
  32.200 @@ -803,32 +770,6 @@ int cpu_exec(CPUState *env1)
  32.201  #endif
  32.202      /* restore flags in standard format */
  32.203      env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
  32.204 -
  32.205 -    /* restore global registers */
  32.206 -#ifdef reg_EAX
  32.207 -    EAX = saved_EAX;
  32.208 -#endif
  32.209 -#ifdef reg_ECX
  32.210 -    ECX = saved_ECX;
  32.211 -#endif
  32.212 -#ifdef reg_EDX
  32.213 -    EDX = saved_EDX;
  32.214 -#endif
  32.215 -#ifdef reg_EBX
  32.216 -    EBX = saved_EBX;
  32.217 -#endif
  32.218 -#ifdef reg_ESP
  32.219 -    ESP = saved_ESP;
  32.220 -#endif
  32.221 -#ifdef reg_EBP
  32.222 -    EBP = saved_EBP;
  32.223 -#endif
  32.224 -#ifdef reg_ESI
  32.225 -    ESI = saved_ESI;
  32.226 -#endif
  32.227 -#ifdef reg_EDI
  32.228 -    EDI = saved_EDI;
  32.229 -#endif
  32.230  #elif defined(TARGET_ARM)
  32.231      /* XXX: Save/restore host fpu exception state?.  */
  32.232  #elif defined(TARGET_SPARC)
  32.233 @@ -836,21 +777,24 @@ int cpu_exec(CPUState *env1)
  32.234      REGWPTR = saved_regwptr;
  32.235  #endif
  32.236  #elif defined(TARGET_PPC)
  32.237 +#elif defined(TARGET_M68K)
  32.238 +    cpu_m68k_flush_flags(env, env->cc_op);
  32.239 +    env->cc_op = CC_OP_FLAGS;
  32.240 +    env->sr = (env->sr & 0xffe0)
  32.241 +              | env->cc_dest | (env->cc_x << 4);
  32.242  #elif defined(TARGET_MIPS)
  32.243  #elif defined(TARGET_SH4)
  32.244      /* XXXXX */
  32.245  #else
  32.246  #error unsupported target CPU
  32.247  #endif
  32.248 +
  32.249 +    /* restore global registers */
  32.250  #if defined(__sparc__) && !defined(HOST_SOLARIS)
  32.251      asm volatile ("mov %0, %%i7" : : "r" (saved_i7));
  32.252  #endif
  32.253 -    T0 = saved_T0;
  32.254 -    T1 = saved_T1;
  32.255 -#if defined(reg_T2)
  32.256 -    T2 = saved_T2;
  32.257 -#endif
  32.258 -    env = saved_env;
  32.259 +#include "hostregs_helper.h"
  32.260 +
  32.261      /* fail safe : never use cpu_single_env outside cpu_exec() */
  32.262      cpu_single_env = NULL; 
  32.263      return ret;
  32.264 @@ -1093,6 +1037,45 @@ static inline int handle_cpu_signal(unsi
  32.265      return 1;
  32.266  }
  32.267  
  32.268 +#elif defined(TARGET_M68K)
  32.269 +static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
  32.270 +                                    int is_write, sigset_t *old_set,
  32.271 +                                    void *puc)
  32.272 +{
  32.273 +    TranslationBlock *tb;
  32.274 +    int ret;
  32.275 +
  32.276 +    if (cpu_single_env)
  32.277 +        env = cpu_single_env; /* XXX: find a correct solution for multithread */
  32.278 +#if defined(DEBUG_SIGNAL)
  32.279 +    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", 
  32.280 +           pc, address, is_write, *(unsigned long *)old_set);
  32.281 +#endif
  32.282 +    /* XXX: locking issue */
  32.283 +    if (is_write && page_unprotect(address, pc, puc)) {
  32.284 +        return 1;
  32.285 +    }
  32.286 +    /* see if it is an MMU fault */
  32.287 +    ret = cpu_m68k_handle_mmu_fault(env, address, is_write, 1, 0);
  32.288 +    if (ret < 0)
  32.289 +        return 0; /* not an MMU fault */
  32.290 +    if (ret == 0)
  32.291 +        return 1; /* the MMU fault was handled without causing real CPU fault */
  32.292 +    /* now we have a real cpu fault */
  32.293 +    tb = tb_find_pc(pc);
  32.294 +    if (tb) {
  32.295 +        /* the PC is inside the translated code. It means that we have
  32.296 +           a virtual CPU fault */
  32.297 +        cpu_restore_state(tb, env, pc, puc);
  32.298 +    }
  32.299 +    /* we restore the process signal mask as the sigreturn should
  32.300 +       do it (XXX: use sigsetjmp) */
  32.301 +    sigprocmask(SIG_SETMASK, old_set, NULL);
  32.302 +    cpu_loop_exit();
  32.303 +    /* never comes here */
  32.304 +    return 1;
  32.305 +}
  32.306 +
  32.307  #elif defined (TARGET_MIPS)
  32.308  static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
  32.309                                      int is_write, sigset_t *old_set,
  32.310 @@ -1193,6 +1176,18 @@ static inline int handle_cpu_signal(unsi
  32.311  
  32.312  #if defined(__i386__)
  32.313  
  32.314 +#if defined(__APPLE__)
  32.315 +# include <sys/ucontext.h>
  32.316 +
  32.317 +# define EIP_sig(context)  (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
  32.318 +# define TRAP_sig(context)    ((context)->uc_mcontext->es.trapno)
  32.319 +# define ERROR_sig(context)   ((context)->uc_mcontext->es.err)
  32.320 +#else
  32.321 +# define EIP_sig(context)     ((context)->uc_mcontext.gregs[REG_EIP])
  32.322 +# define TRAP_sig(context)    ((context)->uc_mcontext.gregs[REG_TRAPNO])
  32.323 +# define ERROR_sig(context)   ((context)->uc_mcontext.gregs[REG_ERR])
  32.324 +#endif
  32.325 +
  32.326  #if defined(USE_CODE_COPY)
  32.327  static void cpu_send_trap(unsigned long pc, int trap, 
  32.328                            struct ucontext *uc)
  32.329 @@ -1213,9 +1208,10 @@ static void cpu_send_trap(unsigned long 
  32.330  }
  32.331  #endif
  32.332  
  32.333 -int cpu_signal_handler(int host_signum, struct siginfo *info, 
  32.334 +int cpu_signal_handler(int host_signum, void *pinfo, 
  32.335                         void *puc)
  32.336  {
  32.337 +    siginfo_t *info = pinfo;
  32.338      struct ucontext *uc = puc;
  32.339      unsigned long pc;
  32.340      int trapno;
  32.341 @@ -1226,8 +1222,8 @@ int cpu_signal_handler(int host_signum, 
  32.342  #define REG_ERR    ERR
  32.343  #define REG_TRAPNO TRAPNO
  32.344  #endif
  32.345 -    pc = uc->uc_mcontext.gregs[REG_EIP];
  32.346 -    trapno = uc->uc_mcontext.gregs[REG_TRAPNO];
  32.347 +    pc = EIP_sig(uc);
  32.348 +    trapno = TRAP_sig(uc);
  32.349  #if defined(TARGET_I386) && defined(USE_CODE_COPY)
  32.350      if (trapno == 0x00 || trapno == 0x05) {
  32.351          /* send division by zero or bound exception */
  32.352 @@ -1237,15 +1233,16 @@ int cpu_signal_handler(int host_signum, 
  32.353  #endif
  32.354          return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
  32.355                                   trapno == 0xe ? 
  32.356 -                                 (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
  32.357 +                                 (ERROR_sig(uc) >> 1) & 1 : 0,
  32.358                                   &uc->uc_sigmask, puc);
  32.359  }
  32.360  
  32.361  #elif defined(__x86_64__)
  32.362  
  32.363 -int cpu_signal_handler(int host_signum, struct siginfo *info,
  32.364 +int cpu_signal_handler(int host_signum, void *pinfo,
  32.365                         void *puc)
  32.366  {
  32.367 +    siginfo_t *info = pinfo;
  32.368      struct ucontext *uc = puc;
  32.369      unsigned long pc;
  32.370  
  32.371 @@ -1307,9 +1304,10 @@ typedef struct ucontext SIGCONTEXT;
  32.372  # define TRAP_sig(context)			EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
  32.373  #endif /* __APPLE__ */
  32.374  
  32.375 -int cpu_signal_handler(int host_signum, struct siginfo *info, 
  32.376 +int cpu_signal_handler(int host_signum, void *pinfo, 
  32.377                         void *puc)
  32.378  {
  32.379 +    siginfo_t *info = pinfo;
  32.380      struct ucontext *uc = puc;
  32.381      unsigned long pc;
  32.382      int is_write;
  32.383 @@ -1330,9 +1328,10 @@ int cpu_signal_handler(int host_signum, 
  32.384  
  32.385  #elif defined(__alpha__)
  32.386  
  32.387 -int cpu_signal_handler(int host_signum, struct siginfo *info, 
  32.388 +int cpu_signal_handler(int host_signum, void *pinfo, 
  32.389                             void *puc)
  32.390  {
  32.391 +    siginfo_t *info = pinfo;
  32.392      struct ucontext *uc = puc;
  32.393      uint32_t *pc = uc->uc_mcontext.sc_pc;
  32.394      uint32_t insn = *pc;
  32.395 @@ -1359,9 +1358,10 @@ int cpu_signal_handler(int host_signum, 
  32.396  }
  32.397  #elif defined(__sparc__)
  32.398  
  32.399 -int cpu_signal_handler(int host_signum, struct siginfo *info, 
  32.400 +int cpu_signal_handler(int host_signum, void *pinfo, 
  32.401                         void *puc)
  32.402  {
  32.403 +    siginfo_t *info = pinfo;
  32.404      uint32_t *regs = (uint32_t *)(info + 1);
  32.405      void *sigmask = (regs + 20);
  32.406      unsigned long pc;
  32.407 @@ -1392,9 +1392,10 @@ int cpu_signal_handler(int host_signum, 
  32.408  
  32.409  #elif defined(__arm__)
  32.410  
  32.411 -int cpu_signal_handler(int host_signum, struct siginfo *info, 
  32.412 +int cpu_signal_handler(int host_signum, void *pinfo, 
  32.413                         void *puc)
  32.414  {
  32.415 +    siginfo_t *info = pinfo;
  32.416      struct ucontext *uc = puc;
  32.417      unsigned long pc;
  32.418      int is_write;
  32.419 @@ -1404,14 +1405,15 @@ int cpu_signal_handler(int host_signum, 
  32.420      is_write = 0;
  32.421      return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
  32.422                               is_write,
  32.423 -                             &uc->uc_sigmask);
  32.424 +                             &uc->uc_sigmask, puc);
  32.425  }
  32.426  
  32.427  #elif defined(__mc68000)
  32.428  
  32.429 -int cpu_signal_handler(int host_signum, struct siginfo *info, 
  32.430 +int cpu_signal_handler(int host_signum, void *pinfo, 
  32.431                         void *puc)
  32.432  {
  32.433 +    siginfo_t *info = pinfo;
  32.434      struct ucontext *uc = puc;
  32.435      unsigned long pc;
  32.436      int is_write;
  32.437 @@ -1431,8 +1433,9 @@ int cpu_signal_handler(int host_signum, 
  32.438  # define __ISR_VALID	1
  32.439  #endif
  32.440  
  32.441 -int cpu_signal_handler(int host_signum, struct siginfo *info, void *puc)
  32.442 +int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
  32.443  {
  32.444 +    siginfo_t *info = pinfo;
  32.445      struct ucontext *uc = puc;
  32.446      unsigned long ip;
  32.447      int is_write = 0;
  32.448 @@ -1459,9 +1462,10 @@ int cpu_signal_handler(int host_signum, 
  32.449  
  32.450  #elif defined(__s390__)
  32.451  
  32.452 -int cpu_signal_handler(int host_signum, struct siginfo *info, 
  32.453 +int cpu_signal_handler(int host_signum, void *pinfo, 
  32.454                         void *puc)
  32.455  {
  32.456 +    siginfo_t *info = pinfo;
  32.457      struct ucontext *uc = puc;
  32.458      unsigned long pc;
  32.459      int is_write;
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/tools/ioemu/cutils.c	Wed May 09 14:17:15 2007 +0100
    33.3 @@ -0,0 +1,83 @@
    33.4 +/*
    33.5 + * Simple C functions to supplement the C library
    33.6 + * 
    33.7 + * Copyright (c) 2006 Fabrice Bellard
    33.8 + *
    33.9 + * Permission is hereby granted, free of charge, to any person obtaining a copy
   33.10 + * of this software and associated documentation files (the "Software"), to deal
   33.11 + * in the Software without restriction, including without limitation the rights
   33.12 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   33.13 + * copies of the Software, and to permit persons to whom the Software is
   33.14 + * furnished to do so, subject to the following conditions:
   33.15 + *
   33.16 + * The above copyright notice and this permission notice shall be included in
   33.17 + * all copies or substantial portions of the Software.
   33.18 + *
   33.19 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   33.20 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   33.21 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   33.22 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   33.23 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   33.24 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   33.25 + * THE SOFTWARE.
   33.26 + */
   33.27 +#include "vl.h"
   33.28 +
   33.29 +void pstrcpy(char *buf, int buf_size, const char *str)
   33.30 +{
   33.31 +    int c;
   33.32 +    char *q = buf;
   33.33 +
   33.34 +    if (buf_size <= 0)
   33.35 +        return;
   33.36 +
   33.37 +    for(;;) {
   33.38 +        c = *str++;
   33.39 +        if (c == 0 || q >= buf + buf_size - 1)
   33.40 +            break;
   33.41 +        *q++ = c;
   33.42 +    }
   33.43 +    *q = '\0';
   33.44 +}
   33.45 +
   33.46 +/* strcat and truncate. */
   33.47 +char *pstrcat(char *buf, int buf_size, const char *s)
   33.48 +{
   33.49 +    int len;
   33.50 +    len = strlen(buf);
   33.51 +    if (len < buf_size) 
   33.52 +        pstrcpy(buf + len, buf_size - len, s);
   33.53 +    return buf;
   33.54 +}
   33.55 +
   33.56 +int strstart(const char *str, const char *val, const char **ptr)
   33.57 +{
   33.58 +    const char *p, *q;
   33.59 +    p = str;
   33.60 +    q = val;
   33.61 +    while (*q != '\0') {
   33.62 +        if (*p != *q)
   33.63 +            return 0;
   33.64 +        p++;
   33.65 +        q++;
   33.66 +    }
   33.67 +    if (ptr)
   33.68 +        *ptr = p;
   33.69 +    return 1;
   33.70 +}
   33.71 +
   33.72 +int stristart(const char *str, const char *val, const char **ptr)
   33.73 +{
   33.74 +    const char *p, *q;
   33.75 +    p = str;
   33.76 +    q = val;
   33.77 +    while (*q != '\0') {
   33.78 +        if (toupper(*p) != toupper(*q))
   33.79 +            return 0;
   33.80 +        p++;
   33.81 +        q++;
   33.82 +    }
   33.83 +    if (ptr)
   33.84 +        *ptr = p;
   33.85 +    return 1;
   33.86 +}
    34.1 --- a/tools/ioemu/disas.c	Tue May 08 10:38:06 2007 +0100
    34.2 +++ b/tools/ioemu/disas.c	Wed May 09 14:17:15 2007 +0100
    34.3 @@ -186,14 +186,14 @@ void target_disas(FILE *out, target_ulon
    34.4      disasm_info.mach = bfd_mach_ppc;
    34.5  #endif
    34.6      print_insn = print_insn_ppc;
    34.7 +#elif defined(TARGET_M68K)
    34.8 +    print_insn = print_insn_m68k;
    34.9  #elif defined(TARGET_MIPS)
   34.10  #ifdef TARGET_WORDS_BIGENDIAN
   34.11      print_insn = print_insn_big_mips;
   34.12  #else
   34.13      print_insn = print_insn_little_mips;
   34.14  #endif
   34.15 -#elif defined(TARGET_M68K)
   34.16 -    print_insn = print_insn_m68k;
   34.17  #elif defined(TARGET_SH4)
   34.18      disasm_info.mach = bfd_mach_sh4;
   34.19      print_insn = print_insn_sh;
   34.20 @@ -271,11 +271,9 @@ void disas(FILE *out, void *code, unsign
   34.21      for (pc = (unsigned long)code; pc < (unsigned long)code + size; pc += count) {
   34.22  	fprintf(out, "0x%08lx:  ", pc);
   34.23  #ifdef __arm__
   34.24 -        /* since data are included in the code, it is better to
   34.25 +        /* since data is included in the code, it is better to
   34.26             display code data too */
   34.27 -        if (is_host) {
   34.28 -            fprintf(out, "%08x  ", (int)bfd_getl32((const bfd_byte *)pc));
   34.29 -        }
   34.30 +        fprintf(out, "%08x  ", (int)bfd_getl32((const bfd_byte *)pc));
   34.31  #endif
   34.32  	count = print_insn(pc, &disasm_info);
   34.33  	fprintf(out, "\n");
   34.34 @@ -387,14 +385,14 @@ void monitor_disas(CPUState *env,
   34.35      disasm_info.mach = bfd_mach_ppc;
   34.36  #endif
   34.37      print_insn = print_insn_ppc;
   34.38 +#elif defined(TARGET_M68K)
   34.39 +    print_insn = print_insn_m68k;
   34.40  #elif defined(TARGET_MIPS)
   34.41  #ifdef TARGET_WORDS_BIGENDIAN
   34.42      print_insn = print_insn_big_mips;
   34.43  #else
   34.44      print_insn = print_insn_little_mips;
   34.45  #endif
   34.46 -#elif defined(TARGET_M68K)
   34.47 -    print_insn = print_insn_m68k;
   34.48  #else
   34.49      term_printf("0x" TARGET_FMT_lx
   34.50  		": Asm output not supported on this arch\n", pc);
    35.1 --- a/tools/ioemu/dyngen-exec.h	Tue May 08 10:38:06 2007 +0100
    35.2 +++ b/tools/ioemu/dyngen-exec.h	Wed May 09 14:17:15 2007 +0100
    35.3 @@ -62,6 +62,9 @@ typedef signed long long int64_t;
    35.4  #endif
    35.5  #endif
    35.6  
    35.7 +/* XXX: This may be wrong for 64-bit ILP32 hosts.  */
    35.8 +typedef void * host_reg_t;
    35.9 +
   35.10  #define INT8_MIN		(-128)
   35.11  #define INT16_MIN		(-32767-1)
   35.12  #define INT32_MIN		(-2147483647-1)
   35.13 @@ -188,7 +191,7 @@ extern int printf(const char *, ...);
   35.14  #endif
   35.15  
   35.16  /* force GCC to generate only one epilog at the end of the function */
   35.17 -#define FORCE_RET() asm volatile ("");
   35.18 +#define FORCE_RET() __asm__ __volatile__("" : : : "memory");
   35.19  
   35.20  #ifndef OPPROTO
   35.21  #define OPPROTO
    36.1 --- a/tools/ioemu/dyngen.c	Tue May 08 10:38:06 2007 +0100
    36.2 +++ b/tools/ioemu/dyngen.c	Wed May 09 14:17:15 2007 +0100
    36.3 @@ -127,10 +127,12 @@
    36.4  typedef int32_t host_long;
    36.5  typedef uint32_t host_ulong;
    36.6  #define swabls(x) swab32s(x)
    36.7 +#define swablss(x) swab32ss(x)
    36.8  #else
    36.9  typedef int64_t host_long;
   36.10  typedef uint64_t host_ulong;
   36.11  #define swabls(x) swab64s(x)
   36.12 +#define swablss(x) swab64ss(x)
   36.13  #endif
   36.14  
   36.15  #ifdef ELF_USES_RELOCA
   36.16 @@ -284,11 +286,21 @@ void swab32s(uint32_t *p)
   36.17      *p = bswap32(*p);
   36.18  }
   36.19  
   36.20 +void swab32ss(int32_t *p)
   36.21 +{
   36.22 +    *p = bswap32(*p);
   36.23 +}
   36.24 +
   36.25  void swab64s(uint64_t *p)
   36.26  {
   36.27      *p = bswap64(*p);
   36.28  }
   36.29  
   36.30 +void swab64ss(int64_t *p)
   36.31 +{
   36.32 +    *p = bswap64(*p);
   36.33 +}
   36.34 +
   36.35  uint16_t get16(uint16_t *p)
   36.36  {
   36.37      uint16_t val;
   36.38 @@ -397,7 +409,7 @@ void elf_swap_rel(ELF_RELOC *rel)
   36.39      swabls(&rel->r_offset);
   36.40      swabls(&rel->r_info);
   36.41  #ifdef ELF_USES_RELOCA
   36.42 -    swabls(&rel->r_addend);
   36.43 +    swablss(&rel->r_addend);
   36.44  #endif
   36.45  }
   36.46  
   36.47 @@ -505,7 +517,7 @@ int load_object(const char *filename)
   36.48      }
   36.49  
   36.50      sec = &shdr[ehdr.e_shstrndx];
   36.51 -    shstr = sdata[ehdr.e_shstrndx];
   36.52 +    shstr = (char *)sdata[ehdr.e_shstrndx];
   36.53  
   36.54      /* swap relocations */
   36.55      for(i = 0; i < ehdr.e_shnum; i++) {
   36.56 @@ -541,7 +553,7 @@ int load_object(const char *filename)
   36.57      strtab_sec = &shdr[symtab_sec->sh_link];
   36.58  
   36.59      symtab = (ElfW(Sym) *)sdata[symtab_sec - shdr];
   36.60 -    strtab = sdata[symtab_sec->sh_link];
   36.61 +    strtab = (char *)sdata[symtab_sec->sh_link];
   36.62      
   36.63      nb_syms = symtab_sec->sh_size / sizeof(ElfW(Sym));
   36.64      if (do_swap) {
   36.65 @@ -1255,90 +1267,149 @@ int arm_emit_ldr_info(const char *name, 
   36.66  {
   36.67      uint8_t *p;
   36.68      uint32_t insn;
   36.69 -    int offset, min_offset, pc_offset, data_size;
   36.70 +    int offset, min_offset, pc_offset, data_size, spare, max_pool;
   36.71      uint8_t data_allocated[1024];
   36.72      unsigned int data_index;
   36.73 +    int type;
   36.74      
   36.75      memset(data_allocated, 0, sizeof(data_allocated));
   36.76      
   36.77      p = p_start;
   36.78      min_offset = p_end - p_start;
   36.79 +    spare = 0x7fffffff;
   36.80      while (p < p_start + min_offset) {
   36.81          insn = get32((uint32_t *)p);
   36.82 +        /* TODO: Armv5e ldrd.  */
   36.83 +        /* TODO: VFP load.  */
   36.84          if ((insn & 0x0d5f0000) == 0x051f0000) {
   36.85              /* ldr reg, [pc, #im] */
   36.86              offset = insn & 0xfff;
   36.87              if (!(insn & 0x00800000))
   36.88 -                        offset = -offset;
   36.89 +                offset = -offset;
   36.90 +            max_pool = 4096;
   36.91 +            type = 0;
   36.92 +        } else if ((insn & 0x0e5f0f00) == 0x0c1f0100) {
   36.93 +            /* FPA ldf.  */
   36.94 +            offset = (insn & 0xff) << 2;
   36.95 +            if (!(insn & 0x00800000))
   36.96 +                offset = -offset;
   36.97 +            max_pool = 1024;
   36.98 +            type = 1;
   36.99 +        } else if ((insn & 0x0fff0000) == 0x028f0000) {
  36.100 +            /* Some gcc load a doubleword immediate with
  36.101 +               add regN, pc, #imm
  36.102 +               ldmia regN, {regN, regM}
  36.103 +               Hope and pray the compiler never generates somethin like
  36.104 +               add reg, pc, #imm1; ldr reg, [reg, #-imm2]; */
  36.105 +            int r;
  36.106 +
  36.107 +            r = (insn & 0xf00) >> 7;
  36.108 +            offset = ((insn & 0xff) >> r) | ((insn & 0xff) << (32 - r));
  36.109 +            max_pool = 1024;
  36.110 +            type = 2;
  36.111 +        } else {
  36.112 +            max_pool = 0;
  36.113 +            type = -1;
  36.114 +        }
  36.115 +        if (type >= 0) {
  36.116 +            /* PC-relative load needs fixing up.  */
  36.117 +            if (spare > max_pool - offset)
  36.118 +                spare = max_pool - offset;
  36.119              if ((offset & 3) !=0)
  36.120 -                error("%s:%04x: ldr pc offset must be 32 bit aligned", 
  36.121 +                error("%s:%04x: pc offset must be 32 bit aligned", 
  36.122 +                      name, start_offset + p - p_start);
  36.123 +            if (offset < 0)
  36.124 +                error("%s:%04x: Embedded literal value",
  36.125                        name, start_offset + p - p_start);
  36.126              pc_offset = p - p_start + offset + 8;
  36.127              if (pc_offset <= (p - p_start) || 
  36.128                  pc_offset >= (p_end - p_start))
  36.129 -                error("%s:%04x: ldr pc offset must point inside the function code", 
  36.130 +                error("%s:%04x: pc offset must point inside the function code", 
  36.131                        name, start_offset + p - p_start);
  36.132              if (pc_offset < min_offset)
  36.133                  min_offset = pc_offset;
  36.134              if (outfile) {
  36.135 -                /* ldr position */
  36.136 +                /* The intruction position */
  36.137                  fprintf(outfile, "    arm_ldr_ptr->ptr = gen_code_ptr + %d;\n", 
  36.138                          p - p_start);
  36.139 -                /* ldr data index */
  36.140 -                data_index = ((p_end - p_start) - pc_offset - 4) >> 2;
  36.141 -                fprintf(outfile, "    arm_ldr_ptr->data_ptr = arm_data_ptr + %d;\n", 
  36.142 +                /* The position of the constant pool data.  */
  36.143 +                data_index = ((p_end - p_start) - pc_offset) >> 2;
  36.144 +                fprintf(outfile, "    arm_ldr_ptr->data_ptr = arm_data_ptr - %d;\n", 
  36.145                          data_index);
  36.146 +                fprintf(outfile, "    arm_ldr_ptr->type = %d;\n", type);
  36.147                  fprintf(outfile, "    arm_ldr_ptr++;\n");
  36.148 -                if (data_index >= sizeof(data_allocated))
  36.149 -                    error("%s: too many data", name);
  36.150 -                if (!data_allocated[data_index]) {
  36.151 -                    ELF_RELOC *rel;
  36.152 -                    int i, addend, type;
  36.153 -                    const char *sym_name, *p;
  36.154 -                    char relname[1024];
  36.155 -
  36.156 -                    data_allocated[data_index] = 1;
  36.157 -
  36.158 -                    /* data value */
  36.159 -                    addend = get32((uint32_t *)(p_start + pc_offset));
  36.160 -                    relname[0] = '\0';
  36.161 -                    for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
  36.162 -                        if (rel->r_offset == (pc_offset + start_offset)) {
  36.163 -                            sym_name = get_rel_sym_name(rel);
  36.164 -                            /* the compiler leave some unnecessary references to the code */
  36.165 -                            get_reloc_expr(relname, sizeof(relname), sym_name);
  36.166 -                            type = ELF32_R_TYPE(rel->r_info);
  36.167 -                            if (type != R_ARM_ABS32)
  36.168 -                                error("%s: unsupported data relocation", name);
  36.169 -                            break;
  36.170 -                        }
  36.171 -                    }
  36.172 -                    fprintf(outfile, "    arm_data_ptr[%d] = 0x%x",
  36.173 -                            data_index, addend);
  36.174 -                    if (relname[0] != '\0')
  36.175 -                        fprintf(outfile, " + %s", relname);
  36.176 -                    fprintf(outfile, ";\n");
  36.177 -                }
  36.178              }
  36.179          }
  36.180          p += 4;
  36.181      }
  36.182 +
  36.183 +    /* Copy and relocate the constant pool data.  */
  36.184      data_size = (p_end - p_start) - min_offset;
  36.185      if (data_size > 0 && outfile) {
  36.186 -        fprintf(outfile, "    arm_data_ptr += %d;\n", data_size >> 2);
  36.187 +        spare += min_offset;
  36.188 +        fprintf(outfile, "    arm_data_ptr -= %d;\n", data_size >> 2);
  36.189 +        fprintf(outfile, "    arm_pool_ptr -= %d;\n", data_size);
  36.190 +        fprintf(outfile, "    if (arm_pool_ptr > gen_code_ptr + %d)\n"
  36.191 +                         "        arm_pool_ptr = gen_code_ptr + %d;\n",
  36.192 +                         spare, spare);
  36.193 +
  36.194 +        data_index = 0;
  36.195 +        for (pc_offset = min_offset;
  36.196 +             pc_offset < p_end - p_start;
  36.197 +             pc_offset += 4) {
  36.198 +
  36.199 +            ELF_RELOC *rel;
  36.200 +            int i, addend, type;
  36.201 +            const char *sym_name;
  36.202 +            char relname[1024];
  36.203 +
  36.204 +            /* data value */
  36.205 +            addend = get32((uint32_t *)(p_start + pc_offset));
  36.206 +            relname[0] = '\0';
  36.207 +            for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
  36.208 +                if (rel->r_offset == (pc_offset + start_offset)) {
  36.209 +                    sym_name = get_rel_sym_name(rel);
  36.210 +                    /* the compiler leave some unnecessary references to the code */
  36.211 +                    get_reloc_expr(relname, sizeof(relname), sym_name);
  36.212 +                    type = ELF32_R_TYPE(rel->r_info);
  36.213 +                    if (type != R_ARM_ABS32)
  36.214 +                        error("%s: unsupported data relocation", name);
  36.215 +                    break;
  36.216 +                }
  36.217 +            }
  36.218 +            fprintf(outfile, "    arm_data_ptr[%d] = 0x%x",
  36.219 +                    data_index, addend);
  36.220 +            if (relname[0] != '\0')
  36.221 +                fprintf(outfile, " + %s", relname);
  36.222 +            fprintf(outfile, ";\n");
  36.223 +
  36.224 +            data_index++;
  36.225 +        }
  36.226      }
  36.227  
  36.228 -    /* the last instruction must be a mov pc, lr */
  36.229      if (p == p_start)
  36.230          goto arm_ret_error;
  36.231      p -= 4;
  36.232      insn = get32((uint32_t *)p);
  36.233 -    if ((insn & 0xffff0000) != 0xe91b0000) {
  36.234 +    /* The last instruction must be an ldm instruction.  There are several
  36.235 +       forms generated by gcc:
  36.236 +        ldmib sp, {..., pc}  (implies a sp adjustment of +4)
  36.237 +        ldmia sp, {..., pc}
  36.238 +        ldmea fp, {..., pc} */
  36.239 +    if ((insn & 0xffff8000) == 0xe99d8000) {
  36.240 +        if (outfile) {
  36.241 +            fprintf(outfile,
  36.242 +                    "    *(uint32_t *)(gen_code_ptr + %d) = 0xe28dd004;\n",
  36.243 +                    p - p_start);
  36.244 +        }
  36.245 +        p += 4;
  36.246 +    } else if ((insn & 0xffff8000) != 0xe89d8000
  36.247 +        && (insn & 0xffff8000) != 0xe91b8000) {
  36.248      arm_ret_error:
  36.249          if (!outfile)
  36.250              printf("%s: invalid epilog\n", name);
  36.251      }
  36.252 -    return p - p_start;	    
  36.253 +    return p - p_start;
  36.254  }
  36.255  #endif
  36.256  
  36.257 @@ -1537,6 +1608,8 @@ void gen_code(const char *name, host_ulo
  36.258      }
  36.259  #elif defined(HOST_ARM)
  36.260      {
  36.261 +        uint32_t insn;
  36.262 +
  36.263          if ((p_end - p_start) <= 16)
  36.264              error("%s: function too small", name);
  36.265          if (get32((uint32_t *)p_start) != 0xe1a0c00d ||
  36.266 @@ -1545,6 +1618,12 @@ void gen_code(const char *name, host_ulo
  36.267              error("%s: invalid prolog", name);
  36.268          p_start += 12;
  36.269          start_offset += 12;
  36.270 +        insn = get32((uint32_t *)p_start);
  36.271 +        if ((insn & 0xffffff00) == 0xe24dd000) {
  36.272 +            /* Stack adjustment.  Assume op uses the frame pointer.  */
  36.273 +            p_start -= 4;
  36.274 +            start_offset -= 4;
  36.275 +        }
  36.276          copy_size = arm_emit_ldr_info(name, start_offset, NULL, p_start, p_end, 
  36.277                                        relocs, nb_relocs);
  36.278      }
  36.279 @@ -2282,7 +2361,37 @@ void gen_code(const char *name, host_ulo
  36.280                  int type;
  36.281                  int addend;
  36.282                  int reloc_offset;
  36.283 +                uint32_t insn;
  36.284  
  36.285 +                insn = get32((uint32_t *)(p_start + 4));
  36.286 +                /* If prologue ends in sub sp, sp, #const then assume
  36.287 +                   op has a stack frame and needs the frame pointer.  */
  36.288 +                if ((insn & 0xffffff00) == 0xe24dd000) {
  36.289 +                    int i;
  36.290 +                    uint32_t opcode;
  36.291 +                    opcode = 0xe28db000; /* add fp, sp, #0.  */
  36.292 +#if 0
  36.293 +/* ??? Need to undo the extra stack adjustment at the end of the op.
  36.294 +   For now just leave the stack misaligned and hope it doesn't break anything
  36.295 +   too important.  */
  36.296 +                    if ((insn & 4) != 0) {
  36.297 +                        /* Preserve doubleword stack alignment.  */
  36.298 +                        fprintf(outfile,
  36.299 +                                "    *(uint32_t *)(gen_code_ptr + 4)= 0x%x;\n",
  36.300 +                                insn + 4);
  36.301 +                        opcode -= 4;
  36.302 +                    }
  36.303 +#endif
  36.304 +                    insn = get32((uint32_t *)(p_start - 4));
  36.305 +                    /* Calculate the size of the saved registers,
  36.306 +                       excluding pc.  */
  36.307 +                    for (i = 0; i < 15; i++) {
  36.308 +                        if (insn & (1 << i))
  36.309 +                            opcode += 4;
  36.310 +                    }
  36.311 +                    fprintf(outfile,
  36.312 +                            "    *(uint32_t *)gen_code_ptr = 0x%x;\n", opcode);
  36.313 +                }
  36.314                  arm_emit_ldr_info(name, start_offset, outfile, p_start, p_end,
  36.315                                    relocs, nb_relocs);
  36.316  
  36.317 @@ -2303,6 +2412,8 @@ void gen_code(const char *name, host_ulo
  36.318                                  reloc_offset, name, addend);
  36.319                          break;
  36.320                      case R_ARM_PC24:
  36.321 +                    case R_ARM_JUMP24:
  36.322 +                    case R_ARM_CALL:
  36.323                          fprintf(outfile, "    arm_reloc_pc24((uint32_t *)(gen_code_ptr + %d), 0x%x, %s);\n", 
  36.324                                  reloc_offset, addend, name);
  36.325                          break;
  36.326 @@ -2407,6 +2518,28 @@ int gen_file(FILE *outfile, int out_type
  36.327          
  36.328      } else {
  36.329          /* generate big code generation switch */
  36.330 +
  36.331 +#ifdef HOST_ARM
  36.332 +        /* We need to know the size of all the ops so we can figure out when
  36.333 +           to emit constant pools.  This must be consistent with opc.h.  */
  36.334 +fprintf(outfile,
  36.335 +"static const uint32_t arm_opc_size[] = {\n"
  36.336 +"  0,\n" /* end */
  36.337 +"  0,\n" /* nop */
  36.338 +"  0,\n" /* nop1 */
  36.339 +"  0,\n" /* nop2 */
  36.340 +"  0,\n"); /* nop3 */
  36.341 +        for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
  36.342 +            const char *name;
  36.343 +            name = get_sym_name(sym);
  36.344 +            if (strstart(name, OP_PREFIX, NULL)) {
  36.345 +                fprintf(outfile, "  %d,\n", sym->st_size);
  36.346 +            }
  36.347 +	}
  36.348 +fprintf(outfile,
  36.349 +"};\n");
  36.350 +#endif
  36.351 +
  36.352  fprintf(outfile,
  36.353  "int dyngen_code(uint8_t *gen_code_buf,\n"
  36.354  "                uint16_t *label_offsets, uint16_t *jmp_offsets,\n"
  36.355 @@ -2417,10 +2550,36 @@ fprintf(outfile,
  36.356  "    const uint32_t *opparam_ptr;\n");
  36.357  
  36.358  #ifdef HOST_ARM
  36.359 +/* Arm is tricky because it uses constant pools for loading immediate values.
  36.360 +   We assume (and require) each function is code followed by a constant pool.
  36.361 +   All the ops are small so this should be ok.  For each op we figure
  36.362 +   out how much "spare" range we have in the load instructions.  This allows
  36.363 +   us to insert subsequent ops in between the op and the constant pool,
  36.364 +   eliminating the neeed to jump around the pool.
  36.365 +
  36.366 +   We currently generate:
  36.367 +   
  36.368 +   [ For this example we assume merging would move op1_pool out of range.
  36.369 +     In practice we should be able to combine many ops before the offset
  36.370 +     limits are reached. ]
  36.371 +   op1_code;
  36.372 +   op2_code;
  36.373 +   goto op3;
  36.374 +   op2_pool;
  36.375 +   op1_pool;
  36.376 +op3:
  36.377 +   op3_code;
  36.378 +   ret;
  36.379 +   op3_pool;
  36.380 +
  36.381 +   Ideally we'd put op1_pool before op2_pool, but that requires two passes.
  36.382 + */
  36.383  fprintf(outfile,
  36.384  "    uint8_t *last_gen_code_ptr = gen_code_buf;\n"
  36.385  "    LDREntry *arm_ldr_ptr = arm_ldr_table;\n"
  36.386 -"    uint32_t *arm_data_ptr = arm_data_table;\n");
  36.387 +"    uint32_t *arm_data_ptr = arm_data_table + ARM_LDR_TABLE_SIZE;\n"
  36.388 +/* Initialise the parmissible pool offset to an arbitary large value.  */
  36.389 +"    uint8_t *arm_pool_ptr = gen_code_buf + 0x1000000;\n");
  36.390  #endif
  36.391  #ifdef HOST_IA64
  36.392      {
  36.393 @@ -2489,9 +2648,23 @@ fprintf(outfile,
  36.394  	/* Generate prologue, if needed. */ 
  36.395  
  36.396  fprintf(outfile,
  36.397 -"    for(;;) {\n"
  36.398 -"        switch(*opc_ptr++) {\n"
  36.399 -);
  36.400 +"    for(;;) {\n");
  36.401 +
  36.402 +#ifdef HOST_ARM
  36.403 +/* Generate constant pool if needed */
  36.404 +fprintf(outfile,
  36.405 +"            if (gen_code_ptr + arm_opc_size[*opc_ptr] >= arm_pool_ptr) {\n"
  36.406 +"                gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, "
  36.407 +"arm_ldr_ptr, arm_data_ptr, arm_data_table + ARM_LDR_TABLE_SIZE, 1);\n"
  36.408 +"                last_gen_code_ptr = gen_code_ptr;\n"
  36.409 +"                arm_ldr_ptr = arm_ldr_table;\n"
  36.410 +"                arm_data_ptr = arm_data_table + ARM_LDR_TABLE_SIZE;\n"
  36.411 +"                arm_pool_ptr = gen_code_ptr + 0x1000000;\n"
  36.412 +"            }\n");
  36.413 +#endif
  36.414 +
  36.415 +fprintf(outfile,
  36.416 +"        switch(*opc_ptr++) {\n");
  36.417  
  36.418          for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
  36.419              const char *name;
  36.420 @@ -2525,17 +2698,6 @@ fprintf(outfile,
  36.421  "            goto the_end;\n"
  36.422  "        }\n");
  36.423  
  36.424 -#ifdef HOST_ARM
  36.425 -/* generate constant table if needed */
  36.426 -fprintf(outfile,
  36.427 -"        if ((gen_code_ptr - last_gen_code_ptr) >= (MAX_FRAG_SIZE - MAX_OP_SIZE)) {\n"
  36.428 -"            gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, arm_ldr_ptr, arm_data_table, arm_data_ptr, 1);\n"
  36.429 -"            last_gen_code_ptr = gen_code_ptr;\n"
  36.430 -"            arm_ldr_ptr = arm_ldr_table;\n"
  36.431 -"            arm_data_ptr = arm_data_table;\n"
  36.432 -"        }\n");         
  36.433 -#endif
  36.434 -
  36.435  
  36.436  fprintf(outfile,
  36.437  "    }\n"
  36.438 @@ -2553,7 +2715,10 @@ fprintf(outfile,
  36.439  
  36.440  /* generate some code patching */ 
  36.441  #ifdef HOST_ARM
  36.442 -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");
  36.443 +fprintf(outfile,
  36.444 +"if (arm_data_ptr != arm_data_table + ARM_LDR_TABLE_SIZE)\n"
  36.445 +"    gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, "
  36.446 +"arm_ldr_ptr, arm_data_ptr, arm_data_table + ARM_LDR_TABLE_SIZE, 0);\n");
  36.447  #endif
  36.448      /* flush instruction cache */
  36.449      fprintf(outfile, "flush_icache_range((unsigned long)gen_code_buf, (unsigned long)gen_code_ptr);\n");
    37.1 --- a/tools/ioemu/dyngen.h	Tue May 08 10:38:06 2007 +0100
    37.2 +++ b/tools/ioemu/dyngen.h	Wed May 09 14:17:15 2007 +0100
    37.3 @@ -19,7 +19,7 @@
    37.4   */
    37.5  
    37.6  int __op_param1, __op_param2, __op_param3;
    37.7 -#ifdef __sparc__
    37.8 +#if defined(__sparc__) || defined(__arm__)
    37.9    void __op_gen_label1(){}
   37.10    void __op_gen_label2(){}
   37.11    void __op_gen_label3(){}
   37.12 @@ -145,18 +145,16 @@ void fix_bsr(void *p, int offset) {
   37.13  
   37.14  #ifdef __arm__
   37.15  
   37.16 -#define MAX_OP_SIZE    (128 * 4) /* in bytes */
   37.17 -/* max size of the code that can be generated without calling arm_flush_ldr */
   37.18 -#define MAX_FRAG_SIZE  (1024 * 4) 
   37.19 -//#define MAX_FRAG_SIZE  (135 * 4) /* for testing */ 
   37.20 +#define ARM_LDR_TABLE_SIZE 1024
   37.21  
   37.22  typedef struct LDREntry {
   37.23      uint8_t *ptr;
   37.24      uint32_t *data_ptr;
   37.25 +    unsigned type:2;
   37.26  } LDREntry;
   37.27  
   37.28  static LDREntry arm_ldr_table[1024];
   37.29 -static uint32_t arm_data_table[1024];
   37.30 +static uint32_t arm_data_table[ARM_LDR_TABLE_SIZE];
   37.31  
   37.32  extern char exec_loop;
   37.33  
   37.34 @@ -175,8 +173,9 @@ static uint8_t *arm_flush_ldr(uint8_t *g
   37.35      int offset, data_size, target;
   37.36      uint8_t *data_ptr;
   37.37      uint32_t insn;
   37.38 +    uint32_t mask;
   37.39   
   37.40 -    data_size = (uint8_t *)data_end - (uint8_t *)data_start;
   37.41 +    data_size = (data_end - data_start) << 2;
   37.42  
   37.43      if (gen_jmp) {
   37.44          /* generate branch to skip the data */
   37.45 @@ -198,17 +197,48 @@ static uint8_t *arm_flush_ldr(uint8_t *g
   37.46          offset = ((unsigned long)(le->data_ptr) - (unsigned long)data_start) + 
   37.47              (unsigned long)data_ptr - 
   37.48              (unsigned long)ptr - 8;
   37.49 -        insn = *ptr & ~(0xfff | 0x00800000);
   37.50          if (offset < 0) {
   37.51 -            offset = - offset;
   37.52 -        } else {
   37.53 -            insn |= 0x00800000;
   37.54 -        }
   37.55 -        if (offset > 0xfff) {
   37.56 -            fprintf(stderr, "Error ldr offset\n");
   37.57 +            fprintf(stderr, "Negative constant pool offset\n");
   37.58              abort();
   37.59          }
   37.60 -        insn |= offset;
   37.61 +        switch (le->type) {
   37.62 +          case 0: /* ldr */
   37.63 +            mask = ~0x00800fff;
   37.64 +            if (offset >= 4096) {
   37.65 +                fprintf(stderr, "Bad ldr offset\n");
   37.66 +                abort();
   37.67 +            }
   37.68 +            break;
   37.69 +          case 1: /* ldc */
   37.70 +            mask = ~0x008000ff;
   37.71 +            if (offset >= 1024 ) {
   37.72 +                fprintf(stderr, "Bad ldc offset\n");
   37.73 +                abort();
   37.74 +            }
   37.75 +            break;
   37.76 +          case 2: /* add */
   37.77 +            mask = ~0xfff;
   37.78 +            if (offset >= 1024 ) {
   37.79 +                fprintf(stderr, "Bad add offset\n");
   37.80 +                abort();
   37.81 +            }
   37.82 +            break;
   37.83 +          default:
   37.84 +            fprintf(stderr, "Bad pc relative fixup\n");
   37.85 +            abort();
   37.86 +          }
   37.87 +        insn = *ptr & mask;
   37.88 +        switch (le->type) {
   37.89 +          case 0: /* ldr */
   37.90 +            insn |= offset | 0x00800000;
   37.91 +            break;
   37.92 +          case 1: /* ldc */
   37.93 +            insn |= (offset >> 2) | 0x00800000;
   37.94 +            break;
   37.95 +          case 2: /* add */
   37.96 +            insn |= (offset >> 2) | 0xf00;
   37.97 +            break;
   37.98 +          }
   37.99          *ptr = insn;
  37.100      }
  37.101      return gen_code_ptr;
    38.1 --- a/tools/ioemu/elf.h	Tue May 08 10:38:06 2007 +0100
    38.2 +++ b/tools/ioemu/elf.h	Wed May 09 14:17:15 2007 +0100
    38.3 @@ -502,6 +502,8 @@ typedef struct {
    38.4  #define R_ARM_GOTPC		25	/* 32 bit PC relative offset to GOT */
    38.5  #define R_ARM_GOT32		26	/* 32 bit GOT entry */
    38.6  #define R_ARM_PLT32		27	/* 32 bit PLT address */
    38.7 +#define R_ARM_CALL              28
    38.8 +#define R_ARM_JUMP24            29
    38.9  #define R_ARM_GNU_VTENTRY	100
   38.10  #define R_ARM_GNU_VTINHERIT	101
   38.11  #define R_ARM_THM_PC11		102	/* thumb unconditional branch */
    39.1 --- a/tools/ioemu/elf_ops.h	Tue May 08 10:38:06 2007 +0100
    39.2 +++ b/tools/ioemu/elf_ops.h	Wed May 09 14:17:15 2007 +0100
    39.3 @@ -153,6 +153,9 @@ int glue(load_elf, SZ)(int fd, int64_t v
    39.4          glue(bswap_ehdr, SZ)(&ehdr);
    39.5      }
    39.6  
    39.7 +    if (ELF_MACHINE != ehdr.e_machine)
    39.8 +        goto fail;
    39.9 +
   39.10      if (pentry)
   39.11     	*pentry = (uint64_t)ehdr.e_entry;
   39.12  
   39.13 @@ -202,4 +205,3 @@ int glue(load_elf, SZ)(int fd, int64_t v
   39.14      qemu_free(phdr);
   39.15      return -1;
   39.16  }
   39.17 -
    40.1 --- a/tools/ioemu/exec-all.h	Tue May 08 10:38:06 2007 +0100
    40.2 +++ b/tools/ioemu/exec-all.h	Wed May 09 14:17:15 2007 +0100
    40.3 @@ -196,9 +196,19 @@ typedef struct TranslationBlock {
    40.4      struct TranslationBlock *jmp_first;
    40.5  } TranslationBlock;
    40.6  
    40.7 +static inline unsigned int tb_jmp_cache_hash_page(target_ulong pc)
    40.8 +{
    40.9 +    target_ulong tmp;
   40.10 +    tmp = pc ^ (pc >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS));
   40.11 +    return (tmp >> TB_JMP_PAGE_BITS) & TB_JMP_PAGE_MASK;
   40.12 +}
   40.13 +
   40.14  static inline unsigned int tb_jmp_cache_hash_func(target_ulong pc)
   40.15  {
   40.16 -    return (pc ^ (pc >> TB_JMP_CACHE_BITS)) & (TB_JMP_CACHE_SIZE - 1);
   40.17 +    target_ulong tmp;
   40.18 +    tmp = pc ^ (pc >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS));
   40.19 +    return (((tmp >> TB_JMP_PAGE_BITS) & TB_JMP_PAGE_MASK) |
   40.20 +	    (tmp & TB_JMP_ADDR_MASK));
   40.21  }
   40.22  
   40.23  static inline unsigned int tb_phys_hash_func(unsigned long pc)
    41.1 --- a/tools/ioemu/exec.c	Tue May 08 10:38:06 2007 +0100
    41.2 +++ b/tools/ioemu/exec.c	Wed May 09 14:17:15 2007 +0100
    41.3 @@ -41,6 +41,7 @@
    41.4  //#define DEBUG_TB_INVALIDATE
    41.5  //#define DEBUG_FLUSH
    41.6  //#define DEBUG_TLB
    41.7 +//#define DEBUG_UNASSIGNED
    41.8  
    41.9  /* make various TB consistency checks */
   41.10  //#define DEBUG_TB_CHECK 
   41.11 @@ -1288,14 +1289,13 @@ void tlb_flush_page(CPUState *env, targe
   41.12      tlb_flush_entry(&env->tlb_table[0][i], addr);
   41.13      tlb_flush_entry(&env->tlb_table[1][i], addr);
   41.14  
   41.15 -    for(i = 0; i < TB_JMP_CACHE_SIZE; i++) {
   41.16 -        tb = env->tb_jmp_cache[i];
   41.17 -        if (tb && 
   41.18 -            ((tb->pc & TARGET_PAGE_MASK) == addr ||
   41.19 -             ((tb->pc + tb->size - 1) & TARGET_PAGE_MASK) == addr)) {
   41.20 -            env->tb_jmp_cache[i] = NULL;
   41.21 -        }
   41.22 -    }
   41.23 +    /* Discard jump cache entries for any tb which might potentially
   41.24 +       overlap the flushed page.  */
   41.25 +    i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE);
   41.26 +    memset (&env->tb_jmp_cache[i], 0, TB_JMP_PAGE_SIZE * sizeof(tb));
   41.27 +
   41.28 +    i = tb_jmp_cache_hash_page(addr);
   41.29 +    memset (&env->tb_jmp_cache[i], 0, TB_JMP_PAGE_SIZE * sizeof(tb));
   41.30  
   41.31  #if !defined(CONFIG_SOFTMMU)
   41.32      if (addr < MMAP_AREA_END)
   41.33 @@ -1801,13 +1801,30 @@ void cpu_register_physical_memory(target
   41.34      }
   41.35  }
   41.36  
   41.37 +/* XXX: temporary until new memory mapping API */
   41.38 +uint32_t cpu_get_physical_page_desc(target_phys_addr_t addr)
   41.39 +{
   41.40 +    PhysPageDesc *p;
   41.41 +
   41.42 +    p = phys_page_find(addr >> TARGET_PAGE_BITS);
   41.43 +    if (!p)
   41.44 +        return IO_MEM_UNASSIGNED;
   41.45 +    return p->phys_offset;
   41.46 +}
   41.47 +
   41.48  static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
   41.49  {
   41.50 +#ifdef DEBUG_UNASSIGNED
   41.51 +    printf("Unassigned mem read  0x%08x\n", (int)addr);
   41.52 +#endif
   41.53      return 0;
   41.54  }
   41.55  
   41.56  static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
   41.57  {
   41.58 +#ifdef DEBUG_UNASSIGNED
   41.59 +    printf("Unassigned mem write 0x%08x = 0x%x\n", (int)addr, val);
   41.60 +#endif
   41.61  }
   41.62  
   41.63  static CPUReadMemoryFunc *unassigned_mem_read[3] = {
    42.1 --- a/tools/ioemu/fpu/.CVS/Entries	Tue May 08 10:38:06 2007 +0100
    42.2 +++ b/tools/ioemu/fpu/.CVS/Entries	Wed May 09 14:17:15 2007 +0100
    42.3 @@ -1,7 +1,7 @@
    42.4 -/softfloat-macros.h/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
    42.5 -/softfloat-native.c/1.4/Sun Aug  6 01:03:50 2006//Trelease_0_8_2
    42.6 -/softfloat-native.h/1.6/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
    42.7 -/softfloat-specialize.h/1.1/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
    42.8 -/softfloat.c/1.2/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
    42.9 -/softfloat.h/1.3/Fri Jul 14 12:43:45 2006//Trelease_0_8_2
   42.10 +/softfloat-macros.h/1.1/Wed Oct 18 10:11:20 2006//Trelease_0_9_0
   42.11 +/softfloat-native.c/1.6/Thu May  3 17:18:00 2007//Trelease_0_9_0
   42.12 +/softfloat-native.h/1.8/Thu May  3 17:18:00 2007//Trelease_0_9_0
   42.13 +/softfloat-specialize.h/1.2/Thu May  3 17:18:00 2007//Trelease_0_9_0
   42.14 +/softfloat.c/1.4/Thu May  3 17:18:00 2007//Trelease_0_9_0
   42.15 +/softfloat.h/1.5/Thu May  3 17:18:00 2007//Trelease_0_9_0
   42.16  D
    43.1 --- a/tools/ioemu/fpu/.CVS/Tag	Tue May 08 10:38:06 2007 +0100
    43.2 +++ b/tools/ioemu/fpu/.CVS/Tag	Wed May 09 14:17:15 2007 +0100
    43.3 @@ -1,1 +1,1 @@
    43.4 -Nrelease_0_8_2
    43.5 +Nrelease_0_9_0
    44.1 --- a/tools/ioemu/fpu/softfloat-native.c	Tue May 08 10:38:06 2007 +0100
    44.2 +++ b/tools/ioemu/fpu/softfloat-native.c	Wed May 09 14:17:15 2007 +0100
    44.3 @@ -149,7 +149,7 @@ float32 float32_sqrt( float32 a STATUS_P
    44.4  {
    44.5      return sqrtf(a);
    44.6  }
    44.7 -char float32_compare( float32 a, float32 b STATUS_PARAM )
    44.8 +int float32_compare( float32 a, float32 b STATUS_PARAM )
    44.9  {
   44.10      if (a < b) {
   44.11          return -1;
   44.12 @@ -161,7 +161,7 @@ char float32_compare( float32 a, float32
   44.13          return 2;
   44.14      }
   44.15  }
   44.16 -char float32_compare_quiet( float32 a, float32 b STATUS_PARAM )
   44.17 +int float32_compare_quiet( float32 a, float32 b STATUS_PARAM )
   44.18  {
   44.19      if (isless(a, b)) {
   44.20          return -1;
   44.21 @@ -173,7 +173,7 @@ char float32_compare_quiet( float32 a, f
   44.22          return 2;
   44.23      }
   44.24  }
   44.25 -char float32_is_signaling_nan( float32 a1)
   44.26 +int float32_is_signaling_nan( float32 a1)
   44.27  {
   44.28      float32u u;
   44.29      uint32_t a;
   44.30 @@ -221,6 +221,11 @@ float128 float64_to_float128( float64 a 
   44.31  /*----------------------------------------------------------------------------
   44.32  | Software IEC/IEEE double-precision operations.
   44.33  *----------------------------------------------------------------------------*/
   44.34 +float64 float64_trunc_to_int( float64 a STATUS_PARAM )
   44.35 +{
   44.36 +    return trunc(a);
   44.37